@sleds/cli 0.1.25 → 0.1.26

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 +1517 -739
  2. package/package.json +1 -1
package/dist/sleds.mjs CHANGED
@@ -1,16 +1,22 @@
1
1
  #!/usr/bin/env node
2
2
  // @bun
3
- var __esm = (fn, res, err) => () => {
4
- if (fn)
5
- try {
6
- res = fn(fn = 0);
7
- } catch (e) {
8
- err = [e];
9
- }
10
- if (err)
11
- throw err[0];
12
- return res;
3
+ import { createRequire } from "node:module";
4
+ var __defProp = Object.defineProperty;
5
+ var __returnValue = (v) => v;
6
+ function __exportSetter(name, newValue) {
7
+ this[name] = __returnValue.bind(null, newValue);
8
+ }
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, {
12
+ get: all[name],
13
+ enumerable: true,
14
+ configurable: true,
15
+ set: __exportSetter.bind(all, name)
16
+ });
13
17
  };
18
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
19
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
14
20
 
15
21
  // ../../packages/shared/src/mcp/format.ts
16
22
  var isObject = (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) => {
@@ -152,8 +158,8 @@ var init_format = __esm(() => {
152
158
  import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
153
159
  import { dirname, join, resolve } from "node:path";
154
160
  var BASE_URL_KEY = "ANTHROPIC_BASE_URL", AUTH_TOKEN_KEY = "ANTHROPIC_AUTH_TOKEN", claudeDir = (home, env = process.env) => {
155
- const o = env.CLAUDE_CONFIG_DIR?.trim();
156
- return o ? resolve(home, o) : join(home, ".claude");
161
+ const o2 = env.CLAUDE_CONFIG_DIR?.trim();
162
+ return o2 ? resolve(home, o2) : join(home, ".claude");
157
163
  }, 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) => {
158
164
  const parts = [];
159
165
  const sh = env.SLEDS_HOME?.trim();
@@ -183,8 +189,8 @@ var BASE_URL_KEY = "ANTHROPIC_BASE_URL", AUTH_TOKEN_KEY = "ANTHROPIC_AUTH_TOKEN"
183
189
  visit(settings.hooks);
184
190
  return out;
185
191
  }, bakedHome = (command) => command.match(/(?:^|\s)SLEDS_HOME=('([^']*)'|(\S+))/)?.[2] ?? command.match(/(?:^|\s)SLEDS_HOME=(\S+)/)?.[1], shellWord = (v) => /^[\w./~-]+$/.test(v) ? v : `'${v.replace(/'/g, "'\\''")}'`, backupPath = (home) => join(claudeDir(home), "settings.json.sleds-backup"), tokenPath = (home, env = process.env) => {
186
- const o = env.SLEDS_HOME?.trim();
187
- return o ? join(resolve(home, o), ".sleds-token") : join(home, ".sleds-token");
192
+ const o2 = env.SLEDS_HOME?.trim();
193
+ return o2 ? join(resolve(home, o2), ".sleds-token") : join(home, ".sleds-token");
188
194
  }, skillDir = (home) => join(claudeDir(home), "skills", "sled"), skillPath = (home) => join(skillDir(home), "SKILL.md"), isObject5 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), envOf = (settings) => {
189
195
  const env = settings.env;
190
196
  return isObject5(env) ? env : {};
@@ -320,12 +326,12 @@ var BASE_URL_KEY = "ANTHROPIC_BASE_URL", AUTH_TOKEN_KEY = "ANTHROPIC_AUTH_TOKEN"
320
326
  return withEventHooks(settings, event, list.filter((e) => !ours(e)));
321
327
  }, applySessionHook = (settings, command) => applyOnce(settings, SESSION_EVENT, isSledsSessionHook, sessionHookEntry(command)), removeSessionHook = (settings) => removeOurs(settings, SESSION_EVENT, isSledsSessionHook), hasSessionHook = (settings) => eventHooks(settings, SESSION_EVENT).some(isSledsSessionHook), applyStopHook = (settings, command) => applyOnce(settings, STOP_EVENT, isSledsStopHook, stopHookEntry(command)), removeStopHook = (settings) => removeOurs(settings, STOP_EVENT, isSledsStopHook), hasStopHook = (settings) => eventHooks(settings, STOP_EVENT).some(isSledsStopHook), isSeatToken = (token) => /^sled_[A-Za-z0-9_-]+$/.test(token), maskToken = (token) => token.length <= 9 ? `${token.slice(0, 5)}…` : `${token.slice(0, 9)}…`, serialize = (settings) => `${JSON.stringify(settings, null, 2)}
322
328
  `, hasClaudeCode = (home) => existsSync(claudeDir(home)), readSettings = (home) => {
323
- const p = settingsPath(home);
324
- if (!existsSync(p))
329
+ const p2 = settingsPath(home);
330
+ if (!existsSync(p2))
325
331
  return {};
326
- const parsed = JSON.parse(readFileSync(p, "utf8"));
332
+ const parsed = JSON.parse(readFileSync(p2, "utf8"));
327
333
  if (!isObject5(parsed))
328
- throw new Error(`${p} is not a JSON object`);
334
+ throw new Error(`${p2} is not a JSON object`);
329
335
  return parsed;
330
336
  }, writeSettings = (home, settings) => {
331
337
  mkdirSync(claudeDir(home), { recursive: true });
@@ -341,10 +347,10 @@ var BASE_URL_KEY = "ANTHROPIC_BASE_URL", AUTH_TOKEN_KEY = "ANTHROPIC_AUTH_TOKEN"
341
347
  writeFileSync(dst, readFileSync(src));
342
348
  return true;
343
349
  }, readTokenFile = (home) => {
344
- const p = tokenPath(home);
345
- if (!existsSync(p))
350
+ const p2 = tokenPath(home);
351
+ if (!existsSync(p2))
346
352
  return null;
347
- const t = readFileSync(p, "utf8").trim();
353
+ const t = readFileSync(p2, "utf8").trim();
348
354
  return t.length > 0 ? t : null;
349
355
  }, writeTokenFile = (home, token) => {
350
356
  mkdirSync(dirname(tokenPath(home)), { recursive: true, mode: 448 });
@@ -360,8 +366,8 @@ var init_settings = __esm(() => {
360
366
  import { chmodSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
361
367
  import { join as join2, resolve as resolve2 } from "node:path";
362
368
  var configDir = (home, env = process.env) => {
363
- const o = env.SLEDS_HOME?.trim();
364
- return o ? resolve2(home, o) : join2(home, ".config", "sleds");
369
+ const o2 = env.SLEDS_HOME?.trim();
370
+ return o2 ? resolve2(home, o2) : join2(home, ".config", "sleds");
365
371
  }, configPath = (home) => join2(configDir(home), "config.json"), isObject6 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), optString = (v) => typeof v === "string" ? v : undefined, parsePriorEnv = (v) => {
366
372
  if (!isObject6(v))
367
373
  return;
@@ -438,15 +444,15 @@ var configDir = (home, env = process.env) => {
438
444
  return;
439
445
  const name = optString(raw.name);
440
446
  const slug = optString(raw.slug);
441
- const plan = raw.plan;
447
+ const plan2 = raw.plan;
442
448
  const c = raw.capabilities;
443
449
  const src = c.upstreamSource;
444
- if (name === undefined || slug === undefined || plan !== "team" && plan !== "enterprise" && plan !== "api" && plan !== "individual" || src !== "own" && src !== "shared" && src !== "none")
450
+ if (name === undefined || slug === undefined || plan2 !== "team" && plan2 !== "enterprise" && plan2 !== "api" && plan2 !== "individual" || src !== "own" && src !== "shared" && src !== "none")
445
451
  return;
446
452
  return {
447
453
  name,
448
454
  slug,
449
- plan,
455
+ plan: plan2,
450
456
  capabilities: {
451
457
  upstreamKey: c.upstreamKey === true,
452
458
  adminKey: c.adminKey === true,
@@ -456,10 +462,10 @@ var configDir = (home, env = process.env) => {
456
462
  mode: raw.mode === "proxy-always" ? "proxy-always" : "seat-first"
457
463
  };
458
464
  }, readConfig = (home) => {
459
- const p = configPath(home);
460
- if (!existsSync2(p))
465
+ const p2 = configPath(home);
466
+ if (!existsSync2(p2))
461
467
  return {};
462
- return parseConfig(JSON.parse(readFileSync2(p, "utf8")));
468
+ return parseConfig(JSON.parse(readFileSync2(p2, "utf8")));
463
469
  }, writeConfig = (home, cfg) => {
464
470
  const dir = configDir(home);
465
471
  mkdirSync2(dir, { recursive: true, mode: 448 });
@@ -478,11 +484,11 @@ var init_config = __esm(() => {
478
484
  import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync4, renameSync as renameSync3, writeFileSync as writeFileSync4 } from "node:fs";
479
485
  import { join as join4 } from "node:path";
480
486
  var METER_CACHE_TTL_MS = 1e4, METER_TIMEOUT_MS = 1500, isObject7 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), num4 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined, meterCachePath = (home) => join4(configDir(home), "meter.json"), readMeterCache = (home, now) => {
481
- const p = meterCachePath(home);
482
- if (!existsSync4(p))
487
+ const p2 = meterCachePath(home);
488
+ if (!existsSync4(p2))
483
489
  return null;
484
490
  try {
485
- const raw = JSON.parse(readFileSync4(p, "utf8"));
491
+ const raw = JSON.parse(readFileSync4(p2, "utf8"));
486
492
  if (!isObject7(raw))
487
493
  return null;
488
494
  const fetchedAt = num4(raw.fetchedAt);
@@ -501,12 +507,12 @@ var METER_CACHE_TTL_MS = 1e4, METER_TIMEOUT_MS = 1500, isObject7 = (v) => typeof
501
507
  writeFileSync4(tmp, `${JSON.stringify(file)}
502
508
  `, { mode: 384 });
503
509
  renameSync3(tmp, target);
504
- }, fetchMeter = async (o) => {
505
- const fetchFn = o.fetchFn ?? fetch;
510
+ }, fetchMeter = async (o2) => {
511
+ const fetchFn = o2.fetchFn ?? fetch;
506
512
  try {
507
- const res = await fetchFn(`${o.proxyUrl}/proxy/meter`, {
508
- headers: { authorization: `Bearer ${o.token}` },
509
- signal: AbortSignal.timeout(o.timeoutMs ?? METER_TIMEOUT_MS)
513
+ const res = await fetchFn(`${o2.proxyUrl}/proxy/meter`, {
514
+ headers: { authorization: `Bearer ${o2.token}` },
515
+ signal: AbortSignal.timeout(o2.timeoutMs ?? METER_TIMEOUT_MS)
510
516
  });
511
517
  if (!res.ok)
512
518
  return null;
@@ -521,18 +527,18 @@ var METER_CACHE_TTL_MS = 1e4, METER_TIMEOUT_MS = 1500, isObject7 = (v) => typeof
521
527
  const proxyUrl = inSettings?.url ?? cfg.proxyUrl;
522
528
  const token = inSettings?.token ?? cfg.token;
523
529
  return proxyUrl && token ? { proxyUrl, token } : null;
524
- }, loadMeter = async (o) => {
525
- const now = o.now ?? Date.now();
526
- const cached = readMeterCache(o.home, now);
530
+ }, loadMeter = async (o2) => {
531
+ const now = o2.now ?? Date.now();
532
+ const cached = readMeterCache(o2.home, now);
527
533
  if (cached)
528
534
  return cached;
529
- const src = meterSource(o.home);
535
+ const src = meterSource(o2.home);
530
536
  if (!src)
531
537
  return null;
532
- const fresh = await fetchMeter({ ...src, fetchFn: o.fetchFn, timeoutMs: o.timeoutMs });
538
+ const fresh = await fetchMeter({ ...src, fetchFn: o2.fetchFn, timeoutMs: o2.timeoutMs });
533
539
  if (fresh) {
534
540
  try {
535
- writeMeterCache(o.home, fresh, now);
541
+ writeMeterCache(o2.home, fresh, now);
536
542
  } catch {}
537
543
  }
538
544
  return fresh;
@@ -545,9 +551,432 @@ var init_meter = __esm(() => {
545
551
  });
546
552
 
547
553
  // src/seat.ts
548
- var SEAT_POST_MIN_INTERVAL_MS2, readStdin2 = (timeoutMs, stdin = process.stdin) => new Promise((resolve) => {
554
+ var exports_seat = {};
555
+ __export(exports_seat, {
556
+ APPROACHING_PCT: () => APPROACHING_PCT2,
557
+ CREDITS_PATTERN: () => CREDITS_PATTERN2,
558
+ SEAT_POST_MIN_DELTA_PCT: () => SEAT_POST_MIN_DELTA_PCT2,
559
+ SEAT_POST_MIN_INTERVAL_MS: () => SEAT_POST_MIN_INTERVAL_MS2,
560
+ SEAT_POST_TIMEOUT_MS: () => SEAT_POST_TIMEOUT_MS2,
561
+ SEAT_WALL_LINE: () => SEAT_WALL_LINE2,
562
+ SEAT_WALL_LINE_NO_KEY: () => SEAT_WALL_LINE_NO_KEY2,
563
+ STDIN_TIMEOUT_MS: () => STDIN_TIMEOUT_MS2,
564
+ bindingResetAt: () => bindingResetAt2,
565
+ creditsHitIn: () => creditsHitIn2,
566
+ formatSeatFragment: () => formatSeatFragment2,
567
+ markPosted: () => markPosted2,
568
+ markWarned: () => markWarned2,
569
+ parseResetsAt: () => parseResetsAt2,
570
+ parseSeatState: () => parseSeatState2,
571
+ parseSeatWindow: () => parseSeatWindow2,
572
+ postSeatWall: () => postSeatWall2,
573
+ postSeatWindow: () => postSeatWindow2,
574
+ readSeatState: () => readSeatState2,
575
+ readStdin: () => readStdin2,
576
+ scanTranscriptForCredits: () => scanTranscriptForCredits2,
577
+ seatSessionFromStdin: () => seatSessionFromStdin2,
578
+ seatStatePath: () => seatStatePath2,
579
+ seatWallDue: () => seatWallDue,
580
+ seatWallEvents: () => seatWallEvents2,
581
+ seatWallLine: () => seatWallLine2,
582
+ seatWindowBody: () => seatWindowBody2,
583
+ seatWindowFromStdin: () => seatWindowFromStdin2,
584
+ shouldPostSeat: () => shouldPostSeat2,
585
+ transcriptPathFromStdin: () => transcriptPathFromStdin2,
586
+ writeSeatState: () => writeSeatState2
587
+ });
588
+ import {
589
+ closeSync as closeSync2,
590
+ existsSync as existsSync18,
591
+ mkdirSync as mkdirSync14,
592
+ openSync as openSync2,
593
+ readFileSync as readFileSync15,
594
+ readSync as readSync2,
595
+ renameSync as renameSync7,
596
+ statSync as statSync3,
597
+ writeFileSync as writeFileSync14
598
+ } from "node:fs";
599
+ import { join as join15 } from "node:path";
600
+ var SEAT_POST_MIN_DELTA_PCT2 = 1, SEAT_POST_MIN_INTERVAL_MS2, SEAT_POST_TIMEOUT_MS2 = 1500, STDIN_TIMEOUT_MS2 = 300, isObject15 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), num7 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined, EPOCH_MS_THRESHOLD2 = 100000000000, parseResetsAt2 = (v) => {
601
+ const n2 = num7(v);
602
+ if (n2 !== undefined) {
603
+ if (n2 <= 0)
604
+ return;
605
+ return n2 >= EPOCH_MS_THRESHOLD2 ? Math.round(n2) : Math.round(n2 * 1000);
606
+ }
607
+ if (typeof v === "string" && v.trim() !== "") {
608
+ const parsed = Date.parse(v);
609
+ return Number.isFinite(parsed) ? parsed : undefined;
610
+ }
611
+ return;
612
+ }, parseBar2 = (v) => {
613
+ if (!isObject15(v))
614
+ return;
615
+ const usedPct = num7(v.used_percentage) ?? num7(v.usedPct);
616
+ const resetsAt = parseResetsAt2(v.resets_at ?? v.resetsAt);
617
+ if (usedPct === undefined || usedPct < 0 || resetsAt === undefined)
618
+ return;
619
+ return { usedPct, resetsAt };
620
+ }, parseSeatWindow2 = (raw, capturedAt) => {
621
+ if (!isObject15(raw))
622
+ return null;
623
+ const limits = isObject15(raw.rate_limits) ? raw.rate_limits : raw;
624
+ const fiveHour = parseBar2(limits.five_hour ?? limits.fiveHour);
625
+ const sevenDay = parseBar2(limits.seven_day ?? limits.sevenDay);
626
+ const spendLimit = parseBar2(limits.spend_limit ?? limits.spendLimit);
627
+ const models = {};
628
+ if (isObject15(limits.models))
629
+ for (const [k, v] of Object.entries(limits.models)) {
630
+ const bar = parseBar2(v);
631
+ if (bar)
632
+ models[k] = bar;
633
+ }
634
+ const usedCreditsUsd = num7(limits.usedCreditsUsd);
635
+ const hasModels = Object.keys(models).length > 0;
636
+ if (!fiveHour && !sevenDay && !spendLimit && !hasModels && usedCreditsUsd === undefined)
637
+ return null;
638
+ const out = { capturedAt };
639
+ if (fiveHour)
640
+ out.fiveHour = fiveHour;
641
+ if (sevenDay)
642
+ out.sevenDay = sevenDay;
643
+ if (spendLimit)
644
+ out.spendLimit = spendLimit;
645
+ if (hasModels)
646
+ out.models = models;
647
+ if (usedCreditsUsd !== undefined)
648
+ out.usedCreditsUsd = usedCreditsUsd;
649
+ return out;
650
+ }, seatWindowFromStdin2 = (text, capturedAt) => {
651
+ const trimmed = text.trim();
652
+ if (!trimmed)
653
+ return null;
654
+ try {
655
+ return parseSeatWindow2(JSON.parse(trimmed), capturedAt);
656
+ } catch {
657
+ return null;
658
+ }
659
+ }, formatSeatFragment2 = (w, now = Date.now()) => {
660
+ if (!w)
661
+ return null;
662
+ const parts = [];
663
+ if (w.sevenDay)
664
+ parts.push(`wk ${Math.round(w.sevenDay.usedPct)}%`);
665
+ if (w.fiveHour)
666
+ parts.push(`5h ${Math.round(w.fiveHour.usedPct)}%`);
667
+ if (w.spendLimit)
668
+ parts.push(`spend ${Math.round(w.spendLimit.usedPct)}%`);
669
+ if (parts.length === 0)
670
+ return null;
671
+ const hot = [
672
+ ["wk", w.sevenDay],
673
+ ["5h", w.fiveHour],
674
+ ["spend", w.spendLimit]
675
+ ].filter((x) => x[1] !== undefined && x[1].usedPct >= APPROACHING_PCT2).sort((a, b) => b[1].usedPct - a[1].usedPct)[0];
676
+ if (hot) {
677
+ const mins = Math.max(0, Math.round((hot[1].resetsAt - now) / 60000));
678
+ const reset = mins >= 60 ? `${Math.floor(mins / 60)}h${mins % 60 ? `${mins % 60}m` : ""}` : `${mins}m`;
679
+ const verb = hot[1].usedPct >= 100 ? "at the wall" : `${Math.round(hot[1].usedPct)}%`;
680
+ return `⚠ seat ${hot[0]} ${verb}${SEP}resets ${reset}${SEP}/sled handoff · sleds defer`;
681
+ }
682
+ return `seat ${parts.join(SEP)}`;
683
+ }, APPROACHING_PCT2 = 90, seatStatePath2 = (home) => join15(configDir(home), "seat.json"), parseWindowStored2 = (v) => {
684
+ if (!isObject15(v))
685
+ return;
686
+ const capturedAt = num7(v.capturedAt);
687
+ if (capturedAt === undefined)
688
+ return;
689
+ return parseSeatWindow2(v, capturedAt) ?? undefined;
690
+ }, parseSeatState2 = (raw) => {
691
+ if (!isObject15(raw))
692
+ return {};
693
+ const out = {};
694
+ const window = parseWindowStored2(raw.window);
695
+ if (window)
696
+ out.window = window;
697
+ const lastPostedAt = num7(raw.lastPostedAt);
698
+ if (lastPostedAt !== undefined)
699
+ out.lastPostedAt = lastPostedAt;
700
+ if (isObject15(raw.lastPosted)) {
701
+ const lp = {};
702
+ const f = num7(raw.lastPosted.fiveHour);
703
+ const s = num7(raw.lastPosted.sevenDay);
704
+ const sp = num7(raw.lastPosted.spendLimit);
705
+ if (f !== undefined)
706
+ lp.fiveHour = f;
707
+ if (s !== undefined)
708
+ lp.sevenDay = s;
709
+ if (sp !== undefined)
710
+ lp.spendLimit = sp;
711
+ out.lastPosted = lp;
712
+ }
713
+ const lastWallResetsAt = num7(raw.lastWallResetsAt);
714
+ if (lastWallResetsAt !== undefined)
715
+ out.lastWallResetsAt = lastWallResetsAt;
716
+ if (isObject15(raw.warned)) {
717
+ const warned = {};
718
+ for (const bar of ["fiveHour", "sevenDay", "spendLimit", "credits"]) {
719
+ const w = raw.warned[bar];
720
+ if (!isObject15(w))
721
+ continue;
722
+ const entry = {};
723
+ const ap = num7(w.approaching);
724
+ const hit = num7(w.hit);
725
+ if (ap !== undefined)
726
+ entry.approaching = ap;
727
+ if (hit !== undefined)
728
+ entry.hit = hit;
729
+ warned[bar] = entry;
730
+ }
731
+ out.warned = warned;
732
+ }
733
+ if (isObject15(raw.told)) {
734
+ const told = {};
735
+ for (const bar of ["fiveHour", "sevenDay", "spendLimit", "credits"]) {
736
+ const w = raw.told[bar];
737
+ if (!isObject15(w))
738
+ continue;
739
+ const entry = {};
740
+ const ap = num7(w.approaching);
741
+ const hit = num7(w.hit);
742
+ if (ap !== undefined)
743
+ entry.approaching = ap;
744
+ if (hit !== undefined)
745
+ entry.hit = hit;
746
+ told[bar] = entry;
747
+ }
748
+ out.told = told;
749
+ }
750
+ if (isObject15(raw.transcriptScan) && typeof raw.transcriptScan.path === "string") {
751
+ const offset = num7(raw.transcriptScan.offset);
752
+ const hitAt = num7(raw.transcriptScan.hitAt);
753
+ out.transcriptScan = {
754
+ path: raw.transcriptScan.path,
755
+ offset: offset ?? 0,
756
+ ...hitAt !== undefined ? { hitAt } : {}
757
+ };
758
+ }
759
+ const session = parseSeatSession2(raw.session);
760
+ if (session)
761
+ out.session = session;
762
+ if (isObject15(raw.cockpit) && raw.cockpit.kind === "cmux") {
763
+ const c = { kind: "cmux" };
764
+ if (isObject15(raw.cockpit.lines)) {
765
+ const lines = {};
766
+ for (const [k, v] of Object.entries(raw.cockpit.lines))
767
+ if (typeof v === "string")
768
+ lines[k] = v;
769
+ c.lines = lines;
770
+ }
771
+ if (raw.cockpit.progress === true)
772
+ c.progress = true;
773
+ const f = raw.cockpit.feed;
774
+ if (isObject15(f) && num7(f.at) !== undefined) {
775
+ const strs = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
776
+ const j = isObject15(f.jobs) ? f.jobs : {};
777
+ c.feed = {
778
+ at: num7(f.at),
779
+ handoffs: strs(f.handoffs),
780
+ jobs: {
781
+ scheduled: num7(j.scheduled) ?? 0,
782
+ running: num7(j.running) ?? 0,
783
+ delivered: num7(j.delivered) ?? 0,
784
+ failed: num7(j.failed) ?? 0
785
+ },
786
+ delivered: strs(f.delivered),
787
+ failed: strs(f.failed)
788
+ };
789
+ }
790
+ out.cockpit = c;
791
+ }
792
+ if (isObject15(raw.estimate)) {
793
+ const e = raw.estimate;
794
+ const project = typeof e.project === "string" ? e.project : undefined;
795
+ const [lo, hi, lm, hm, at] = [e.lowUsd, e.highUsd, e.lowMin, e.highMin, e.at].map(num7);
796
+ if (project && lo !== undefined && hi !== undefined && lm !== undefined && hm !== undefined && at !== undefined)
797
+ out.estimate = { project, lowUsd: lo, highUsd: hi, lowMin: lm, highMin: hm, at };
798
+ }
799
+ return out;
800
+ }, parseSeatSession2 = (v) => {
801
+ if (!isObject15(v) || typeof v.id !== "string" || !v.id)
802
+ return;
803
+ const at = num7(v.at);
804
+ if (at === undefined)
805
+ return;
806
+ const out = { id: v.id, at };
807
+ if (typeof v.cwd === "string" && v.cwd)
808
+ out.cwd = v.cwd;
809
+ if (typeof v.model === "string" && v.model)
810
+ out.model = v.model;
811
+ return out;
812
+ }, seatSessionFromStdin2 = (text, now) => {
813
+ const trimmed = text.trim();
814
+ if (!trimmed)
815
+ return null;
816
+ try {
817
+ const raw = JSON.parse(trimmed);
818
+ if (!isObject15(raw) || typeof raw.session_id !== "string" || !raw.session_id)
819
+ return null;
820
+ const out = { id: raw.session_id, at: now };
821
+ if (typeof raw.cwd === "string" && raw.cwd)
822
+ out.cwd = raw.cwd;
823
+ const model = isObject15(raw.model) ? raw.model.id : raw.model;
824
+ if (typeof model === "string" && model)
825
+ out.model = model;
826
+ return out;
827
+ } catch {
828
+ return null;
829
+ }
830
+ }, bindingResetAt2 = (w, now) => {
831
+ if (!w)
832
+ return;
833
+ const bars = [
834
+ ...w.fiveHour ? [w.fiveHour] : [],
835
+ ...w.sevenDay ? [w.sevenDay] : [],
836
+ ...w.spendLimit ? [w.spendLimit] : [],
837
+ ...Object.values(w.models ?? {})
838
+ ].filter((b) => b.resetsAt > now);
839
+ const full = bars.filter((b) => b.usedPct >= 100);
840
+ const pick = (full.length ? full : bars).map((b) => b.resetsAt);
841
+ return pick.length ? Math.min(...pick) : undefined;
842
+ }, readSeatState2 = (home) => {
843
+ const p2 = seatStatePath2(home);
844
+ if (!existsSync18(p2))
845
+ return {};
846
+ try {
847
+ return parseSeatState2(JSON.parse(readFileSync15(p2, "utf8")));
848
+ } catch {
849
+ return {};
850
+ }
851
+ }, writeSeatState2 = (home, state) => {
852
+ const dir = configDir(home);
853
+ mkdirSync14(dir, { recursive: true, mode: 448 });
854
+ const target = seatStatePath2(home);
855
+ const tmp = `${target}.${process.pid}.tmp`;
856
+ writeFileSync14(tmp, `${JSON.stringify(state)}
857
+ `, { mode: 384 });
858
+ renameSync7(tmp, target);
859
+ }, pctOf2 = (b) => b?.usedPct, shouldPostSeat2 = (state, next, now) => {
860
+ if (state.lastPostedAt === undefined || !state.lastPosted)
861
+ return true;
862
+ if (now - state.lastPostedAt >= SEAT_POST_MIN_INTERVAL_MS2)
863
+ return true;
864
+ const pairs = [
865
+ [state.lastPosted.fiveHour, pctOf2(next.fiveHour)],
866
+ [state.lastPosted.sevenDay, pctOf2(next.sevenDay)],
867
+ [state.lastPosted.spendLimit, pctOf2(next.spendLimit)]
868
+ ];
869
+ for (const [prev, cur] of pairs) {
870
+ if (prev === undefined && cur === undefined)
871
+ continue;
872
+ if (prev === undefined || cur === undefined)
873
+ return true;
874
+ if (Math.abs(cur - prev) >= SEAT_POST_MIN_DELTA_PCT2)
875
+ return true;
876
+ }
877
+ return false;
878
+ }, markPosted2 = (state, w, now) => {
879
+ const lastPosted = {};
880
+ if (w.fiveHour)
881
+ lastPosted.fiveHour = w.fiveHour.usedPct;
882
+ if (w.sevenDay)
883
+ lastPosted.sevenDay = w.sevenDay.usedPct;
884
+ if (w.spendLimit)
885
+ lastPosted.spendLimit = w.spendLimit.usedPct;
886
+ return { ...state, window: w, lastPostedAt: now, lastPosted };
887
+ }, seatWallDue = (state, w) => {
888
+ if (!w?.sevenDay || w.sevenDay.usedPct < 100)
889
+ return false;
890
+ return state.lastWallResetsAt === undefined || state.lastWallResetsAt < w.sevenDay.resetsAt;
891
+ }, seatWallEvents2 = (state, w) => {
892
+ if (!w)
893
+ return [];
894
+ const out = [];
895
+ const bars = [
896
+ ["fiveHour", w.fiveHour],
897
+ ["sevenDay", w.sevenDay],
898
+ ["spendLimit", w.spendLimit]
899
+ ];
900
+ for (const [bar, b] of bars) {
901
+ if (!b)
902
+ continue;
903
+ const seen = state.warned?.[bar] ?? {};
904
+ const weeklyOld = bar === "sevenDay" && state.lastWallResetsAt !== undefined && state.lastWallResetsAt >= b.resetsAt;
905
+ if (b.usedPct >= APPROACHING_PCT2 && (seen.approaching ?? -1) < b.resetsAt && !weeklyOld)
906
+ out.push({ bar, stage: "approaching", usedPct: b.usedPct, resetsAt: b.resetsAt });
907
+ if (b.usedPct >= 100 && (seen.hit ?? -1) < b.resetsAt && !weeklyOld)
908
+ out.push({ bar, stage: "hit", usedPct: b.usedPct, resetsAt: b.resetsAt });
909
+ }
910
+ return out;
911
+ }, markWarned2 = (state, events) => {
912
+ if (events.length === 0)
913
+ return state;
914
+ const warned = { ...state.warned ?? {} };
915
+ let lastWallResetsAt = state.lastWallResetsAt;
916
+ for (const e of events) {
917
+ warned[e.bar] = { ...warned[e.bar] ?? {}, [e.stage]: e.resetsAt };
918
+ if (e.bar === "sevenDay" && e.stage === "hit")
919
+ lastWallResetsAt = e.resetsAt;
920
+ }
921
+ return { ...state, warned, ...lastWallResetsAt !== undefined ? { lastWallResetsAt } : {} };
922
+ }, CREDITS_PATTERN2, creditsHitIn2 = (text) => CREDITS_PATTERN2.test(text), transcriptPathFromStdin2 = (text) => {
923
+ try {
924
+ const raw = JSON.parse(text.trim());
925
+ return isObject15(raw) && typeof raw.transcript_path === "string" && raw.transcript_path ? raw.transcript_path : null;
926
+ } catch {
927
+ return null;
928
+ }
929
+ }, scanTranscriptForCredits2 = (path, prior) => {
930
+ const from = prior && prior.path === path ? prior.offset : 0;
931
+ try {
932
+ const size = statSync3(path).size;
933
+ if (size <= from)
934
+ return {
935
+ hit: false,
936
+ next: { path, offset: size, ...prior?.hitAt ? { hitAt: prior.hitAt } : {} }
937
+ };
938
+ const start = Math.max(from, size - 256 * 1024);
939
+ const fd = openSync2(path, "r");
940
+ try {
941
+ const buf = Buffer.alloc(size - start);
942
+ readSync2(fd, buf, 0, buf.length, start);
943
+ const hit = creditsHitIn2(buf.toString("utf8"));
944
+ return {
945
+ hit,
946
+ next: {
947
+ path,
948
+ offset: size,
949
+ ...hit ? { hitAt: Date.now() } : prior?.hitAt ? { hitAt: prior.hitAt } : {}
950
+ }
951
+ };
952
+ } finally {
953
+ closeSync2(fd);
954
+ }
955
+ } catch {
956
+ return { hit: false, next: prior && prior.path === path ? prior : { path, offset: 0 } };
957
+ }
958
+ }, seatWindowBody2 = (w) => ({
959
+ capturedAt: w.capturedAt,
960
+ source: "claude",
961
+ ...w.fiveHour ? { fiveHour: w.fiveHour } : {},
962
+ ...w.sevenDay ? { sevenDay: w.sevenDay } : {},
963
+ ...w.spendLimit ? { spendLimit: w.spendLimit } : {}
964
+ }), postJson2 = async (o2, path, body) => {
965
+ const fetchFn = o2.fetchFn ?? fetch;
966
+ try {
967
+ const res = await fetchFn(`${o2.proxyUrl}${path}`, {
968
+ method: "POST",
969
+ headers: { authorization: `Bearer ${o2.token}`, "content-type": "application/json" },
970
+ body: JSON.stringify(body),
971
+ signal: AbortSignal.timeout(o2.timeoutMs ?? SEAT_POST_TIMEOUT_MS2)
972
+ });
973
+ return res.ok;
974
+ } catch {
975
+ return false;
976
+ }
977
+ }, postSeatWindow2 = (o2, w) => postJson2(o2, "/proxy/seat", seatWindowBody2(w)), postSeatWall2 = (o2, input) => postJson2(o2, "/proxy/seat-wall", { source: "claude", ...input }), SEAT_WALL_LINE2 = "Seat limit hit. sleds on --until-reset to continue on the platform 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((resolve6) => {
549
978
  if (stdin.isTTY) {
550
- resolve("");
979
+ resolve6("");
551
980
  return;
552
981
  }
553
982
  let data = "";
@@ -557,7 +986,7 @@ var SEAT_POST_MIN_INTERVAL_MS2, readStdin2 = (timeoutMs, stdin = process.stdin)
557
986
  return;
558
987
  settled = true;
559
988
  clearTimeout(timer);
560
- resolve(data);
989
+ resolve6(data);
561
990
  };
562
991
  const timer = setTimeout(finish, timeoutMs);
563
992
  stdin.setEncoding("utf8");
@@ -572,6 +1001,7 @@ var init_seat = __esm(() => {
572
1001
  init_config();
573
1002
  init_meter();
574
1003
  SEAT_POST_MIN_INTERVAL_MS2 = 5 * 60000;
1004
+ CREDITS_PATTERN2 = /out of usage credits|cc_cli_limit_message/i;
575
1005
  });
576
1006
 
577
1007
  // src/index.ts
@@ -757,28 +1187,34 @@ var GUIDES = [
757
1187
  id: "board",
758
1188
  title: "Read the board",
759
1189
  audience: "everyone",
760
- lede: "Sleds is the board: the pool of sized work, a sled per seat with the jobs moving on it, and what landed this week.",
1190
+ lede: "Work is the items: the pool of sized work and what landed this week. Sleds is who pulls them — a person or an agent on its own — and Seats what each sled pulls with.",
761
1191
  steps: [
762
1192
  {
763
- do: "Open `Sleds` and read the strip",
764
- where: "Sleds",
765
- note: "Five lanes: waiting for product · ready · moving · landed this week · worth landed. Click a lane to narrow the page; `Mine` shows your sled, the rows proposed for you and the asks you filed."
1193
+ do: "Open `Work` and read the strip",
1194
+ where: "Work",
1195
+ note: "Five lanes: waiting for product · ready · moving · landed this week · worth landed. Click a lane to narrow the page; `Mine` shows your sled, the items proposed for you and the asks you filed."
1196
+ },
1197
+ {
1198
+ do: "Read a pool item: the band, the worth, the chip, the readiness",
1199
+ note: "`proposed` names the sled the rules (and the model) suggest, with why; `waiting for product` needs a yes; `N gaps` says what is missing before anyone could start; an amber note says a related or duplicate item exists. `Take it` puts it on your sled; an approver can `Put it on <name>'s sled`."
766
1200
  },
767
1201
  {
768
- do: "Read a pool row: the band, the worth, the chip",
769
- note: "`proposed` names the seat the rules (and the model) suggest, with why; `waiting for product` needs a yes; an amber note says a related or duplicate row exists. `Take it` puts it on your sled; an approver can `Put it on <seat>'s sled`."
1202
+ do: "Read a sled card: the seats, the jobs, the band spent",
1203
+ where: "Sleds",
1204
+ note: "Each seat is one agent on one platform with its own wall; the bar is the window used. A job says which seat it runs on and, at a wall, `paused at a wall` with `Move to <seat>` when the sled has headroom elsewhere."
770
1205
  },
771
1206
  {
772
- do: "Read a seat card: the rails, the jobs, the band spent",
773
- note: "Each rail is one agent on one platform with its own wall; the bar is the window used. A job says which rail it runs on and, at a wall, `paused at a wall` with `Move to <rail>` when the seat has headroom elsewhere."
1207
+ do: "Open an item for the whole story",
1208
+ note: "The modal: the description, the links and files, the brief and who filed it, the child items, the questions, the thread — and every verb that applies to you. `copy as markdown` is the whole item as one document."
774
1209
  },
775
1210
  {
776
- do: "Open a row for the whole story",
777
- note: "The panel: the brief and who filed it, what the AI added, the recommendation, milestones with holders, runs, the receipt when it lands, and every verb that applies to you."
1211
+ do: "File one from here when chat is not at hand",
1212
+ where: "Work › + New item",
1213
+ note: "Title, why, done — the same brief your AI files from chat — then the description, repos, due, worth and a parent if it has one. Sized on file."
778
1214
  }
779
1215
  ],
780
- check: "Your own sled shows under `Mine` with the jobs you hold; a landed row shows its measured time and verdict under `Landed this week` and on Record › Receipts.",
781
- scope: "A product viewer sees seats and holders, never rails, models or spend; the words on the board are the words in chat — sled, seat, rail, job, wall, receipt."
1216
+ check: "Your own sled shows under `Mine` with the jobs you hold; a landed item shows its measured time and verdict under `Landed this week` and on Record › Receipts.",
1217
+ scope: "A product viewer sees sleds and holders, never seats, models or spend; the words on the board are the words in chat — item, sled, seat, job, wall, receipt."
782
1218
  },
783
1219
  {
784
1220
  id: "workspace",
@@ -852,7 +1288,7 @@ var GUIDES = [
852
1288
  {
853
1289
  do: "Optional: SLEDS for Chrome — the meter, and the Team roster and credits when you administer the plan",
854
1290
  where: "The zip your admin sends › unzip › `chrome://extensions` › Developer mode › `Load unpacked` › the `dist` folder",
855
- note: "Then right-click the icon › Options: Proxy URL `https://proxy.sleds.ai`, the same seat token, platform Anthropic, tick the consent box, Save. It reads your seat's bars from claude.ai — the rails the proxy cannot see — and reports them even when Claude Code is closed. Chrome nags about developer-mode extensions on start until the Web Store listing; dismiss it."
1291
+ note: "Then right-click the icon › Options: Proxy URL `https://proxy.sleds.ai`, the same seat token, platform Anthropic, tick the consent box, Save. It reads your seat's bars from claude.ai — the quota the proxy cannot see — and reports them even when Claude Code is closed. Chrome nags about developer-mode extensions on start until the Web Store listing; dismiss it."
856
1292
  }
857
1293
  ],
858
1294
  check: "`/sled usage` answers with your name and workspace; the status line in Claude Code shows the same bars."
@@ -904,7 +1340,7 @@ var GUIDES = [
904
1340
  {
905
1341
  do: "Connect the site and name the projects to mirror",
906
1342
  where: "Settings › Integrations › Jira › `Connect`",
907
- note: "`Site` is the host (`acme.atlassian.net`). `Projects to mirror, read-only` takes project keys (`WORK, CORE`): their open issues become sized rows in the pool on Sleds, epics with their children, and an issue that reaches Done lands its row — pulled every 30 minutes or with `Sync now`. Leave `Project key intake files into` blank for read-only; set it later and intake files a Jira issue and `plan` files sub-tasks."
1343
+ note: "`Site` is the host (`acme.atlassian.net`). `Projects to mirror, read-only` takes project keys (`WORK, CORE`): their open issues become sized items in the pool on Sleds, epics with their children, and an issue that reaches Done lands its row — pulled every 30 minutes or with `Sync now`. Leave `Project key intake files into` blank for read-only; set it later and intake files a Jira issue and `plan` files sub-tasks."
908
1344
  },
909
1345
  {
910
1346
  do: "Prove the token with `Send test` and the issue key left blank",
@@ -917,13 +1353,13 @@ var GUIDES = [
917
1353
  }
918
1354
  ],
919
1355
  check: "The Jira tile says connected with the token's last four, the blank Send test names the account the token belongs to, and after `Sync now` the pool on Sleds lists the mirrored project's open issues with a band on each.",
920
- scope: "With the project key blank and no `sled` labels in use, SLEDS never creates or comments on a Jira issue. The mirror only reads; rows carry the tracker's own state, labels, priority and assignee, never edited here."
1356
+ scope: "With the project key blank and no `sled` labels in use, SLEDS never creates or comments on a Jira issue. The mirror only reads; items carry the tracker's own state, labels, priority and assignee, never edited here."
921
1357
  },
922
1358
  {
923
1359
  id: "slack",
924
1360
  title: "Connect Slack",
925
1361
  audience: "admin",
926
- lede: "One button. SLEDS posts hand-offs, walls and digests to a channel of yours and DMs the person a thing is for — with nothing to create, copy or paste.",
1362
+ lede: "One button. SLEDS posts hand-offs, walls and digests to a channel of yours, DMs the person a thing is for, and answers `@SLEDS` in any channel — with nothing to create, copy or paste.",
927
1363
  steps: [
928
1364
  {
929
1365
  do: "Add to Slack",
@@ -935,6 +1371,11 @@ var GUIDES = [
935
1371
  where: "In Slack, in that channel: `/invite @SLEDS`",
936
1372
  note: "Posting to the channel works from the moment you allowed; reading and replying in a private channel needs the bot as a member."
937
1373
  },
1374
+ {
1375
+ do: "Talk to it in a channel",
1376
+ where: "Any channel the bot is in: `@SLEDS where is QW-142` · `@SLEDS what's open` · `@SLEDS item QW-142` · `@SLEDS create a ticket for this`",
1377
+ note: "It answers in the thread. `create a ticket for this` under someone's message reads that message as the ask, posts the draft in the thread with the questions still open, takes the replies as answers, and files on *yes* — with the person who asked as the filer. A workspace installed before Sept 28 clicks Add to Slack once more so the app has the channel scopes."
1378
+ },
938
1379
  {
939
1380
  do: "Send one test post",
940
1381
  where: "Settings › Integrations › Slack › `Send test`",
@@ -952,7 +1393,7 @@ var GUIDES = [
952
1393
  id: "approval",
953
1394
  title: "Turn on product's yes",
954
1395
  audience: "admin",
955
- lede: "An approval step before engineering can take a row: it waits until someone product-side says yes, or defers it with a note.",
1396
+ lede: "An approval step before engineering can take an item: it waits until someone product-side says yes, or defers it with a note.",
956
1397
  steps: [
957
1398
  {
958
1399
  do: "Choose who needs a yes",
@@ -966,7 +1407,7 @@ var GUIDES = [
966
1407
  },
967
1408
  {
968
1409
  do: "Approvers decide from the board or the Overview",
969
- where: "Overview › `Waiting on product`, or the row on Sleds",
1410
+ where: "Overview › `Waiting on product`, or the item on Work",
970
1411
  note: "`Approve` opens the gate; `Defer` keeps it closed and carries the note back to the filer, who answers in the brief and it comes back. In chat the same is `approve {project, decision, note?}`."
971
1412
  },
972
1413
  {
@@ -974,7 +1415,7 @@ var GUIDES = [
974
1415
  note: "An approved epic can be planned in chat (`plan`): its milestones are sized, filed under it, and inherit the yes — they do not queue again. The epic's cap is the sum."
975
1416
  }
976
1417
  ],
977
- check: "File an ask from chat (`intake`): its row shows waiting for product in the pool on Sleds, the approvers see it under Waiting on product, and `run` on it is refused until someone approves."
1418
+ check: "File an ask from chat (`intake`): its item shows waiting for product in the pool on Work, the approvers see it under Waiting on product, and `run` on it is refused until someone approves."
978
1419
  }
979
1420
  ];
980
1421
  function findGuides(filter) {
@@ -1030,7 +1471,7 @@ var VERBS = [
1030
1471
  want: "See my overnight jobs and the team's open hand-offs",
1031
1472
  mcp: "jobs · handoffs",
1032
1473
  claudeCode: "/sled jobs · `sleds handoffs`",
1033
- app: "Sleds › Moving (the runs on each seat's sled) · Record › Receipts once they land",
1474
+ app: "Work › Moving (the runs on each sled) · Record › Receipts once they land",
1034
1475
  how: "Newest first: id, status, route, cost. Hand-offs meant for you are listed first."
1035
1476
  },
1036
1477
  {
@@ -1038,8 +1479,8 @@ var VERBS = [
1038
1479
  group: "meter",
1039
1480
  want: "Ask where a piece of work is",
1040
1481
  mcp: "status {q?} — a tracker key or a word from the title; nothing for what you filed",
1041
- app: "Sleds (the strip and the row's stage: waiting for product · deferred · ready · moving · landed)",
1042
- how: "One paragraph per row: its stage, who has it, the band, the worth, the tree when it has milestones, the PR when it landed. Yours by default; a lead widens to the team."
1482
+ app: "Work (the strip and the item's stage: waiting for product · deferred · ready · moving · landed)",
1483
+ how: "One paragraph per item: its stage, who has it, the band, the worth, the tree when it has milestones, the PR when it landed. Yours by default; a lead widens to the team."
1043
1484
  },
1044
1485
  {
1045
1486
  id: "touches",
@@ -1052,18 +1493,66 @@ var VERBS = [
1052
1493
  {
1053
1494
  id: "attach",
1054
1495
  group: "meter",
1055
- want: "Put the spec, the prototype or a screenshot on the row so the team can open it",
1056
- mcp: "attach {project, name, content, mime?, kind?} — intake takes the same as `attachments` when filing",
1057
- app: "Sleds › the row › Assets",
1058
- how: "The file itself lives in SLEDS, not only in the chat that made it: a spec as markdown, a prototype as one HTML page (opens and renders in its own tab), a screenshot. Up to 4 MB; the same name again replaces. Anyone on the board opens it from the row; the person who added it, or an admin, can remove it."
1496
+ want: "Put the spec, the prototype, a screenshot or a link on the item so the team can open it",
1497
+ mcp: "attach {project, name, content, mime?, kind?} · attach {project, url, title?} — intake takes the same as `attachments` when filing",
1498
+ app: "Work › the item › Links",
1499
+ how: "The file itself lives in SLEDS, not only in the chat that made it: a spec as markdown, a prototype as one HTML page (opens and renders in its own tab), a screenshot — or a link to a doc, a Figma, a Loom. Up to 4 MB; the same name again replaces. Anyone on the board opens it from the item; the person who added it, or an admin, can remove it."
1500
+ },
1501
+ {
1502
+ id: "update",
1503
+ group: "meter",
1504
+ want: "Change an item — its title, why, done, description, due day, what it sits under, or what it touches",
1505
+ mcp: "update {project, ask?, why?, done?, smallest?, touches?, demand?, description?, due?, parent?, repos?, sensitivity?}",
1506
+ app: "Work › the item › click a field",
1507
+ how: "The filer, an approver or an admin changes an item from chat or by clicking the field in the app; every change says who and through what (via Claude · Cowork, via ChatGPT, in the app) and the record keeps before and after. A change to the ask, done or smallest marks the band stale with a Re-size at hand — never re-sized silently. A mirrored ticket is the tracker's word and is not changed here."
1508
+ },
1509
+ {
1510
+ id: "archive",
1511
+ group: "meter",
1512
+ want: "Put an item away without deleting it",
1513
+ mcp: "archive {project, undo?}",
1514
+ app: "Work › the item › ⋯ › Archive · the archived chip on Work",
1515
+ how: "Archived items leave Work, the sleds and the counts, and keep everything — unarchive brings one back whole. The filer, an approver or an admin. Delete (⋯ › Delete…) is an admin's and only for a hand-filed item that never ran; a mirrored ticket and a landed item are archived, never deleted."
1516
+ },
1517
+ {
1518
+ id: "item",
1519
+ group: "meter",
1520
+ want: "Read an item whole — what an engineer or an agent needs to pick it up cold",
1521
+ mcp: "item {q}",
1522
+ app: "Work › the item · Copy as markdown",
1523
+ how: "One markdown document: the brief, the description, the repo(s), the links and files, what sits under it, the open questions, the thread, and the readiness line — what is still missing before someone could start. It is what an agent reads before building from an item, and what the readiness check reads."
1524
+ },
1525
+ {
1526
+ id: "check",
1527
+ group: "meter",
1528
+ want: "Know whether an item says enough to start — and what is missing",
1529
+ mcp: "check {project}",
1530
+ app: "Work › the item › Readiness › Check",
1531
+ how: "Readiness has two layers. The rules run on every read and cost nothing: no why, no done, no repo, an open question, not sized, waiting for product's yes, or thin. The check is a small model on the workspace's platform key reading the item as an engineer would and naming what it would have to ask before starting; its answer goes on the thread as a comment from SLEDS and rides on the item's readiness from then on. Nothing here judges the idea — only whether the item says enough."
1532
+ },
1533
+ {
1534
+ id: "profile",
1535
+ group: "meter",
1536
+ want: "Know how hard an item is, what it touches, and which model tier fits",
1537
+ mcp: "item {q} (the Profile line) · update {project, sensitivity, sensitivityNote?}",
1538
+ app: "Work › the item › Profile",
1539
+ how: "Spec 18. Rules, never a model: complexity (low · medium · high, with reasons — the kind of work, the steps that want a premium model, files, repos, gaps) maps to a tier (economy · default · premium; economy is Haiku). Sensitivity (public · internal · restricted) is the most restrictive of what a person said, what the repo's `.sled/config.yml` says (`dataClass`, `restrictedPaths`, `publicPaths`), what the product map says, and what the rules detect in the item's own words — personal data, secret shapes, bulk customer data. Anyone can raise it; only an approver can lower it, with a note, on the record. A restricted item's text never goes to a cloud model: no readiness check, no rerank. Routing on it comes with Policy › Routing (P2)."
1540
+ },
1541
+ {
1542
+ id: "comment",
1543
+ group: "meter",
1544
+ want: "Leave a note on an item's thread — for the team, or as your agent's record of what it did",
1545
+ mcp: "comment {project, md}",
1546
+ app: "Work › the item › Thread",
1547
+ how: "The thread is one conversation between the team and its agents: a comment from a person, a note from their Claude, a size from the estimator, a run's receipt, a question and its answer — in order, each signed with who and through what."
1059
1548
  },
1060
1549
  {
1061
1550
  id: "answer",
1062
1551
  group: "meter",
1063
1552
  want: "Answer a question engineering asked about something I filed",
1064
1553
  mcp: "answer {answer, project?, id?} — nothing to see what is waiting on you",
1065
- app: "Sleds › the row › Questions",
1066
- how: "An approver asks on the row; you hear by bell, DM and email. Your reply, here or on the row, goes on the record and the asker hears at once. A worth question answered with a level or a band sets the row's worth."
1554
+ app: "Work › the item › Questions",
1555
+ how: "An approver asks on the item; you hear by bell, DM and email. Your reply, here or on the item, goes on the record and the asker hears at once. A worth question answered with a level or a band sets the item's worth."
1067
1556
  },
1068
1557
  {
1069
1558
  id: "estimate",
@@ -1071,7 +1560,7 @@ var VERBS = [
1071
1560
  want: "Size a task before running it",
1072
1561
  mcp: "estimate {spec, source?}",
1073
1562
  claudeCode: "/sled estimate · `sleds spec-event` fires on save of a spec file",
1074
- app: "Sleds (rows appear in the pool as specs and issues are sized)",
1563
+ app: "Work (items appear in the pool as specs and issues are sized)",
1075
1564
  how: "A cost and time band with confidence and a spend cap — never a point figure. Recorded; the actual calibrates the next one."
1076
1565
  },
1077
1566
  {
@@ -1080,7 +1569,7 @@ var VERBS = [
1080
1569
  want: "Say what the work is worth to the business",
1081
1570
  mcp: "a `Worth:` line in the spec you estimate (`Worth: high · $5k–20k · Acme renewal`)",
1082
1571
  claudeCode: "`SLEDS-Worth:` line in the PR body",
1083
- app: "Sleds › the row › Worth…",
1572
+ app: "Work › the item › Worth…",
1084
1573
  how: "A level, dollars when you know them, a note. Yours to state; the tracker's priority stands in at low confidence; blank stays blank."
1085
1574
  },
1086
1575
  {
@@ -1088,15 +1577,15 @@ var VERBS = [
1088
1577
  group: "send",
1089
1578
  want: "Send an ask to engineering from the conversation I already have open",
1090
1579
  mcp: "intake {text, links?, answers?, confirm?, parent?}",
1091
- app: "Sleds (the row lands in the pool sized, filed by you, at waiting or ready)",
1092
- how: "Your AI reads what you sent and asks only what it cannot answer — who it is for, what done looks like, the smallest version, the worth, what it touches, how many have asked — then shows the brief. On yes the row is filed on the sled and sized. Nothing is written before yes; worth is never guessed. `parent` files it under an epic or the ask it spun off from, so the parent's tree cost is true."
1580
+ app: "Work (the item lands in the pool sized, filed by you, at waiting or ready)",
1581
+ how: "Your AI reads what you sent and asks only what it cannot answer — who it is for, what done looks like, the smallest version, the worth, what it touches, how many have asked — then shows the brief. On yes the item is filed on the sled and sized. Nothing is written before yes; worth is never guessed. `parent` files it under an epic or the ask it spun off from, so the parent's tree cost is true."
1093
1582
  },
1094
1583
  {
1095
1584
  id: "plan",
1096
1585
  group: "send",
1097
1586
  want: "Turn an approved epic into milestones I can send one at a time",
1098
1587
  mcp: "plan {q | project, milestones?, confirm?} — the epic first, then the drafted list",
1099
- app: "Sleds (the epic row expands into its milestones; the tree under its band) · Approve · plan it",
1588
+ app: "Work (the epic expands into its child items; the tree under its band) · Approve · plan it",
1100
1589
  how: "Your AI drafts 3–7 vertical slices from the epic's brief — each something a person could use on its own — and shows them. On yes SLEDS sizes each, files it under the epic with the epic's worth and approval (a Jira sub-task when the epic lives there), and says what the tree will cost. Nothing is filed before yes."
1101
1590
  },
1102
1591
  {
@@ -1104,15 +1593,15 @@ var VERBS = [
1104
1593
  group: "send",
1105
1594
  want: "Give product's yes on an ask — or say not now, and why",
1106
1595
  mcp: "approve {q, decision: approve | defer, note?}",
1107
- app: "Sleds › Approve / Defer on a waiting row · Overview › Waiting on product · Policy › Product's yes",
1108
- how: "Off by default. When Policy says asks from intake (or every row) wait for product, a row sits at waiting until an approver — the named approvers, else an owner or admin — approves it; nobody can run it before. Defer keeps it closed and sends the note to the filer; they answer in the brief and it comes back."
1596
+ app: "Work › Approve / Defer on a waiting item · Overview › Waiting on product · Policy › Product's yes",
1597
+ how: "Off by default. When Policy says asks from intake (or every item) wait for product, an item sits at waiting until an approver — the named approvers, else an owner or admin — approves it; nobody can run it before. Defer keeps it closed and sends the note to the filer; they answer in the brief and it comes back."
1109
1598
  },
1110
1599
  {
1111
1600
  id: "dispatch",
1112
1601
  group: "send",
1113
1602
  want: "Ask where a piece of work should go, then send it there",
1114
1603
  mcp: "dispatch {q, run?: now | park | overnight, to?} — suggests with no run",
1115
- app: "Sleds › Take it (onto your own sled) · Sleds › the row › Send to… · Put it on <seat>'s sled",
1604
+ app: "Work › Take it (onto your own sled) · Work › the item › Send to… · Put it on <name>'s sled",
1116
1605
  how: "Now on the seat with the most weekly headroom, overnight at half price, parked for the team, or not worth it yet — with the reasons. Nothing runs until you say run."
1117
1606
  },
1118
1607
  {
@@ -1121,7 +1610,7 @@ var VERBS = [
1121
1610
  want: "Send work to a teammate or a buddy",
1122
1611
  mcp: "handoff {task, to?, note?}",
1123
1612
  claudeCode: "/sled handoff · the wall popup",
1124
- app: "Sleds › the row › Send to… · extension › Park hand-off",
1613
+ app: "Work › the item › Send to… · extension › Park hand-off",
1125
1614
  how: "Parks a self-contained brief (the picker starts cold). Named by email — a teammate, or a paired buddy in another workspace — or anyone on the team."
1126
1615
  },
1127
1616
  {
@@ -1130,7 +1619,7 @@ var VERBS = [
1130
1619
  want: "Take back a hand-off nobody has picked up",
1131
1620
  mcp: "withdraw {handoffId}",
1132
1621
  claudeCode: "`sleds withdraw <id>`",
1133
- app: "Sleds › the row › Withdraw",
1622
+ app: "Work › the item › Withdraw",
1134
1623
  how: "Only the seat that parked it can withdraw it. Unpicked hand-offs are reminded after a day and expire after three."
1135
1624
  },
1136
1625
  {
@@ -1139,7 +1628,7 @@ var VERBS = [
1139
1628
  want: "Pick up work someone sent me",
1140
1629
  mcp: "handoffs → pickup {handoffId}",
1141
1630
  claudeCode: "/sled pickup <id> · `sleds pickup <id>`",
1142
- app: "Sleds › Take it · extension › Take it",
1631
+ app: "Work › Take it · extension › Take it",
1143
1632
  how: "A parked task comes back verbatim; a walled session comes back as its first and last messages. Runs on your seat, metered to your workspace."
1144
1633
  },
1145
1634
  {
@@ -1157,7 +1646,7 @@ var VERBS = [
1157
1646
  want: "Run this tonight at half price",
1158
1647
  mcp: "overnight {spec, source?}",
1159
1648
  claudeCode: "/sled overnight",
1160
- app: "wall popup › Run overnight · Sleds › the Night shift seat",
1649
+ app: "wall popup › Run overnight · Sleds › the Night shift sled",
1161
1650
  how: "Sized first; the cap bounds the spend. Runs in the workspace's overnight window on the batch tier; `/sled resume <id>` pulls it back in."
1162
1651
  },
1163
1652
  {
@@ -1165,7 +1654,7 @@ var VERBS = [
1165
1654
  group: "defer",
1166
1655
  want: "Pull a finished overnight job into my session",
1167
1656
  claudeCode: "/sled resume <id>",
1168
- app: "Sleds › the Night shift seat › the row",
1657
+ app: "Sleds › the Night shift sled › the item",
1169
1658
  how: "The delivered result, with its record of which model built it — which model built it, signed by the workspace key."
1170
1659
  },
1171
1660
  {
@@ -1174,15 +1663,15 @@ var VERBS = [
1174
1663
  want: "Record what a piece of work actually took",
1175
1664
  mcp: "actual {source, minutes?, usd?, model?, ref?}",
1176
1665
  claudeCode: "`SLEDS-Actual: 45 min · $7` in the PR body — the ledger posts it on merge",
1177
- app: "Record › Receipts (fills in on merge or delivery) · Sleds › Landed this week",
1178
- how: "Closes the estimate: est → actual per row, and the calibration for the next band. A delivered job closes its own."
1666
+ app: "Record › Receipts (fills in on merge or delivery) · Work › Landed this week",
1667
+ how: "Closes the estimate: est → actual per item, and the calibration for the next band. A delivered job closes its own."
1179
1668
  },
1180
1669
  {
1181
1670
  id: "verify",
1182
1671
  group: "close",
1183
1672
  want: "Check which model built something",
1184
1673
  claudeCode: "`sleds verify <jobId | SLEDS-Attest line>`",
1185
- app: "Record › Receipts › the row's ref",
1674
+ app: "Record › Receipts › the item's ref",
1186
1675
  how: "Ed25519 over the job, model, outputs and time; verified locally against the workspace's public key."
1187
1676
  },
1188
1677
  {
@@ -1234,6 +1723,10 @@ var VERBS = [
1234
1723
  }
1235
1724
  ];
1236
1725
  var FAQ = [
1726
+ {
1727
+ q: "Item, sled, seat — what are the words?",
1728
+ a: "An item is a unit of work — a feature, a fix, an ask — with a band and a worth; children are child items. A sled is who the work is on: a person, or an agent on its own. A seat is what a sled pulls with: an agent on a platform with a credential (Claude on a Team plan, Codex on an API key), each with its own wall. Work is the page of items, Sleds the page of sleds, Seats the capacity under them."
1729
+ },
1237
1730
  {
1238
1731
  q: "What does SLEDS see, and what does it keep?",
1239
1732
  a: "Requests stream through the proxy to your own Claude or OpenAI seat and back; we keep the numbers — tokens, model, cost, when — and the decisions, never your prompts or code. Two features carry content because they cannot work without it, and both are yours to turn off: a hand-off parks the conversation for a teammate (encrypted, expires in 7 days); an estimate reads a spec to size it. Your tracker and Slack receive what you already see in them."
@@ -1447,17 +1940,17 @@ function renderBrief(b) {
1447
1940
  function renderBriefMarkdown(b, open, extra = {}) {
1448
1941
  const cell = (t) => t.replace(/\|/g, "\\|").replace(/\s+/g, " ").trim();
1449
1942
  const rows = ["| | | |", "|---|---|---|"];
1450
- const field = (label, f) => {
1943
+ const field2 = (label, f) => {
1451
1944
  if (f)
1452
1945
  rows.push(`| **${label}** | ${cell(f.text)} | ${fromWord(f)} |`);
1453
1946
  };
1454
1947
  rows.push(`| **Ask** | ${cell(b.ask.text)} | ${fromWord(b.ask)} |`);
1455
- field("Why", b.why);
1456
- field("Done", b.done);
1457
- field("Smallest", b.smallest);
1948
+ field2("Why", b.why);
1949
+ field2("Done", b.done);
1950
+ field2("Smallest", b.smallest);
1458
1951
  rows.push(`| **Worth** | ${b.worth ? cell(worthLabel(b.worth)) : "_not stated_"} | ${b.worth ? "stated" : ""} |`);
1459
- field("Touches", b.touches);
1460
- field("Demand", b.demand);
1952
+ field2("Touches", b.touches);
1953
+ field2("Demand", b.demand);
1461
1954
  if (b.due)
1462
1955
  rows.push(`| **Due** | ${b.due} | from your words |`);
1463
1956
  const out = ["**Brief — draft**", "", ...rows];
@@ -1561,6 +2054,8 @@ var STOP = new Set([
1561
2054
  "up",
1562
2055
  "via"
1563
2056
  ]);
2057
+ // ../../packages/shared/src/profile/profile.ts
2058
+ var LIGHT = new Set(["summarize", "research", "walkthrough", "docs"]);
1564
2059
  // ../../packages/shared/src/dispatch/plan.ts
1565
2060
  init_format();
1566
2061
 
@@ -1666,29 +2161,50 @@ init_format();
1666
2161
  var isObject2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
1667
2162
  var str2 = (v) => typeof v === "string" ? v : undefined;
1668
2163
  var num2 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined;
1669
- function statusName(row) {
1670
- const source = isObject2(row.source) ? row.source : {};
2164
+ function statusName(row2) {
2165
+ const source = isObject2(row2.source) ? row2.source : {};
1671
2166
  const kind = str2(source.kind);
1672
2167
  const doc = str2(source.doc);
1673
- const title = str2(row.title) ?? str2(row.project) ?? "this row";
2168
+ const title = str2(row2.title) ?? str2(row2.project) ?? "this row";
1674
2169
  if ((kind === "linear" || kind === "github" || kind === "jira") && doc)
1675
2170
  return `${doc} · ${title}`;
1676
- const key = str2(row.key);
2171
+ const key = str2(row2.key);
1677
2172
  return key ? `${key} · ${title}` : title;
1678
2173
  }
1679
- function stateTail(row) {
1680
- const retired = str2(row.retired);
2174
+ function stateTail(row2) {
2175
+ const retired = str2(row2.retired);
1681
2176
  if (retired)
1682
2177
  return ` Retired: ${retired}.`;
1683
- if (row.stale === true)
2178
+ if (row2.stale === true)
1684
2179
  return " Stale: no movement in 14 days.";
1685
2180
  return "";
1686
2181
  }
1687
- function statusLine(row, now) {
1688
- return `${statusBody(row, now)}${trackerTail(row)}${stateTail(row)}${assetsTail(row)}`;
2182
+ function statusLine(row2, now) {
2183
+ return `${statusBody(row2, now)}${trackerTail(row2)}${stateTail(row2)}${readinessTail(row2)}${profileTail(row2)}${assetsTail(row2)}`;
1689
2184
  }
1690
- function assetsTail(row) {
1691
- const assets = Array.isArray(row.assets) ? row.assets.filter(isObject2) : [];
2185
+ function profileTail(row2) {
2186
+ const p2 = isObject2(row2.profile) ? row2.profile : null;
2187
+ if (!p2)
2188
+ return "";
2189
+ const line = str2(p2.line);
2190
+ if (!line)
2191
+ return "";
2192
+ const why = Array.isArray(p2.reasons) ? p2.reasons.filter((x) => typeof x === "string") : [];
2193
+ const restricted = str2(p2.sensitivity) === "restricted";
2194
+ return ` Profile: ${line}${why.length && (restricted || str2(p2.source) !== "default") ? ` (${why.slice(0, 2).join("; ")})` : ""}.${restricted ? " Restricted: cloud routes close for it once Policy › Routing says so; nothing is held yet." : ""}`;
2195
+ }
2196
+ function readinessTail(row2) {
2197
+ const r = isObject2(row2.readiness) ? row2.readiness : null;
2198
+ if (!r || str2(r.state) !== "gaps")
2199
+ return "";
2200
+ const line = str2(r.line);
2201
+ if (!line)
2202
+ return "";
2203
+ const repos = Array.isArray(row2.repos) ? row2.repos.filter((x) => typeof x === "string") : [];
2204
+ return ` Readiness: ${line}.${repos.length ? ` Repo: ${repos.join(", ")}.` : ""} \`item\` reads the whole thing; \`check\` asks the model.`;
2205
+ }
2206
+ function assetsTail(row2) {
2207
+ const assets = Array.isArray(row2.assets) ? row2.assets.filter(isObject2) : [];
1692
2208
  if (assets.length === 0)
1693
2209
  return "";
1694
2210
  const parts = assets.map((a) => {
@@ -1699,8 +2215,8 @@ function assetsTail(row) {
1699
2215
  });
1700
2216
  return ` On the row: ${parts.join(" · ")}.`;
1701
2217
  }
1702
- function trackerTail(row) {
1703
- const source = isObject2(row.source) ? row.source : {};
2218
+ function trackerTail(row2) {
2219
+ const source = isObject2(row2.source) ? row2.source : {};
1704
2220
  const kind = str2(source.kind);
1705
2221
  if (kind !== "github" && kind !== "jira" && kind !== "linear")
1706
2222
  return "";
@@ -1742,36 +2258,36 @@ function trackerTail(row) {
1742
2258
  const where = kind === "github" ? "GitHub" : kind === "jira" ? "Jira" : "Linear";
1743
2259
  return ` In ${where}: ${bits.join(" · ")}.`;
1744
2260
  }
1745
- function statusBody(row, now) {
1746
- const name = statusName(row);
1747
- const stage = str2(row.stage) ?? "ready";
1748
- const handoff = isObject2(row.handoff) ? row.handoff : null;
1749
- const work = isObject2(row.work) ? row.work : null;
1750
- const worth = isObject2(row.worth) ? row.worth : null;
1751
- const band = bandLine(row.band);
2261
+ function statusBody(row2, now) {
2262
+ const name = statusName(row2);
2263
+ const stage = str2(row2.stage) ?? "ready";
2264
+ const handoff = isObject2(row2.handoff) ? row2.handoff : null;
2265
+ const work = isObject2(row2.work) ? row2.work : null;
2266
+ const worth = isObject2(row2.worth) ? row2.worth : null;
2267
+ const band = bandLine(row2.band);
1752
2268
  const sized = band ? `Sized ${band}` : "Not sized";
1753
2269
  const worthText = worth ? `worth ${worthLabel(worth)}` : "worth not stated";
1754
2270
  const ago = (ts) => num2(ts) !== undefined ? `${shortDuration(Math.max(0, now - num2(ts)))} ago` : "";
1755
2271
  if (stage === "landed") {
1756
- const mins = num2(row.actualMinutes);
1757
- const dollars = num2(row.actualUsd);
2272
+ const mins = num2(row2.actualMinutes);
2273
+ const dollars2 = num2(row2.actualUsd);
1758
2274
  const credits = work ? num2(work.seatCreditsUsd) : undefined;
1759
2275
  const bits = [
1760
2276
  mins !== undefined ? `${Math.round(mins)} min` : null,
1761
- dollars !== undefined && dollars > 0 ? usd2(dollars) : null,
2277
+ dollars2 !== undefined && dollars2 > 0 ? usd2(dollars2) : null,
1762
2278
  credits !== undefined ? `${usd2(credits)} credits` : null,
1763
2279
  work ? str2(work.model) : null
1764
2280
  ].filter((b) => Boolean(b));
1765
2281
  const ref = work ? str2(work.ref) : undefined;
1766
2282
  return `${name} — landed${bits.length ? `: ${bits.join(" · ")}` : ""}${ref ? ` · ${ref}` : ""}. ${sized}, ${worthText}.`;
1767
2283
  }
1768
- const tree = isObject2(row.tree) ? row.tree : null;
2284
+ const tree = isObject2(row2.tree) ? row2.tree : null;
1769
2285
  const treeText = treeLine(tree);
1770
2286
  if (stage === "on_sled" && handoff) {
1771
2287
  const who = str2(handoff.pickedBy) ?? "someone";
1772
2288
  return `${name} — on the sled: ${who} has it (picked ${ago(handoff.at)}). ${sized}, ${worthText}.${treeText} You will hear when it lands.`;
1773
2289
  }
1774
- const approval = isObject2(row.approval) ? row.approval : null;
2290
+ const approval = isObject2(row2.approval) ? row2.approval : null;
1775
2291
  if (stage === "deferred") {
1776
2292
  const by = approval ? str2(approval.by) ?? "product" : "product";
1777
2293
  const note = approval ? str2(approval.note) : undefined;
@@ -1787,7 +2303,7 @@ function statusBody(row, now) {
1787
2303
  const to = str2(handoff.to);
1788
2304
  return `${name} — ready, parked ${to ? `for ${to}` : "for anyone on the team"} ${ago(handoff.at)}; nobody has taken it yet. ${sized}, ${worthText}.${okText}${treeText}`;
1789
2305
  }
1790
- return `${name} — ready; nobody has it yet. ${sized}, ${worthText}.${okText}${treeText} An engineer takes it from the sled (Projects › Take it, or /sled pickup after a Send to…).`;
2306
+ return `${name} — ready; nobody has it yet. ${sized}, ${worthText}.${okText}${treeText} An engineer takes it from the pool (Work › Take it, or /sled pickup after a Send to…).`;
1791
2307
  }
1792
2308
  function treeLine(tree) {
1793
2309
  if (!tree)
@@ -2014,11 +2530,11 @@ a{color:var(--peri)}
2014
2530
  </script></body></html>`;
2015
2531
 
2016
2532
  // ../../packages/shared/src/mcp/server.ts
2017
- function fetchClient(o) {
2018
- const fetchFn = o.fetchFn ?? fetch;
2019
- const base = o.proxyUrl.replace(/\/+$/, "");
2020
- const headers = { "content-type": "application/json", authorization: `Bearer ${o.token}` };
2021
- const timeout = () => AbortSignal.timeout(o.timeoutMs ?? MCP_TIMEOUT_MS);
2533
+ function fetchClient(o2) {
2534
+ const fetchFn = o2.fetchFn ?? fetch;
2535
+ const base = o2.proxyUrl.replace(/\/+$/, "");
2536
+ const headers = { "content-type": "application/json", authorization: `Bearer ${o2.token}` };
2537
+ const timeout = () => AbortSignal.timeout(o2.timeoutMs ?? MCP_TIMEOUT_MS);
2022
2538
  return {
2023
2539
  async post(path, body) {
2024
2540
  try {
@@ -2081,17 +2597,17 @@ var SERVER_INFO = {
2081
2597
  ]
2082
2598
  };
2083
2599
  var SERVER_INSTRUCTIONS = [
2084
- "SLEDS is the ledger of engineering work: every piece is sized before it runs (a cost and time band, never a point figure) and closed with a measured actual after. You are the head; SLEDS holds the record. The person may be a PM or designer describing something they want built, or an engineer about to build — read which.",
2085
- 'When someone describes work for engineering (a feature, a fix, a spec, a PRD, "can we…"): offer once to put it on the sled. If they say yes, use `intake` — it drafts the brief, asks only what it cannot answer (who it is for and why now, what done looks like, the smallest version, the worth, how many have asked) two at a time, writes nothing until they confirm. Never guess worth. It also reads the product map — what the ask touches, which product docs it names, what on the board collides with it; read it back plainly, let them correct it (`touches` answers the same for any question). You judge; the map only says what is there. About a page that exists? Ask for its URL (in `links`) and a screenshot to mock the change on. Anything with a screen: offer once a clickable prototype in the workspace\'s design system when intake names one — it is the ask, not the spec. Spec, prototype, screenshot go on the row as files (`attachments` on intake, `attach` after) so anyone on the board can open them; a link only they can. Change a filed ask here, not from Slack. Say it is on the sled, the band, whether it waits for product\'s yes. They never need to learn a verb.',
2086
- "When you are about to build something that will take more than a few minutes: `status` first if a row may exist for it; otherwise `estimate` with a stable `source` (kind · project · doc · item) before the first line of work, and say the band. When it lands: `actual` with the same `source`, the state, where the output lives (`ref`), the model, and your session link (`sessionId`). Do not pass `minutes` unless a person stated them — SLEDS measures the time itself. A follow-up to landed work is a new `item` under the same doc, never an overwrite. An `actual` with no estimate still records (landed unsized), but the band you skipped is the point, so estimate first.",
2087
- "If SLEDS says there is no estimate for the source, size it first and send the actual again. If it says unreachable, try once more; then move on and tell the person the row is still owed. Never invent a number to get past an error."
2600
+ "SLEDS is where the business meets engineering: every piece of work is sized before it runs (a cost and time band, never a point figure) and closed with a measured actual after. You are the head; SLEDS holds the record. The person may be a PM or designer describing what they want built, or an engineer about to build — read which.",
2601
+ 'When someone describes work for engineering (a feature, a fix, a spec, a PRD, "can we…"): offer once to put it on the sled. If they say yes, use `intake` — it drafts the brief, asks only what it cannot answer (who it is for and why now, what done looks like, the smallest version, the worth, how many asked) two at a time, writes nothing until they confirm. Never guess worth. It also reads the product map — what the ask touches, which product docs it names, what on the board collides with it; read it back plainly, let them correct it (`touches` answers the same for any question). You judge; the map only says what is there. About a page that exists? Ask for its URL (in `links`) and a screenshot to mock the change on. Anything with a screen: offer once a clickable prototype in the workspace\'s design system when intake names one — it is the ask, not the spec. Spec, prototype, screenshot go on the item as files (`attachments` on intake, `attach` after) so anyone on the board can open them; a link only they can. Change a filed ask here, not from Slack. Say it is on the sled, the band, whether it waits for product\'s yes. They never need to learn a verb.',
2602
+ "When you are about to build something that will take more than a few minutes: `status` first if an item may exist for it; `item` reads it whole; otherwise `estimate` with a stable `source` (kind · project · doc · item) before the first line of work, and say the band. When it lands: `actual` with the same `source`, the state, where the output lives (`ref`), the model, and your session link (`sessionId`). Do not pass `minutes` unless a person stated them — SLEDS measures time. A follow-up to landed work is a new `item` under the same doc, never an overwrite. An `actual` with no estimate still records, but the band you skipped is the point, so estimate first.",
2603
+ "If SLEDS says there is no estimate for the source, size it first and send the actual again. If it says unreachable, try once more; then move on and tell the person the item is still owed. Never invent a number to get past an error."
2088
2604
  ].join(`
2089
2605
 
2090
2606
  `);
2091
2607
  var MCP_TIMEOUT_MS = 5000;
2092
2608
  var sourceSchema = {
2093
2609
  type: "object",
2094
- description: "Where this item lives, so the Projects page groups it: a Claude Project doc, a repo spec, a Linear/GitHub issue. Same source + same text on a later call returns the same estimate (idempotent sync).",
2610
+ description: "Where this item lives, so the Work page groups it: a Claude Project doc, a repo spec, a Linear/GitHub issue. Same source + same text on a later call returns the same estimate (idempotent sync).",
2095
2611
  properties: {
2096
2612
  kind: {
2097
2613
  type: "string",
@@ -2127,13 +2643,13 @@ var TOOLS = [
2127
2643
  },
2128
2644
  {
2129
2645
  name: "estimate",
2130
- description: "Call this BEFORE starting any build that will take more than a few minutes — before the first line of work, not after. Sizes the task: the org estimator's cost and time band with confidence and a spend cap, never a point figure. Pass a stable `source` (kind · project · doc · item) so the row has a home on the sled and the later `actual` finds it. Recorded, so actuals calibrate the next estimate.",
2646
+ description: "Call this BEFORE starting any build that will take more than a few minutes — before the first line of work, not after. Sizes the task: the org estimator's cost and time band with confidence and a spend cap, never a point figure. Pass a stable `source` (kind · project · doc · item) so the item has a home on the sled and the later `actual` finds it. Recorded, so actuals calibrate the next estimate.",
2131
2647
  inputSchema: specSchema
2132
2648
  },
2133
2649
  {
2134
2650
  name: "intake",
2135
2651
  _meta: { ui: { resourceUri: INTAKE_VIEW_URI } },
2136
- description: 'Use this when a person describes work they want engineering to do — a feature, a fix, a spec, a PRD, "can we…" — and has said yes to putting it on the sled. Sends the ask to engineering from this conversation (spec 13). Pass what the person sent — a paragraph, a spec, a PRD — plus any links (the URL of the page it is about, a prototype you made). If it concerns a page or feature that already exists, ask for its URL and a screenshot first — the screenshot is what you mock the change on. Without `confirm` nothing is written: you get the brief drafted from it and the questions still open (who it is for and why now, what done looks like, the smallest version, the worth, what it touches and where it would live, how many have asked) — ask at most two at a time, in your own words, and skip any the person already answered. Put their answers in `answers`, show them the brief, and when they say yes call again with `confirm: true`: the row is filed on the sled, sized, with their name on it. A brief without a why and a done is a draft and will not file. Worth is never guessed.',
2652
+ description: 'Use this when a person describes work they want engineering to do — a feature, a fix, a spec, a PRD, "can we…" — and has said yes to putting it on the sled. Sends the ask to engineering from this conversation (spec 13). Pass what the person sent — a paragraph, a spec, a PRD — plus any links (the URL of the page it is about, a prototype you made). If it concerns a page or feature that already exists, ask for its URL and a screenshot first — the screenshot is what you mock the change on. Without `confirm` nothing is written: you get the brief drafted from it and the questions still open (who it is for and why now, what done looks like, the smallest version, the worth, what it touches and where it would live, how many have asked) — ask at most two at a time, in your own words, and skip any the person already answered. Put their answers in `answers`, show them the brief, and when they say yes call again with `confirm: true`: the item is filed on the sled, sized, with their name on it. A brief without a why and a done is a draft and will not file. Worth is never guessed.',
2137
2653
  inputSchema: {
2138
2654
  type: "object",
2139
2655
  properties: {
@@ -2193,7 +2709,7 @@ var TOOLS = [
2193
2709
  added: {
2194
2710
  type: "array",
2195
2711
  items: { type: "string" },
2196
- description: "What you added on the way, one line each — milestones you drafted ('M1 — the posting form only'), a decision you flagged for product, the nearest landed work you found. Shown on the row as the AI's contribution; an approver reads it before saying yes."
2712
+ description: "What you added on the way, one line each — milestones you drafted ('M1 — the posting form only'), a decision you flagged for product, the nearest landed work you found. Shown on the item as the AI's contribution; an approver reads it before saying yes."
2197
2713
  },
2198
2714
  due: {
2199
2715
  type: "string",
@@ -2206,6 +2722,15 @@ var TOOLS = [
2206
2722
  parent: {
2207
2723
  type: "string",
2208
2724
  description: "The exact project key (from status) of the row this ask belongs under — an epic's milestone, or a spin-off found while building. The parent's tree cost then includes it."
2725
+ },
2726
+ repos: {
2727
+ type: "array",
2728
+ items: { type: "string" },
2729
+ description: "The repo(s) the work lands in, owner/name, when the person named one. Otherwise the product map's hit is used."
2730
+ },
2731
+ workspace: {
2732
+ type: "string",
2733
+ description: "Spec 19: the workspace (a board inside the org — by name or slug) the item is for. The draft lists the org's workspaces when it has more than one and asks; the person may skip it, and the item is placed later on the Work page."
2209
2734
  }
2210
2735
  },
2211
2736
  required: ["text"]
@@ -2243,7 +2768,7 @@ var TOOLS = [
2243
2768
  },
2244
2769
  {
2245
2770
  name: "approve",
2246
- description: "Product's yes on an ask (or 'not now' with a note). Only when the workspace gates asks (Policy › product's yes: intake or always) do rows wait; then an engineer cannot run one until product approves it. decision 'approve' opens the gate; 'defer' keeps it closed and sends the note back to the filer through status. The seat must be an approver: a named approver in Policy, else an owner or admin. Pass q (a tracker key or a word from the title) or the exact project key from status.",
2771
+ description: "Product's yes on an ask (or 'not now' with a note). Only when the workspace gates asks (Policy › product's yes: intake or always) do items wait; then an engineer cannot run one until product approves it. decision 'approve' opens the gate; 'defer' keeps it closed and sends the note back to the filer through status. The seat must be an approver: a named approver in Policy, else an owner or admin. Pass q (a tracker key or a word from the title) or the exact project key from status.",
2247
2772
  inputSchema: {
2248
2773
  type: "object",
2249
2774
  properties: {
@@ -2293,7 +2818,7 @@ var TOOLS = [
2293
2818
  },
2294
2819
  {
2295
2820
  name: "status",
2296
- description: "Where is it — call this first when you may be picking up work that already has a row (a ticket key, a spec section, a hand-off), so you estimate nothing twice. One paragraph per piece of work: its stage on the sled (waiting for product · deferred · ready · on the sled · landed), who has it, the size band, the worth, the tree when it has milestones, and the PR when it landed. Pass q (a tracker key like ENG-482, or a word from the title); with nothing, the rows you filed through intake, newest first.",
2821
+ description: "Where is it — call this first when you may be picking up work that already has an item (a ticket key, a spec section, a hand-off), so you estimate nothing twice. One paragraph per piece of work: its stage on the sled (waiting for product · deferred · ready · on the sled · landed), who has it, the size band, the worth, the tree when it has milestones, and the PR when it landed. Pass q (a tracker key like ENG-482, or a word from the title); with nothing, the rows you filed through intake, newest first.",
2297
2822
  inputSchema: {
2298
2823
  type: "object",
2299
2824
  properties: {
@@ -2306,7 +2831,7 @@ var TOOLS = [
2306
2831
  },
2307
2832
  {
2308
2833
  name: "touches",
2309
- description: "What the product says an ask reaches: the areas of the product (from the workspace's repos), the product's own documents it names, and the rows on the board it collides with. Call with `text` — the ask, or a question like 'if we change the 4-hour minimum, what else is affected?'. Read it back in plain words; you judge, the map only says what is there. `intake` calls this on its own while drafting.",
2834
+ description: "What the product says an ask reaches: the areas of the product (from the workspace's repos), the product's own documents it names, and the items on the board it collides with. Call with `text` — the ask, or a question like 'if we change the 4-hour minimum, what else is affected?'. Read it back in plain words; you judge, the map only says what is there. `intake` calls this on its own while drafting.",
2310
2835
  inputSchema: {
2311
2836
  type: "object",
2312
2837
  properties: {
@@ -2317,14 +2842,16 @@ var TOOLS = [
2317
2842
  },
2318
2843
  {
2319
2844
  name: "attach",
2320
- description: "Put a file on a row already on the sled so anyone on the board can open it — a spec or PRD as markdown, a prototype you made as one HTML page (it opens and renders in its own tab), a screenshot. Pass the row's project key (from status, or what intake said) and the file. Up to 4 MB; the same name again replaces the earlier one. `intake` takes the same files as `attachments` when filing.",
2845
+ description: "Put a file or a link on an item so anyone on the board can open it — a spec or PRD as markdown, a prototype you made as one HTML page (it opens and renders in its own tab), a screenshot; or a URL (a doc, a Figma, a Loom) with `url` instead of a file. Pass the item's key (QW-142, from status, or what intake said). Files up to 4 MB; the same name again replaces the earlier one. `intake` takes the same files as `attachments` when filing.",
2321
2846
  inputSchema: {
2322
2847
  type: "object",
2323
2848
  properties: {
2324
- project: {
2849
+ project: { type: "string", description: "The item's key — QW-142 — or its project key." },
2850
+ url: {
2325
2851
  type: "string",
2326
- description: "The row's project key, e.g. manual:intake/help-and-support or jira:WORK/WORK-7551."
2852
+ description: "A link instead of a file: the URL. `title` names it."
2327
2853
  },
2854
+ title: { type: "string", description: "With url: what to call the link." },
2328
2855
  name: {
2329
2856
  type: "string",
2330
2857
  description: "File name with extension: spec.md, prototype.html, before.png."
@@ -2341,12 +2868,83 @@ var TOOLS = [
2341
2868
  },
2342
2869
  encoding: { type: "string", enum: ["text", "base64"] }
2343
2870
  },
2344
- required: ["project", "name", "content"]
2871
+ required: ["project"]
2872
+ }
2873
+ },
2874
+ {
2875
+ name: "update",
2876
+ description: "Change an item on the sled — its title (`ask`), why, done, smallest, touches, demand, its description (markdown: the prose the brief does not hold), its due day, which item it sits under, the repo(s) it lands in, or its sensitivity (public · internal · restricted). Pass the item's key and only the fields that change. The filer, an approver or an admin may; a mirrored ticket cannot be changed here. A change to the ask, done or smallest marks the band stale — say so, and offer to re-size. Everything you write is signed as coming through you.",
2877
+ inputSchema: {
2878
+ type: "object",
2879
+ properties: {
2880
+ project: { type: "string", description: "The item's key — QW-142 — or its project key." },
2881
+ ask: { type: "string", description: "The title: what they want, one line." },
2882
+ why: { type: "string" },
2883
+ done: { type: "string" },
2884
+ smallest: { type: "string" },
2885
+ touches: { type: "string" },
2886
+ demand: { type: "string" },
2887
+ description: {
2888
+ type: "string",
2889
+ description: "Markdown. Links and images inline. Empty clears it."
2890
+ },
2891
+ due: { type: ["string", "null"], description: "YYYY-MM-DD, or null to clear." },
2892
+ parent: {
2893
+ type: ["string", "null"],
2894
+ description: "The parent item's key, or null for none."
2895
+ },
2896
+ repos: {
2897
+ type: "array",
2898
+ items: { type: "string" },
2899
+ description: "The repo(s) the work lands in, owner/name. Replaces the list; [] clears it."
2900
+ },
2901
+ sensitivity: {
2902
+ type: ["string", "null"],
2903
+ enum: ["public", "internal", "restricted", null],
2904
+ description: "The person's word on what the work touches: public · internal · restricted. Anyone can raise it; only an approver can lower it below what the rules found, and then `sensitivityNote` says why. Null clears the word and the rules stand."
2905
+ },
2906
+ sensitivityNote: { type: "string", description: "Why, when lowering the class." }
2907
+ },
2908
+ required: ["project"]
2909
+ }
2910
+ },
2911
+ {
2912
+ name: "item",
2913
+ description: "Read one item whole, as one markdown document — everything an engineer or an agent needs to pick the work up cold: the brief, the description, the repo(s), the links and files, what sits under it, the open questions, the thread, and its readiness (what is still missing before someone could start). Pass the item's key (QW-142) or its title. Call this before building from an item, and before `check`.",
2914
+ inputSchema: {
2915
+ type: "object",
2916
+ properties: {
2917
+ q: { type: "string", description: "The item's key — QW-142 — or its title." }
2918
+ },
2919
+ required: ["q"]
2920
+ }
2921
+ },
2922
+ {
2923
+ name: "check",
2924
+ description: "Ask SLEDS to check an item's readiness with a model: it reads the item as an engineer would and names what it would have to ask before starting. The answer lands on the item's thread within a minute (and on `item` / `status` after). The rules-based readiness (no why, no done, no repo, open questions, unsized) is on every read for free; this is the second opinion, on the workspace's platform key. Pass the item's key.",
2925
+ inputSchema: {
2926
+ type: "object",
2927
+ properties: {
2928
+ project: { type: "string", description: "The item's key — QW-142 — or its project key." }
2929
+ },
2930
+ required: ["project"]
2931
+ }
2932
+ },
2933
+ {
2934
+ name: "comment",
2935
+ description: "Say something on an item's thread — a note, a finding, what you did, a question for the team. Markdown. It shows on the item for everyone with who wrote it and that it came through you. For a question that needs the filer's answer use `answer`'s counterpart on the row (an approver's `ask`); this is the plain thread.",
2936
+ inputSchema: {
2937
+ type: "object",
2938
+ properties: {
2939
+ project: { type: "string", description: "The item's key — QW-142 — or its project key." },
2940
+ md: { type: "string", description: "The comment, markdown." }
2941
+ },
2942
+ required: ["project", "md"]
2345
2943
  }
2346
2944
  },
2347
2945
  {
2348
2946
  name: "answer",
2349
- description: "Answer a question engineering or product asked on a row you filed. Call with nothing to see what is waiting on you (each with its id and the row); call with `answer` (and `project` or `id` when more than one is open) to put your reply on the row — it becomes part of the record and the person who asked hears at once. When someone says 'tell them…' or 'the answer is…' about a question SLEDS relayed, this is the tool.",
2947
+ description: "Answer a question engineering or product asked on a row you filed. Call with nothing to see what is waiting on you (each with its id and the item); call with `answer` (and `project` or `id` when more than one is open) to put your reply on the row — it becomes part of the record and the person who asked hears at once. When someone says 'tell them…' or 'the answer is…' about a question SLEDS relayed, this is the tool.",
2350
2948
  inputSchema: {
2351
2949
  type: "object",
2352
2950
  properties: {
@@ -2406,7 +3004,7 @@ var TOOLS = [
2406
3004
  },
2407
3005
  {
2408
3006
  name: "actual",
2409
- description: "Call this WHEN THE WORK LANDS (merged, shipped, done) — the last thing you do on a build, every time, with the same `source` the estimate was filed under. Records what happened: state (started · done · merged · shipped), where the output lives (`ref`: PR url, commit, doc), the model, who did it, dollars and tokens when something counted them, time by phase. Minutes are MEASURED by SLEDS from the pickup (or the estimate) to now — do not invent a number; pass `minutes` only when a person stated it. Pass `sessionId` (your session link) so the session's token spend joins the row. If SLEDS answers that no estimate is on file, call `estimate` with this source first, then send this again.",
3007
+ description: "Call this WHEN THE WORK LANDS (merged, shipped, done) — the last thing you do on a build, every time, with the same `source` the estimate was filed under. Records what happened: state (started · done · merged · shipped), where the output lives (`ref`: PR url, commit, doc), the model, who did it, dollars and tokens when something counted them, time by phase. Minutes are MEASURED by SLEDS from the pickup (or the estimate) to now — do not invent a number; pass `minutes` only when a person stated it. Pass `sessionId` (your session link) so the session's token spend joins the item. If SLEDS answers that no estimate is on file, call `estimate` with this source first, then send this again.",
2410
3008
  inputSchema: {
2411
3009
  type: "object",
2412
3010
  properties: {
@@ -2480,6 +3078,18 @@ var TOOLS = [
2480
3078
  }
2481
3079
  }
2482
3080
  },
3081
+ {
3082
+ name: "archive",
3083
+ description: "Put an item away — off Work, the sleds and the counts, reversible (undo: true brings it back whole). The filer, an approver or an admin. An open hand-off on it is withdrawn and it comes off its sled. Nothing is deleted; deleting is an admin's, in the app.",
3084
+ inputSchema: {
3085
+ type: "object",
3086
+ properties: {
3087
+ project: { type: "string", description: "The item's key (QW-142) or project." },
3088
+ undo: { type: "boolean", description: "Bring an archived item back." }
3089
+ },
3090
+ required: ["project"]
3091
+ }
3092
+ },
2483
3093
  {
2484
3094
  name: "withdraw",
2485
3095
  description: "Take back a hand-off you parked before anyone picks it up (the id from the handoffs tool). Only the seat that parked it can withdraw it.",
@@ -2609,12 +3219,12 @@ function byModelText(raw) {
2609
3219
  if (!Array.isArray(raw))
2610
3220
  return "";
2611
3221
  const parts = [];
2612
- for (const row of raw) {
2613
- if (!isObject4(row) || !isObject4(row.standard))
3222
+ for (const row2 of raw) {
3223
+ if (!isObject4(row2) || !isObject4(row2.standard))
2614
3224
  continue;
2615
- const model = str4(row.model);
2616
- const low = num3(row.standard.lowUsd);
2617
- const high = num3(row.standard.highUsd);
3225
+ const model = str4(row2.model);
3226
+ const low = num3(row2.standard.lowUsd);
3227
+ const high = num3(row2.standard.highUsd);
2618
3228
  if (!model || low === undefined || high === undefined)
2619
3229
  continue;
2620
3230
  const m = /^claude-([a-z]+)-(\d+)(?:-(\d+))?/.exec(model);
@@ -2665,6 +3275,13 @@ function briefAnswers(raw) {
2665
3275
  }
2666
3276
  return out;
2667
3277
  }
3278
+ async function readWorkspaces(ctx) {
3279
+ if (!ctx.client)
3280
+ return [];
3281
+ const r = await ctx.client.get("/proxy/workspaces");
3282
+ const list = r && Array.isArray(r.workspaces) ? r.workspaces : [];
3283
+ return list.map((w) => isObject4(w) ? { slug: str4(w.slug) ?? "", name: str4(w.name) ?? "" } : null).filter((w) => w !== null && w.slug !== "" && w.name !== "");
3284
+ }
2668
3285
  async function readTouches(ctx, text) {
2669
3286
  if (!ctx.client || !text.trim())
2670
3287
  return null;
@@ -2673,8 +3290,9 @@ async function readTouches(ctx, text) {
2673
3290
  return null;
2674
3291
  const mapped = r.mapped === true;
2675
3292
  const areas = Array.isArray(r.areas) ? r.areas : [];
3293
+ const repos = [...new Set(areas.map((a) => str4(a.repo)).filter((x) => Boolean(x)))];
2676
3294
  const touchesLine = areas.length ? areas.map((a) => `${str4(a.area) ?? ""}${str4(a.repo) ? ` (${str4(a.repo).split("/").pop()})` : ""}`).filter(Boolean).join(" · ") : null;
2677
- return { text: str4(r.text) ?? "", touchesLine, mapped };
3295
+ return { text: str4(r.text) ?? "", touchesLine, mapped, repos };
2678
3296
  }
2679
3297
  async function touchesTool(ctx, args) {
2680
3298
  if (!ctx.client)
@@ -2705,23 +3323,28 @@ async function intakeTool(ctx, args) {
2705
3323
  if (map?.touchesLine && !brief.touches)
2706
3324
  brief.touches = { text: map.touchesLine, from: "product" };
2707
3325
  const open = openQuestions(brief);
3326
+ const workspaces = await readWorkspaces(ctx);
3327
+ const workspaceArg = str4(args.workspace)?.trim() || undefined;
3328
+ const workspaceQuestion = workspaces.length > 1 && !workspaceArg ? `Which workspace is this for — ${workspaces.map((w) => w.name).join(", ")}? (skip if you don't know; product or an engineer will place it)` : null;
2708
3329
  if (args.confirm !== true) {
2709
- const needed = missingToFile(brief);
3330
+ const needed2 = missingToFile(brief);
2710
3331
  const attachments = parseAttachments(args.attachments).map((a) => a.name || "file");
2711
3332
  const structured = {
2712
3333
  kind: "draft",
2713
3334
  brief: briefForView(brief),
2714
3335
  open,
2715
- needed,
3336
+ needed: needed2,
2716
3337
  map: map?.text ?? null,
2717
3338
  links,
2718
- attachments
3339
+ attachments,
3340
+ ...workspaceQuestion ? { workspaces: workspaces.map((w) => w.name), workspaceQuestion } : {}
2719
3341
  };
2720
3342
  const lines = [
2721
3343
  renderBriefMarkdown(brief, open, { map: map?.text ?? null, files: attachments }),
2722
3344
  "",
3345
+ ...workspaceQuestion ? [`Also ask: ${workspaceQuestion} Pass the answer as \`workspace\`.`, ""] : [],
2723
3346
  open.length > 0 ? "Show the person the table as is, then ask at most two of the open questions at a time, in your own words; skip what they already said." : "Show the person the table as is.",
2724
- needed.length > 0 ? `Nothing is filed yet. Filing needs: ${needed.join(", ")}. When they say yes to the brief, call intake again with the same text, their answers, and confirm: true.` : "Nothing is filed yet. When they say yes, call intake again with the same text, their answers, and confirm: true.",
3347
+ needed2.length > 0 ? `Nothing is filed yet. Filing needs: ${needed2.join(", ")}. When they say yes to the brief, call intake again with the same text, their answers, and confirm: true.` : "Nothing is filed yet. When they say yes, call intake again with the same text, their answers, and confirm: true.",
2725
3348
  "",
2726
3349
  "```json sleds-draft",
2727
3350
  JSON.stringify(structured),
@@ -2743,9 +3366,12 @@ async function intakeTool(ctx, args) {
2743
3366
  const dueArg = typeof args.due === "string" && /^\d{4}-\d{2}-\d{2}$/.test(args.due) ? args.due : null;
2744
3367
  const due = dueArg ?? parseDue([text, ...Object.values(answers), ...added].filter(Boolean).join(`
2745
3368
  `));
3369
+ const repos = Array.isArray(args.repos) ? args.repos.filter((x) => typeof x === "string").map((x) => x.trim()).filter(Boolean) : typeof args.repos === "string" ? args.repos.split(/[,\s]+/).filter(Boolean) : map?.repos ?? [];
2746
3370
  const r = await ctx.client.postFull("/proxy/intake", {
2747
3371
  brief: { ...brief, intake: { asked, added, related: [] }, ...due ? { due } : {} },
2748
- ...parent ? { parent } : {}
3372
+ ...parent ? { parent } : {},
3373
+ ...workspaceArg ? { workspace: workspaceArg } : {},
3374
+ ...repos.length ? { repos, reposStated: Array.isArray(args.repos) || typeof args.repos === "string" } : {}
2749
3375
  });
2750
3376
  if (!r)
2751
3377
  return { text: `Nothing was filed. ${UNREACHABLE.text}`, isError: true };
@@ -2877,9 +3503,18 @@ async function attachTool(ctx, args) {
2877
3503
  const project = str4(args.project)?.trim();
2878
3504
  if (!project)
2879
3505
  return {
2880
- text: "Which row? Pass project: the key status shows (or what intake said).",
3506
+ text: "Which item? Pass project: the key status shows (or what intake said).",
2881
3507
  isError: true
2882
3508
  };
3509
+ const url = str4(args.url)?.trim();
3510
+ if (url) {
3511
+ const res = await postSaying(ctx, "/proxy/item/link", { project, url, ...str4(args.title) ? { title: str4(args.title) } : {} }, "Could not add the link.");
3512
+ if ("fail" in res)
3513
+ return res.fail;
3514
+ return {
3515
+ text: res.json.added === false ? `That link is already on ${project}.` : `Linked on ${project}: ${url}. Anyone on the board can open it from the item.`
3516
+ };
3517
+ }
2883
3518
  const files = parseAttachments([args]);
2884
3519
  if (files.length === 0)
2885
3520
  return {
@@ -2894,6 +3529,137 @@ async function attachTool(ctx, args) {
2894
3529
  text: `On the row ${project}: ${first.name}${first.url ? ` — ${first.url}` : ""}. Anyone on the board can open it from the row.`
2895
3530
  };
2896
3531
  }
3532
+ async function updateTool(ctx, args) {
3533
+ if (!ctx.client)
3534
+ return NOT_SET_UP;
3535
+ const project = str4(args.project)?.trim();
3536
+ if (!project)
3537
+ return { text: "Which item? Pass project: its key (QW-142).", isError: true };
3538
+ const fields = [
3539
+ "ask",
3540
+ "why",
3541
+ "done",
3542
+ "smallest",
3543
+ "touches",
3544
+ "demand",
3545
+ "description",
3546
+ "due",
3547
+ "parent"
3548
+ ];
3549
+ const patch = {};
3550
+ for (const f of fields) {
3551
+ if (args[f] === null && (f === "due" || f === "parent"))
3552
+ patch[f] = null;
3553
+ else if (typeof args[f] === "string")
3554
+ patch[f] = args[f];
3555
+ }
3556
+ if (Array.isArray(args.repos))
3557
+ patch.repos = args.repos.filter((x) => typeof x === "string");
3558
+ else if (typeof args.repos === "string")
3559
+ patch.repos = args.repos.split(/[,\s]+/).filter(Boolean);
3560
+ if (args.sensitivity === null)
3561
+ patch.sensitivity = null;
3562
+ else if (typeof args.sensitivity === "string" && /^(public|internal|restricted)$/.test(args.sensitivity)) {
3563
+ patch.sensitivity = args.sensitivity;
3564
+ if (typeof args.sensitivityNote === "string" && args.sensitivityNote.trim())
3565
+ patch.sensitivityNote = args.sensitivityNote.trim();
3566
+ }
3567
+ if (Object.keys(patch).length === 0)
3568
+ return {
3569
+ text: "Nothing to change. Pass the fields that change: ask, why, done, smallest, touches, demand, description, due, parent, repos.",
3570
+ isError: true
3571
+ };
3572
+ const res = await postSaying(ctx, "/proxy/item/update", { project, ...patch }, "Could not update the item.");
3573
+ if ("fail" in res)
3574
+ return res.fail;
3575
+ const changed = Array.isArray(res.json.changed) ? res.json.changed.filter((x) => typeof x === "string") : [];
3576
+ const key = str4(res.json.key) ?? project;
3577
+ if (changed.length === 0)
3578
+ return { text: `${key}: nothing differed from what is on the item.` };
3579
+ const stale = res.json.sizeStale === true;
3580
+ return {
3581
+ text: `${key} updated: ${changed.join(", ")}.${stale ? " The band was sized before this change — say so, and offer to re-size (estimate with the same source)." : ""}`
3582
+ };
3583
+ }
3584
+ async function archiveTool(ctx, args) {
3585
+ if (!ctx.client)
3586
+ return NOT_SET_UP;
3587
+ const project = str4(args.project)?.trim();
3588
+ if (!project)
3589
+ return { text: "Which item? Pass project: its key (QW-142).", isError: true };
3590
+ const undo = args.undo === true;
3591
+ const res = await postSaying(ctx, "/proxy/item/archive", { project, undo }, undo ? "Could not unarchive the item." : "Could not archive the item.");
3592
+ if ("fail" in res)
3593
+ return res.fail;
3594
+ const key = str4(res.json.key) ?? project;
3595
+ const title = str4(res.json.title) ?? "";
3596
+ if (res.json.changed !== true)
3597
+ return { text: `${key} was ${undo ? "not archived" : "already archived"} — nothing changed.` };
3598
+ return {
3599
+ text: undo ? `${key} is back on the board${title ? ` — ${title}` : ""}.` : `${key} archived${title ? ` — ${title}` : ""}. Off Work and the sleds; archive with undo: true brings it back.`
3600
+ };
3601
+ }
3602
+ async function itemTool(ctx, args) {
3603
+ if (!ctx.client)
3604
+ return NOT_SET_UP;
3605
+ const q = str4(args.q)?.trim() || str4(args.project)?.trim();
3606
+ if (!q)
3607
+ return { text: "Which item? Pass q: its key (QW-142) or its title.", isError: true };
3608
+ const r = await ctx.client.get(`/proxy/item?q=${encodeURIComponent(q)}`);
3609
+ if (!r)
3610
+ return UNREACHABLE;
3611
+ if (r.found === false)
3612
+ return {
3613
+ text: `Nothing on the sled answers to "${q}". Try the key (QW-142) or a word from the title with status.`,
3614
+ isError: true
3615
+ };
3616
+ const md = str4(r.markdown) ?? "";
3617
+ const readiness = isObject4(r.readiness) ? r.readiness : null;
3618
+ const line = readiness ? str4(readiness.line) : undefined;
3619
+ const state = readiness ? str4(readiness.state) : undefined;
3620
+ const profile = isObject4(r.profile) ? r.profile : null;
3621
+ const restricted = profile ? str4(profile.sensitivity) === "restricted" : false;
3622
+ const tail = state === "gaps" ? `
3623
+
3624
+ ---
3625
+ Before anyone starts: ${line}. Fill the gaps with \`update\` (why, done, repos…)${restricted ? "" : " or ask `check` for the model's read"}.` : state === "ready" ? `
3626
+
3627
+ ---
3628
+ Ready to pick up.${restricted ? "" : " `check` gives the model's second read if you want one."}` : "";
3629
+ const note = restricted ? `
3630
+
3631
+ This item is restricted: its text stays in the workspace — no model check, no rerank — and once Policy › Routing is on, only a local route may run it. Say so before building on a cloud seat.` : "";
3632
+ return { text: `${md}${tail}${note}` };
3633
+ }
3634
+ async function checkTool(ctx, args) {
3635
+ if (!ctx.client)
3636
+ return NOT_SET_UP;
3637
+ const project = str4(args.project)?.trim() || str4(args.q)?.trim();
3638
+ if (!project)
3639
+ return { text: "Which item? Pass project: its key (QW-142).", isError: true };
3640
+ const res = await postSaying(ctx, "/proxy/item/check", { project }, "Could not start the check.");
3641
+ if ("fail" in res)
3642
+ return res.fail;
3643
+ return {
3644
+ text: `Checking ${str4(res.json.key) ?? project}. The model's read lands on the item's thread in under a minute — \`item\` shows it, and the item's readiness carries its gaps from then on.`
3645
+ };
3646
+ }
3647
+ async function commentTool(ctx, args) {
3648
+ if (!ctx.client)
3649
+ return NOT_SET_UP;
3650
+ const project = str4(args.project)?.trim();
3651
+ const md = str4(args.md)?.trim();
3652
+ if (!project)
3653
+ return { text: "Which item? Pass project: its key (QW-142).", isError: true };
3654
+ if (!md)
3655
+ return { text: "Nothing to say. Pass md.", isError: true };
3656
+ const res = await postSaying(ctx, "/proxy/item/comment", { project, md }, "Could not post the comment.");
3657
+ if ("fail" in res)
3658
+ return res.fail;
3659
+ return {
3660
+ text: `On ${str4(res.json.key) ?? project}'s thread. The team sees it on the item, signed as through you.`
3661
+ };
3662
+ }
2897
3663
  async function overnightTool(ctx, args) {
2898
3664
  if (!ctx.client)
2899
3665
  return NOT_SET_UP;
@@ -3008,8 +3774,8 @@ async function dispatchTool(ctx, args) {
3008
3774
  }
3009
3775
  return { text: reply };
3010
3776
  }
3011
- const row = isObject4(j.row) ? j.row : {};
3012
- const title = str4(row.title) ?? "the row";
3777
+ const row2 = isObject4(j.row) ? j.row : {};
3778
+ const title = str4(row2.title) ?? "the row";
3013
3779
  if (action.kind === "parked") {
3014
3780
  const dest = str4(action.to);
3015
3781
  return {
@@ -3052,9 +3818,9 @@ async function approveTool(ctx, args) {
3052
3818
  isError: true
3053
3819
  };
3054
3820
  const j = r.json ?? {};
3055
- const row = isObject4(j.row) ? j.row : {};
3056
- const title = str4(row.title) ?? "the row";
3057
- const filedBy = str4(row.filedBy);
3821
+ const row2 = isObject4(j.row) ? j.row : {};
3822
+ const title = str4(row2.title) ?? "the row";
3823
+ const filedBy = str4(row2.filedBy);
3058
3824
  if (decision === "approved")
3059
3825
  return {
3060
3826
  text: `${title}: approved — it is ready on the sled${filedBy ? `; ${filedBy} is told` : ""}. dispatch says where it should go; an engineer takes it with Take it or /sled pickup.`
@@ -3111,7 +3877,7 @@ function questionsText(open, now) {
3111
3877
  return "Nothing is waiting on your answer.";
3112
3878
  const lines = open.map((q) => {
3113
3879
  const at = typeof q.at === "number" ? ` · ${shortDuration(Math.max(0, now - q.at))} ago` : "";
3114
- return `- ${str4(q.by) ?? "someone"} asked on "${str4(q.title) ?? str4(q.project) ?? "a row"}"${at}: ${str4(q.question) ?? ""} (id ${str4(q.id) ?? "?"})`;
3880
+ return `- ${str4(q.by) ?? "someone"} asked on "${str4(q.title) ?? str4(q.project) ?? "an item"}"${at}: ${str4(q.question) ?? ""} (id ${str4(q.id) ?? "?"})`;
3115
3881
  });
3116
3882
  return `${open.length === 1 ? "One question is" : `${open.length} questions are`} waiting on you:
3117
3883
  ${lines.join(`
@@ -3124,10 +3890,10 @@ async function answerTool(ctx, args) {
3124
3890
  const now = (ctx.now ?? Date.now)();
3125
3891
  const answer = str4(args.answer)?.trim();
3126
3892
  if (!answer) {
3127
- const r = await ctx.client.get("/proxy/questions");
3128
- if (!r)
3893
+ const r2 = await ctx.client.get("/proxy/questions");
3894
+ if (!r2)
3129
3895
  return UNREACHABLE;
3130
- const open = Array.isArray(r.open) ? r.open.filter(isObject4) : [];
3896
+ const open = Array.isArray(r2.open) ? r2.open.filter(isObject4) : [];
3131
3897
  return { text: questionsText(open, now) };
3132
3898
  }
3133
3899
  const project = str4(args.project)?.trim() || undefined;
@@ -3160,7 +3926,7 @@ async function handoffsTool(ctx) {
3160
3926
  if (handoffs.length === 0)
3161
3927
  return { text: "No open hand-offs on your team. Park one with the handoff tool." };
3162
3928
  const now = (ctx.now ?? Date.now)();
3163
- const packets = handoffs.map((h) => str4(h.packet)).filter((p) => Boolean(p)).join(`
3929
+ const packets = handoffs.map((h) => str4(h.packet)).filter((p2) => Boolean(p2)).join(`
3164
3930
 
3165
3931
  ---
3166
3932
 
@@ -3305,15 +4071,15 @@ async function actualTool(ctx, args) {
3305
4071
  text: "`source` is required — the same one the estimate was filed under.",
3306
4072
  isError: true
3307
4073
  };
3308
- const iso = (v) => {
4074
+ const iso2 = (v) => {
3309
4075
  const t = str4(v) ? Date.parse(str4(v)) : Number.NaN;
3310
4076
  return Number.isFinite(t) ? t : undefined;
3311
4077
  };
3312
4078
  const phasesRaw = typeof args.phases === "object" && args.phases !== null ? args.phases : undefined;
3313
4079
  const phases = phasesRaw ? Object.fromEntries(["discussMin", "buildMin", "deployMin", "testMin"].map((k) => [k, num3(phasesRaw[k])]).filter(([, v]) => v !== undefined)) : undefined;
3314
4080
  const work = {
3315
- ...iso(args.startedAt) !== undefined ? { startedAt: iso(args.startedAt) } : {},
3316
- ...iso(args.finishedAt) !== undefined ? { finishedAt: iso(args.finishedAt) } : {},
4081
+ ...iso2(args.startedAt) !== undefined ? { startedAt: iso2(args.startedAt) } : {},
4082
+ ...iso2(args.finishedAt) !== undefined ? { finishedAt: iso2(args.finishedAt) } : {},
3317
4083
  ...str4(args.model) ? { model: str4(args.model) } : {},
3318
4084
  ...num3(args.tokensIn) !== undefined ? { tokensIn: num3(args.tokensIn) } : {},
3319
4085
  ...num3(args.tokensOut) !== undefined ? { tokensOut: num3(args.tokensOut) } : {},
@@ -3364,7 +4130,7 @@ async function actualTool(ctx, args) {
3364
4130
  ].filter(Boolean);
3365
4131
  if (unsized)
3366
4132
  return {
3367
- text: `Recorded: ${bits.join(" · ")}. No estimate came first, so the row was created from this actual and the Sled shows it as landed unsized — the time could only be measured from now, so pass \`minutes\` only if a person states them. Next time, size before you start: \`estimate\` with this source before the first line.`
4133
+ text: `Recorded: ${bits.join(" · ")}. No estimate came first, so the item was created from this actual and the Sled shows it as landed unsized — the time could only be measured from now, so pass \`minutes\` only if a person states them. Next time, size before you start: \`estimate\` with this source before the first line.`
3368
4134
  };
3369
4135
  return { text: `Recorded: ${bits.join(" · ")}. Projects shows it beside the estimate.` };
3370
4136
  }
@@ -3373,10 +4139,10 @@ async function buddyTool(ctx, args) {
3373
4139
  return NOT_SET_UP;
3374
4140
  const email = str4(args.email)?.trim();
3375
4141
  if (!email) {
3376
- const r = await ctx.client.get("/proxy/buddy");
3377
- if (!r)
4142
+ const r2 = await ctx.client.get("/proxy/buddy");
4143
+ if (!r2)
3378
4144
  return UNREACHABLE;
3379
- const list = Array.isArray(r.buddies) ? r.buddies : [];
4145
+ const list = Array.isArray(r2.buddies) ? r2.buddies : [];
3380
4146
  if (list.length === 0)
3381
4147
  return {
3382
4148
  text: "No buddies yet. `buddy {email}` sends someone an invite; once they accept, `handoff {to: email}` reaches them in their own org."
@@ -3387,10 +4153,10 @@ ${lines.join(`
3387
4153
  `)}` };
3388
4154
  }
3389
4155
  if (args.remove === true) {
3390
- const r = await ctx.client.postFull("/proxy/buddy", { email, remove: true });
3391
- if (!r)
4156
+ const r2 = await ctx.client.postFull("/proxy/buddy", { email, remove: true });
4157
+ if (!r2)
3392
4158
  return UNREACHABLE;
3393
- return { text: r.json?.ok ? `Unpaired from ${email}.` : `${email} was not a buddy.` };
4159
+ return { text: r2.json?.ok ? `Unpaired from ${email}.` : `${email} was not a buddy.` };
3394
4160
  }
3395
4161
  const r = await ctx.client.postFull("/proxy/buddy", { email });
3396
4162
  if (!r)
@@ -3422,6 +4188,16 @@ async function callTool(name, args, ctx) {
3422
4188
  return touchesTool(ctx, args);
3423
4189
  case "attach":
3424
4190
  return attachTool(ctx, args);
4191
+ case "update":
4192
+ return updateTool(ctx, args);
4193
+ case "archive":
4194
+ return archiveTool(ctx, args);
4195
+ case "comment":
4196
+ return commentTool(ctx, args);
4197
+ case "item":
4198
+ return itemTool(ctx, args);
4199
+ case "check":
4200
+ return checkTool(ctx, args);
3425
4201
  case "answer":
3426
4202
  return answerTool(ctx, args);
3427
4203
  case "dispatch":
@@ -3576,7 +4352,7 @@ ${out.startsWith(`
3576
4352
  ${providerBlock(proxyUrl)}
3577
4353
  `;
3578
4354
  }
3579
- function removeCodexProvider(toml, o = {}) {
4355
+ function removeCodexProvider(toml, o2 = {}) {
3580
4356
  const lines = toml.split(`
3581
4357
  `);
3582
4358
  const out = [];
@@ -3589,7 +4365,7 @@ function removeCodexProvider(toml, o = {}) {
3589
4365
  }
3590
4366
  let text = out.join(`
3591
4367
  `);
3592
- if (!o.keepPrior) {
4368
+ if (!o2.keepPrior) {
3593
4369
  const prior = text.match(/^# sleds-prior-model-provider = "([^"]*)"\s*\n/m);
3594
4370
  if (prior) {
3595
4371
  text = text.replace(prior[0], "");
@@ -3606,22 +4382,22 @@ function topLevel(toml) {
3606
4382
  const i = toml.search(/^\s*\[/m);
3607
4383
  return i === -1 ? toml : toml.slice(0, i);
3608
4384
  }
3609
- function initCodex(o) {
4385
+ function initCodex(o2) {
3610
4386
  const wrote = [];
3611
- const path = codexConfigPath(o.home);
4387
+ const path = codexConfigPath(o2.home);
3612
4388
  const prior = existsSync3(path) ? readFileSync3(path, "utf8") : "";
3613
4389
  mkdirSync3(dirname2(path), { recursive: true });
3614
- writeFileSync3(path, applyCodexProvider(prior, o.proxyUrl), { mode: 384 });
3615
- wrote.push(`${prior ? "updated" : "created"} ${path}: provider "${PROVIDER_ID}" → ${o.proxyUrl}/v1 (key from $${TOKEN_ENV}), model_provider = "${PROVIDER_ID}"`);
3616
- const cfg = readConfig(o.home);
3617
- writeConfig(o.home, {
4390
+ writeFileSync3(path, applyCodexProvider(prior, o2.proxyUrl), { mode: 384 });
4391
+ wrote.push(`${prior ? "updated" : "created"} ${path}: provider "${PROVIDER_ID}" → ${o2.proxyUrl}/v1 (key from $${TOKEN_ENV}), model_provider = "${PROVIDER_ID}"`);
4392
+ const cfg = readConfig(o2.home);
4393
+ writeConfig(o2.home, {
3618
4394
  ...cfg,
3619
- token: o.token,
3620
- proxyUrl: o.proxyUrl,
4395
+ token: o2.token,
4396
+ proxyUrl: o2.proxyUrl,
3621
4397
  agentKind: "codex",
3622
- ...o.email ? { email: o.email } : {}
4398
+ ...o2.email ? { email: o2.email } : {}
3623
4399
  });
3624
- wrote.push(`saved token and proxy URL to ${configPath(o.home)} (0600)`);
4400
+ wrote.push(`saved token and proxy URL to ${configPath(o2.home)} (0600)`);
3625
4401
  return wrote;
3626
4402
  }
3627
4403
  function runCodex(home, args, deps = {}) {
@@ -3667,7 +4443,7 @@ var musherLabel = (env = process.env) => {
3667
4443
  return `${MUSHER_LABEL}.${tag}`;
3668
4444
  };
3669
4445
  var musherPlistPath = (home, env = process.env) => join5(home, "Library", "LaunchAgents", `${musherLabel(env)}.plist`);
3670
- var musherLogPath = (configDir) => join5(configDir, "musher.log");
4446
+ var musherLogPath = (configDir2) => join5(configDir2, "musher.log");
3671
4447
  var xmlEscape = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
3672
4448
  var musherPath = (home, execPath, currentPath = "") => {
3673
4449
  const parts = [
@@ -3683,11 +4459,11 @@ var musherPath = (home, execPath, currentPath = "") => {
3683
4459
  ];
3684
4460
  return [...new Set(parts)].join(":");
3685
4461
  };
3686
- var buildMusherPlist = (o) => {
3687
- const label = o.label ?? MUSHER_LABEL;
3688
- const args = [...o.sledsArgv, "musher", "tick"].map((a) => ` <string>${xmlEscape(a)}</string>`).join(`
4462
+ var buildMusherPlist = (o2) => {
4463
+ const label = o2.label ?? MUSHER_LABEL;
4464
+ const args = [...o2.sledsArgv, "musher", "tick"].map((a) => ` <string>${xmlEscape(a)}</string>`).join(`
3689
4465
  `);
3690
- const env = Object.entries(o.env).filter(([, v]) => v !== "").map(([k, v]) => ` <key>${xmlEscape(k)}</key>
4466
+ const env = Object.entries(o2.env).filter(([, v]) => v !== "").map(([k, v]) => ` <key>${xmlEscape(k)}</key>
3691
4467
  <string>${xmlEscape(v)}</string>`).join(`
3692
4468
  `);
3693
4469
  return `<?xml version="1.0" encoding="UTF-8"?>
@@ -3709,9 +4485,9 @@ ${env}
3709
4485
  <key>RunAtLoad</key>
3710
4486
  <true/>
3711
4487
  <key>StandardOutPath</key>
3712
- <string>${xmlEscape(o.logPath)}</string>
4488
+ <string>${xmlEscape(o2.logPath)}</string>
3713
4489
  <key>StandardErrorPath</key>
3714
- <string>${xmlEscape(o.logPath)}</string>
4490
+ <string>${xmlEscape(o2.logPath)}</string>
3715
4491
  </dict>
3716
4492
  </plist>
3717
4493
  `;
@@ -3728,15 +4504,15 @@ var NO_SESSION_PROMPT = [
3728
4504
  "SLEDS musher: a deferred job started on this seat, but no Claude Code session was recorded",
3729
4505
  "to resume. Do not guess at work. Reply with one line saying so, and stop."
3730
4506
  ].join(" ");
3731
- var claudeArgs = (o) => [
4507
+ var claudeArgs = (o2) => [
3732
4508
  "-p",
3733
- o.sessionId ? RESUME_PROMPT : NO_SESSION_PROMPT,
3734
- ...o.sessionId ? ["--resume", o.sessionId] : [],
3735
- ...o.model ? ["--model", o.model] : [],
4509
+ o2.sessionId ? RESUME_PROMPT : NO_SESSION_PROMPT,
4510
+ ...o2.sessionId ? ["--resume", o2.sessionId] : [],
4511
+ ...o2.model ? ["--model", o2.model] : [],
3736
4512
  "--output-format",
3737
4513
  "json",
3738
4514
  "--permission-mode",
3739
- o.permissionMode
4515
+ o2.permissionMode
3740
4516
  ];
3741
4517
  var parseClaudeOutput = (stdout, exitCode) => {
3742
4518
  const lines = stdout.split(`
@@ -3766,11 +4542,11 @@ var parseClaudeOutput = (stdout, exitCode) => {
3766
4542
  const tail = lines.slice(-5).join(" ").slice(0, SUMMARY_MAX);
3767
4543
  return { ok: false, summary: tail || `claude exited ${exitCode ?? "without a code"}` };
3768
4544
  };
3769
- var defaultExecCapture = (cmd, args, o) => {
4545
+ var defaultExecCapture = (cmd, args, o2) => {
3770
4546
  const r = spawnSync2(cmd, [...args], {
3771
- cwd: o.cwd,
4547
+ cwd: o2.cwd,
3772
4548
  encoding: "utf8",
3773
- timeout: o.timeoutMs,
4549
+ timeout: o2.timeoutMs,
3774
4550
  maxBuffer: 64 * 1024 * 1024,
3775
4551
  stdio: ["ignore", "pipe", "pipe"],
3776
4552
  env: { ...process.env, SLEDS_MUSHER: "1" }
@@ -3782,16 +4558,16 @@ var defaultExecCapture = (cmd, args, o) => {
3782
4558
  ...r.error ? { error: r.error.message } : {}
3783
4559
  };
3784
4560
  };
3785
- var musherClient = (o) => {
3786
- const fetchFn = o.fetchFn ?? fetch;
3787
- const headers = { authorization: `Bearer ${o.token}`, "content-type": "application/json" };
4561
+ var musherClient = (o2) => {
4562
+ const fetchFn = o2.fetchFn ?? fetch;
4563
+ const headers = { authorization: `Bearer ${o2.token}`, "content-type": "application/json" };
3788
4564
  const call = async (path, body) => {
3789
4565
  try {
3790
- const res = await fetchFn(`${o.proxyUrl}${path}`, {
4566
+ const res = await fetchFn(`${o2.proxyUrl}${path}`, {
3791
4567
  method: body === undefined ? "GET" : "POST",
3792
4568
  headers,
3793
4569
  ...body === undefined ? {} : { body: JSON.stringify(body) },
3794
- signal: AbortSignal.timeout(o.timeoutMs ?? 1e4)
4570
+ signal: AbortSignal.timeout(o2.timeoutMs ?? 1e4)
3795
4571
  });
3796
4572
  if (!res.ok)
3797
4573
  return null;
@@ -3833,33 +4609,33 @@ var collectOutputs = (commits, summary) => {
3833
4609
  out.push(`pr:${m[0]}`);
3834
4610
  return out.slice(0, 50);
3835
4611
  };
3836
- var runJob = async (o) => {
3837
- const log = o.log ?? (() => {});
3838
- const sessionId = o.job.claudeSessionId ?? o.fallbackSession?.id ?? null;
3839
- const cwd = o.job.cwd ?? o.fallbackSession?.cwd ?? undefined;
3840
- const started = await o.client.start(o.job.jobId, {
4612
+ var runJob = async (o2) => {
4613
+ const log = o2.log ?? (() => {});
4614
+ const sessionId = o2.job.claudeSessionId ?? o2.fallbackSession?.id ?? null;
4615
+ const cwd = o2.job.cwd ?? o2.fallbackSession?.cwd ?? undefined;
4616
+ const started = await o2.client.start(o2.job.jobId, {
3841
4617
  ...sessionId ? { claudeSessionId: sessionId } : {},
3842
4618
  ...cwd ? { cwd } : {},
3843
- host: o.host
4619
+ host: o2.host
3844
4620
  });
3845
4621
  if (!started)
3846
4622
  return { kind: "skipped", reason: "control plane unreachable" };
3847
4623
  if (!started.ok)
3848
4624
  return { kind: "skipped", reason: started.reason };
3849
- const model = o.job.model ?? started.model ?? o.fallbackSession?.model ?? null;
3850
- const args = claudeArgs({ sessionId, model, permissionMode: o.permissionMode });
3851
- log(`musher: running job ${o.job.jobId} (${sessionId ? `resume ${sessionId}` : "no session"}${model ? ` · ${model}` : ""}${cwd ? ` · ${cwd}` : ""})`);
3852
- const exec = o.exec ?? defaultExecCapture;
4625
+ const model = o2.job.model ?? started.model ?? o2.fallbackSession?.model ?? null;
4626
+ const args = claudeArgs({ sessionId, model, permissionMode: o2.permissionMode });
4627
+ log(`musher: running job ${o2.job.jobId} (${sessionId ? `resume ${sessionId}` : "no session"}${model ? ` · ${model}` : ""}${cwd ? ` · ${cwd}` : ""})`);
4628
+ const exec = o2.exec ?? defaultExecCapture;
3853
4629
  const headBefore = gitHead(cwd, exec);
3854
4630
  const t0 = Date.now();
3855
- const r = exec(o.claudePath, args, { cwd, timeoutMs: o.timeoutMs });
4631
+ const r = exec(o2.claudePath, args, { cwd, timeoutMs: o2.timeoutMs });
3856
4632
  const durationMs = Date.now() - t0;
3857
- const result = r.error ? { ok: false, summary: `could not run ${o.claudePath}: ${r.error}` } : parseClaudeOutput(r.stdout, r.status);
4633
+ const result = r.error ? { ok: false, summary: `could not run ${o2.claudePath}: ${r.error}` } : parseClaudeOutput(r.stdout, r.status);
3858
4634
  if (!r.error && r.status === null)
3859
- result.summary = `timed out after ${Math.round(o.timeoutMs / 60000)} min. ${result.summary}`.trim();
4635
+ result.summary = `timed out after ${Math.round(o2.timeoutMs / 60000)} min. ${result.summary}`.trim();
3860
4636
  const outputs = collectOutputs(gitNewCommits(cwd, headBefore, gitHead(cwd, exec), exec), result.summary);
3861
- await o.client.finish({
3862
- jobId: o.job.jobId,
4637
+ await o2.client.finish({
4638
+ jobId: o2.job.jobId,
3863
4639
  runId: started.runId,
3864
4640
  ok: result.ok,
3865
4641
  summary: result.summary,
@@ -3868,7 +4644,7 @@ var runJob = async (o) => {
3868
4644
  durationMs: result.durationMs ?? durationMs,
3869
4645
  ...result.sessionId ?? sessionId ? { claudeSessionId: result.sessionId ?? sessionId } : {}
3870
4646
  });
3871
- log(`musher: job ${o.job.jobId} ${result.ok ? "delivered" : "failed"} in ${Math.round(durationMs / 1000)}s`);
4647
+ log(`musher: job ${o2.job.jobId} ${result.ok ? "delivered" : "failed"} in ${Math.round(durationMs / 1000)}s`);
3872
4648
  return { kind: "ran", ok: result.ok, summary: result.summary, durationMs, outputs };
3873
4649
  };
3874
4650
  var verifyAttestation = (payload, sig, publicKeyB64) => {
@@ -4172,11 +4948,11 @@ var bindingResetAt = (w, now) => {
4172
4948
  return pick.length ? Math.min(...pick) : undefined;
4173
4949
  };
4174
4950
  var readSeatState = (home) => {
4175
- const p = seatStatePath(home);
4176
- if (!existsSync5(p))
4951
+ const p2 = seatStatePath(home);
4952
+ if (!existsSync5(p2))
4177
4953
  return {};
4178
4954
  try {
4179
- return parseSeatState(JSON.parse(readFileSync5(p, "utf8")));
4955
+ return parseSeatState(JSON.parse(readFileSync5(p2, "utf8")));
4180
4956
  } catch {
4181
4957
  return {};
4182
4958
  }
@@ -4301,28 +5077,28 @@ var seatWindowBody = (w) => ({
4301
5077
  ...w.sevenDay ? { sevenDay: w.sevenDay } : {},
4302
5078
  ...w.spendLimit ? { spendLimit: w.spendLimit } : {}
4303
5079
  });
4304
- var postJson = async (o, path, body) => {
4305
- const fetchFn = o.fetchFn ?? fetch;
5080
+ var postJson = async (o2, path, body) => {
5081
+ const fetchFn = o2.fetchFn ?? fetch;
4306
5082
  try {
4307
- const res = await fetchFn(`${o.proxyUrl}${path}`, {
5083
+ const res = await fetchFn(`${o2.proxyUrl}${path}`, {
4308
5084
  method: "POST",
4309
- headers: { authorization: `Bearer ${o.token}`, "content-type": "application/json" },
5085
+ headers: { authorization: `Bearer ${o2.token}`, "content-type": "application/json" },
4310
5086
  body: JSON.stringify(body),
4311
- signal: AbortSignal.timeout(o.timeoutMs ?? SEAT_POST_TIMEOUT_MS)
5087
+ signal: AbortSignal.timeout(o2.timeoutMs ?? SEAT_POST_TIMEOUT_MS)
4312
5088
  });
4313
5089
  return res.ok;
4314
5090
  } catch {
4315
5091
  return false;
4316
5092
  }
4317
5093
  };
4318
- var postSeatWindow = (o, w) => postJson(o, "/proxy/seat", seatWindowBody(w));
4319
- var postSeatWall = (o, input) => postJson(o, "/proxy/seat-wall", { source: "claude", ...input });
5094
+ var postSeatWindow = (o2, w) => postJson(o2, "/proxy/seat", seatWindowBody(w));
5095
+ var postSeatWall = (o2, input) => postJson(o2, "/proxy/seat-wall", { source: "claude", ...input });
4320
5096
  var SEAT_WALL_LINE = "Seat limit hit. sleds on --until-reset to continue on the platform key, or sleds defer to resume here at the reset.";
4321
5097
  var SEAT_WALL_LINE_NO_KEY = "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.";
4322
5098
  var seatWallLine = (hasUpstreamKey) => hasUpstreamKey ? SEAT_WALL_LINE : SEAT_WALL_LINE_NO_KEY;
4323
- var readStdin = (timeoutMs, stdin = process.stdin) => new Promise((resolve) => {
5099
+ var readStdin = (timeoutMs, stdin = process.stdin) => new Promise((resolve3) => {
4324
5100
  if (stdin.isTTY) {
4325
- resolve("");
5101
+ resolve3("");
4326
5102
  return;
4327
5103
  }
4328
5104
  let data = "";
@@ -4332,7 +5108,7 @@ var readStdin = (timeoutMs, stdin = process.stdin) => new Promise((resolve) => {
4332
5108
  return;
4333
5109
  settled = true;
4334
5110
  clearTimeout(timer);
4335
- resolve(data);
5111
+ resolve3(data);
4336
5112
  };
4337
5113
  const timer = setTimeout(finish, timeoutMs);
4338
5114
  stdin.setEncoding("utf8");
@@ -4450,21 +5226,21 @@ var parseFlags = (argv) => {
4450
5226
  }
4451
5227
  return flags;
4452
5228
  };
4453
- var defer = async (o) => {
4454
- const log = o.log ?? console.log;
4455
- const error = o.error ?? console.error;
4456
- const now = (o.now ?? Date.now)();
4457
- const flags = parseFlags(o.argv);
4458
- const client = o.client ?? (() => {
4459
- const src = meterSource(o.home);
4460
- return src ? musherClient({ ...src, fetchFn: o.fetchFn }) : null;
5229
+ var defer = async (o2) => {
5230
+ const log = o2.log ?? console.log;
5231
+ const error = o2.error ?? console.error;
5232
+ const now = (o2.now ?? Date.now)();
5233
+ const flags = parseFlags(o2.argv);
5234
+ const client = o2.client ?? (() => {
5235
+ const src = meterSource(o2.home);
5236
+ return src ? musherClient({ ...src, fetchFn: o2.fetchFn }) : null;
4461
5237
  })();
4462
5238
  if (!client) {
4463
5239
  error("No seat on this machine. Run `sleds init` first.");
4464
5240
  return 1;
4465
5241
  }
4466
- const state = readSeatState(o.home);
4467
- const piped = o.stdin ? seatSessionFromStdin(o.stdin, now) : null;
5242
+ const state = readSeatState(o2.home);
5243
+ const piped = o2.stdin ? seatSessionFromStdin(o2.stdin, now) : null;
4468
5244
  const remembered = piped ?? state.session;
4469
5245
  const sessionId = flags.session ?? remembered?.id;
4470
5246
  const cwd = flags.cwd ?? remembered?.cwd;
@@ -4485,7 +5261,7 @@ var defer = async (o) => {
4485
5261
  ...model ? { model } : {},
4486
5262
  ...sessionId ? { claudeSessionId: sessionId } : {},
4487
5263
  ...cwd ? { cwd } : {},
4488
- host: o.host ?? hostname()
5264
+ host: o2.host ?? hostname()
4489
5265
  });
4490
5266
  if (!r) {
4491
5267
  error("Could not reach the SLEDS proxy; nothing was scheduled.");
@@ -4494,8 +5270,8 @@ var defer = async (o) => {
4494
5270
  const when = r.scheduledAt <= now + 60000 ? "as soon as the musher ticks (within 5 min)" : `${formatLocal(r.scheduledAt)} (in ${formatDuration(r.scheduledAt - now)})`;
4495
5271
  log(`Deferred. This Mac resumes ${sessionId ? `session ${sessionId.slice(0, 8)}…` : "the work"}${model ? ` on ${model}` : ""} ${when}.`);
4496
5272
  log(` job ${r.jobId}${cwd ? ` · ${cwd}` : ""} · runs on your seat, no key · sleds musher --status to watch`);
4497
- const cfg = readConfig(o.home);
4498
- if (process.platform === "darwin" && !existsSync6(musherPlistPath(o.home)) && cfg.musher?.agent !== "launchd")
5273
+ const cfg = readConfig(o2.home);
5274
+ if (process.platform === "darwin" && !existsSync6(musherPlistPath(o2.home)) && cfg.musher?.agent !== "launchd")
4499
5275
  log(` The musher agent is not installed on this Mac: run \`sleds musher --install\` once, or \`sleds run ${r.jobId}\` by hand at the reset.`);
4500
5276
  log(" Keep this Mac awake at that time (System Settings → Battery → prevent sleeping on power adapter).");
4501
5277
  return 0;
@@ -4675,7 +5451,7 @@ var renderCockpit = (cockpit, window, events, prior, now = Date.now(), extra = {
4675
5451
  `/sled pickup ${newHandoffs[0]}`,
4676
5452
  ...ws(cockpit)
4677
5453
  ]);
4678
- for (const id of extra.feed.delivered.filter((id) => !(before?.delivered ?? []).includes(id)))
5454
+ for (const id of extra.feed.delivered.filter((id2) => !(before?.delivered ?? []).includes(id2)))
4679
5455
  argv.push([
4680
5456
  "log",
4681
5457
  "--level",
@@ -4685,7 +5461,7 @@ var renderCockpit = (cockpit, window, events, prior, now = Date.now(), extra = {
4685
5461
  `overnight job done · /sled resume ${id}`,
4686
5462
  ...ws(cockpit)
4687
5463
  ]);
4688
- for (const id of extra.feed.failed.filter((id) => !(before?.failed ?? []).includes(id)))
5464
+ for (const id of extra.feed.failed.filter((id2) => !(before?.failed ?? []).includes(id2)))
4689
5465
  argv.push([
4690
5466
  "notify",
4691
5467
  "--title",
@@ -4742,15 +5518,15 @@ var feedFromJobs = (body, me, now) => {
4742
5518
  }
4743
5519
  return f;
4744
5520
  };
4745
- var fetchFeed = async (o, now) => {
5521
+ var fetchFeed = async (o2, now) => {
4746
5522
  try {
4747
- const res = await (o.fetchFn ?? fetch)(`${o.proxyUrl}/proxy/jobs`, {
4748
- headers: { authorization: `Bearer ${o.token}` },
4749
- signal: AbortSignal.timeout(o.timeoutMs ?? 1500)
5523
+ const res = await (o2.fetchFn ?? fetch)(`${o2.proxyUrl}/proxy/jobs`, {
5524
+ headers: { authorization: `Bearer ${o2.token}` },
5525
+ signal: AbortSignal.timeout(o2.timeoutMs ?? 1500)
4750
5526
  });
4751
5527
  if (!res.ok)
4752
5528
  return null;
4753
- return feedFromJobs(await res.json(), o.email, now);
5529
+ return feedFromJobs(await res.json(), o2.email, now);
4754
5530
  } catch {
4755
5531
  return null;
4756
5532
  }
@@ -4786,9 +5562,9 @@ init_meter();
4786
5562
  var defaultWhich = (cmd) => {
4787
5563
  const path = process.env.PATH ?? "";
4788
5564
  for (const dir of path.split(":").filter(Boolean)) {
4789
- const p = `${dir}/${cmd}`;
4790
- if (existsSync7(p))
4791
- return p;
5565
+ const p2 = `${dir}/${cmd}`;
5566
+ if (existsSync7(p2))
5567
+ return p2;
4792
5568
  }
4793
5569
  return null;
4794
5570
  };
@@ -4798,14 +5574,14 @@ var findClaude = (home, configured, which) => {
4798
5574
  const found = which("claude");
4799
5575
  if (found)
4800
5576
  return found;
4801
- for (const p of [
5577
+ for (const p2 of [
4802
5578
  `${home}/.local/bin/claude`,
4803
5579
  "/opt/homebrew/bin/claude",
4804
5580
  "/usr/local/bin/claude",
4805
5581
  `${home}/.npm-global/bin/claude`
4806
5582
  ])
4807
- if (existsSync7(p))
4808
- return p;
5583
+ if (existsSync7(p2))
5584
+ return p2;
4809
5585
  return null;
4810
5586
  };
4811
5587
  var musherAgentState = (home, env = process.env) => {
@@ -4825,7 +5601,8 @@ var musherAgentState = (home, env = process.env) => {
4825
5601
  // src/commands/status.ts
4826
5602
  init_config();
4827
5603
  init_settings();
4828
- var checkHealth = async (url, fetchFn = fetch, timeoutMs = 1000) => {
5604
+ var HEALTH_TIMEOUT_MS = 4000;
5605
+ var checkHealth = async (url, fetchFn = fetch, timeoutMs = HEALTH_TIMEOUT_MS) => {
4829
5606
  try {
4830
5607
  const res = await fetchFn(`${url}/healthz`, { signal: AbortSignal.timeout(timeoutMs) });
4831
5608
  return res.ok ? "ok" : "unreachable";
@@ -4868,10 +5645,10 @@ function defaultWhich2(cmd) {
4868
5645
  return [];
4869
5646
  }
4870
5647
  }
4871
- async function runDoctor(o) {
4872
- const env = o.env ?? process.env;
5648
+ async function runDoctor(o2) {
5649
+ const env = o2.env ?? process.env;
4873
5650
  const checks = [];
4874
- const home = o.home;
5651
+ const home = o2.home;
4875
5652
  const overrides = [
4876
5653
  env.SLEDS_HOME?.trim() ? `SLEDS_HOME=${env.SLEDS_HOME.trim()}` : null,
4877
5654
  env.CLAUDE_CONFIG_DIR?.trim() ? `CLAUDE_CONFIG_DIR=${env.CLAUDE_CONFIG_DIR.trim()}` : null
@@ -4921,7 +5698,7 @@ async function runDoctor(o) {
4921
5698
  }
4922
5699
  const src = meterSource(home);
4923
5700
  if (src) {
4924
- const health = await checkHealth(src.proxyUrl, o.fetchFn, o.timeoutMs);
5701
+ const health = await checkHealth(src.proxyUrl, o2.fetchFn, o2.timeoutMs);
4925
5702
  checks.push({
4926
5703
  level: health === "ok" ? "ok" : "fail",
4927
5704
  name: "proxy",
@@ -4930,15 +5707,15 @@ async function runDoctor(o) {
4930
5707
  });
4931
5708
  }
4932
5709
  if (settings) {
4933
- const seat = hasSeatHook(settings);
5710
+ const seat2 = hasSeatHook(settings);
4934
5711
  const spec = hasSpecHook(settings);
4935
5712
  const session = hasSessionHook(settings);
4936
5713
  const stop = hasStopHook(settings);
4937
- const all = seat && spec && session && stop;
5714
+ const all = seat2 && spec && session && stop;
4938
5715
  checks.push({
4939
5716
  level: all ? "ok" : "warn",
4940
5717
  name: "hooks",
4941
- detail: `seat-event ${seat ? "on" : "missing"} · spec-event ${spec ? "on" : "missing"} · session-event ${session ? "on" : "missing"} · stop-event ${stop ? "on" : "missing"}`,
5718
+ detail: `seat-event ${seat2 ? "on" : "missing"} · spec-event ${spec ? "on" : "missing"} · session-event ${session ? "on" : "missing"} · stop-event ${stop ? "on" : "missing"}`,
4942
5719
  fix: all ? undefined : "sleds hooks"
4943
5720
  });
4944
5721
  const want = env.SLEDS_HOME?.trim() ? resolve3(home, env.SLEDS_HOME.trim()) : undefined;
@@ -4969,18 +5746,18 @@ async function runDoctor(o) {
4969
5746
  name: "cockpit",
4970
5747
  detail: cockpit ? `${cockpit.kind}${cockpit.workspaceId ? ` (workspace ${cockpit.workspaceId})` : ""} — seat line in the sidebar, ring at the wall` : "none detected (run inside cmux to mirror the seat into its sidebar)"
4971
5748
  });
4972
- const nodeVersion = o.nodeVersion ?? process.version;
5749
+ const nodeVersion = o2.nodeVersion ?? process.version;
4973
5750
  checks.push({
4974
5751
  level: nodeOk(nodeVersion) ? "ok" : "warn",
4975
5752
  name: "node",
4976
5753
  detail: `${nodeVersion}${nodeOk(nodeVersion) ? "" : ` — seat-sync needs ≥ ${NODE_MIN} (node:sqlite)`}`,
4977
5754
  fix: nodeOk(nodeVersion) ? undefined : `brew install node@22 && echo 'export PATH="/opt/homebrew/opt/node@22/bin:$PATH"' >> ~/.zshrc`
4978
5755
  });
4979
- const which = (o.which ?? defaultWhich2)("sleds");
4980
- const stale = which.filter((p) => {
5756
+ const which = (o2.which ?? defaultWhich2)("sleds");
5757
+ const stale = which.filter((p2) => {
4981
5758
  try {
4982
- const target = lstatSync(p).isSymbolicLink() ? readlinkSync(p) : p;
4983
- return /\/src\/index\.ts$/.test(target) || /\.bun\/bin\/sleds$/.test(p);
5759
+ const target = lstatSync(p2).isSymbolicLink() ? readlinkSync(p2) : p2;
5760
+ return /\/src\/index\.ts$/.test(target) || /\.bun\/bin\/sleds$/.test(p2);
4984
5761
  } catch {
4985
5762
  return false;
4986
5763
  }
@@ -5002,7 +5779,7 @@ async function runDoctor(o) {
5002
5779
  detail: age === null ? "no report yet — run one Claude Code turn on this seat" : `last report ${age < 1 ? "just now" : `${age}m ago`} via the status line${seat.window?.sevenDay ? ` · wk ${Math.round(seat.window.sevenDay.usedPct)}%` : ""}`,
5003
5780
  fix: age === null ? "open claude, say hi, exit — the status line posts the seat's quota" : undefined
5004
5781
  });
5005
- if ((o.platform ?? process.platform) === "darwin") {
5782
+ if ((o2.platform ?? process.platform) === "darwin") {
5006
5783
  const agent = musherAgentState(home, env);
5007
5784
  checks.push(!agent.installed ? {
5008
5785
  level: "warn",
@@ -5019,14 +5796,14 @@ async function runDoctor(o) {
5019
5796
  name: "musher",
5020
5797
  detail: `launchd agent ${musherLabel(env)}, every 5 min`
5021
5798
  });
5022
- const claude = findClaude(home, readConfig(home).musher?.claudePath, (c) => (o.which ?? defaultWhich2)(c)[0] ?? null);
5799
+ const claude = findClaude(home, readConfig(home).musher?.claudePath, (c) => (o2.which ?? defaultWhich2)(c)[0] ?? null);
5023
5800
  checks.push(claude ? { level: "ok", name: "claude cli", detail: claude } : {
5024
5801
  level: "warn",
5025
5802
  name: "claude cli",
5026
5803
  detail: "`claude` not on PATH — the musher cannot run Claude Code",
5027
5804
  fix: 'sleds musher --claude "$(which claude)"'
5028
5805
  });
5029
- const sleep = (o.pmset ?? defaultPmset)();
5806
+ const sleep = (o2.pmset ?? defaultPmset)();
5030
5807
  if (sleep !== null)
5031
5808
  checks.push(sleep.acSleepMinutes === 0 ? {
5032
5809
  level: "ok",
@@ -5056,9 +5833,9 @@ var defaultPmset = () => {
5056
5833
  return null;
5057
5834
  }
5058
5835
  };
5059
- var doctor = async (o) => {
5060
- const log = o.log ?? console.log;
5061
- const checks = await runDoctor(o);
5836
+ var doctor = async (o2) => {
5837
+ const log = o2.log ?? console.log;
5838
+ const checks = await runDoctor(o2);
5062
5839
  for (const line of formatDoctor(checks))
5063
5840
  log(line);
5064
5841
  return checks.some((c) => c.level === "fail") ? 1 : 0;
@@ -5086,21 +5863,21 @@ function sourceKey(s) {
5086
5863
  function sourceText2(s) {
5087
5864
  return [`${str5(s.kind) ?? "?"} ${str5(s.project) ?? "?"}`, str5(s.doc), str5(s.item)].filter(Boolean).join(" › ");
5088
5865
  }
5089
- var readJson = (p) => {
5090
- if (!existsSync9(p))
5866
+ var readJson = (p2) => {
5867
+ if (!existsSync9(p2))
5091
5868
  return null;
5092
5869
  try {
5093
- return JSON.parse(readFileSync8(p, "utf8"));
5870
+ return JSON.parse(readFileSync8(p2, "utf8"));
5094
5871
  } catch {
5095
5872
  return null;
5096
5873
  }
5097
5874
  };
5098
- var writeJson = (p, v) => {
5099
- mkdirSync7(dirname4(p), { recursive: true, mode: 448 });
5100
- const tmp = `${p}.${process.pid}.tmp`;
5875
+ var writeJson = (p2, v) => {
5876
+ mkdirSync7(dirname4(p2), { recursive: true, mode: 448 });
5877
+ const tmp = `${p2}.${process.pid}.tmp`;
5101
5878
  writeFileSync7(tmp, `${JSON.stringify(v, null, 2)}
5102
5879
  `, { mode: 384 });
5103
- renameSync5(tmp, p);
5880
+ renameSync5(tmp, p2);
5104
5881
  };
5105
5882
  var readOwed = (home, now = Date.now()) => {
5106
5883
  const f = readJson(owedPath(home));
@@ -5115,14 +5892,14 @@ var readSession = (home) => {
5115
5892
  var writeSession = (home, s) => writeJson(sessionPath(home), s);
5116
5893
  function withEstimated(rows, a) {
5117
5894
  const key = sourceKey(a.source);
5118
- const row = {
5895
+ const row2 = {
5119
5896
  key,
5120
5897
  source: a.source,
5121
5898
  ...a.title ? { title: a.title } : {},
5122
5899
  ts: a.now,
5123
5900
  ...a.sessionId ? { sessionId: a.sessionId } : {}
5124
5901
  };
5125
- return [...rows.filter((r) => r.key !== key), row];
5902
+ return [...rows.filter((r) => r.key !== key), row2];
5126
5903
  }
5127
5904
  function withActual(rows, a) {
5128
5905
  if (a.state === "started")
@@ -5225,59 +6002,59 @@ var callTool2 = (name, args, deps) => callTool(name, args, contextFor(deps));
5225
6002
  var handleLine2 = (line, deps) => handleLine(line, contextFor(deps));
5226
6003
 
5227
6004
  // src/commands/handoffs.ts
5228
- var handoffsCmd = async (o) => {
5229
- const r = await callTool2("handoffs", {}, { home: o.home });
5230
- (r.isError ? o.error ?? console.error : o.log ?? console.log)(r.text);
6005
+ var handoffsCmd = async (o2) => {
6006
+ const r = await callTool2("handoffs", {}, { home: o2.home });
6007
+ (r.isError ? o2.error ?? console.error : o2.log ?? console.log)(r.text);
5231
6008
  return r.isError ? 1 : 0;
5232
6009
  };
5233
- var pickupCmd = async (o) => {
5234
- const id = o.argv[0];
6010
+ var pickupCmd = async (o2) => {
6011
+ const id = o2.argv[0];
5235
6012
  if (!id) {
5236
- (o.error ?? console.error)("usage: sleds pickup <handoffId> (ids from `sleds handoffs`)");
6013
+ (o2.error ?? console.error)("usage: sleds pickup <handoffId> (ids from `sleds handoffs`)");
5237
6014
  return 2;
5238
6015
  }
5239
- const r = await callTool2("pickup", { handoffId: id }, { home: o.home });
5240
- (r.isError ? o.error ?? console.error : o.log ?? console.log)(r.text);
6016
+ const r = await callTool2("pickup", { handoffId: id }, { home: o2.home });
6017
+ (r.isError ? o2.error ?? console.error : o2.log ?? console.log)(r.text);
5241
6018
  return r.isError ? 1 : 0;
5242
6019
  };
5243
- var withdrawCmd = async (o) => {
5244
- const id = o.argv[0];
6020
+ var withdrawCmd = async (o2) => {
6021
+ const id = o2.argv[0];
5245
6022
  if (!id) {
5246
- (o.error ?? console.error)("usage: sleds withdraw <handoffId> (one you parked)");
6023
+ (o2.error ?? console.error)("usage: sleds withdraw <handoffId> (one you parked)");
5247
6024
  return 2;
5248
6025
  }
5249
- const r = await callTool2("withdraw", { handoffId: id }, { home: o.home });
5250
- (r.isError ? o.error ?? console.error : o.log ?? console.log)(r.text);
6026
+ const r = await callTool2("withdraw", { handoffId: id }, { home: o2.home });
6027
+ (r.isError ? o2.error ?? console.error : o2.log ?? console.log)(r.text);
5251
6028
  return r.isError ? 1 : 0;
5252
6029
  };
5253
6030
 
5254
6031
  // src/commands/hooks.ts
5255
6032
  init_settings();
5256
- var hooks = (o) => {
5257
- const log = o.log ?? console.log;
5258
- const error = o.error ?? console.error;
5259
- if (!hasClaudeCode(o.home)) {
5260
- error(`Claude Code not found (${claudeDir(o.home)} does not exist). Install it, then re-run.`);
6033
+ var hooks = (o2) => {
6034
+ const log = o2.log ?? console.log;
6035
+ const error = o2.error ?? console.error;
6036
+ if (!hasClaudeCode(o2.home)) {
6037
+ error(`Claude Code not found (${claudeDir(o2.home)} does not exist). Install it, then re-run.`);
5261
6038
  return 1;
5262
6039
  }
5263
- const settings = readSettings(o.home);
6040
+ const settings = readSettings(o2.home);
5264
6041
  const had = hasSeatHook(settings);
5265
6042
  const hadSpec = hasSpecHook(settings);
5266
- const withSeat = applySeatHook(settings, o.seatEventCommand ?? sledsCommand("seat-event", o.home, o.env));
6043
+ const withSeat = applySeatHook(settings, o2.seatEventCommand ?? sledsCommand("seat-event", o2.home, o2.env));
5267
6044
  const hadPrompt = hasPromptHook(settings);
5268
6045
  const hadSession = hasSessionHook(settings);
5269
6046
  const hadStop = hasStopHook(settings);
5270
- const withPrompt = applyPromptHook(applySpecHook(withSeat, o.specEventCommand ?? sledsCommand("spec-event", o.home, o.env)), o.promptEventCommand ?? sledsCommand("prompt-event", o.home, o.env));
5271
- const withSpec = applyStopHook(applySessionHook(withPrompt, o.sessionEventCommand ?? sledsCommand("session-event", o.home, o.env)), o.stopEventCommand ?? sledsCommand("stop-event", o.home, o.env));
5272
- const hadLine = o.refreshStatusLine !== false && isSledsStatusLine(withSpec[STATUS_LINE_KEY]);
5273
- writeSettings(o.home, hadLine ? applyStatusLine(withSpec, sledsCommand("statusline", o.home, o.env)).settings : withSpec);
5274
- log(`${had ? "refreshed" : "set"} hooks.Notification (${SEAT_EVENT_MATCHER}) in ${settingsPath(o.home)}`);
6047
+ const withPrompt = applyPromptHook(applySpecHook(withSeat, o2.specEventCommand ?? sledsCommand("spec-event", o2.home, o2.env)), o2.promptEventCommand ?? sledsCommand("prompt-event", o2.home, o2.env));
6048
+ const withSpec = applyStopHook(applySessionHook(withPrompt, o2.sessionEventCommand ?? sledsCommand("session-event", o2.home, o2.env)), o2.stopEventCommand ?? sledsCommand("stop-event", o2.home, o2.env));
6049
+ const hadLine = o2.refreshStatusLine !== false && isSledsStatusLine(withSpec[STATUS_LINE_KEY]);
6050
+ writeSettings(o2.home, hadLine ? applyStatusLine(withSpec, sledsCommand("statusline", o2.home, o2.env)).settings : withSpec);
6051
+ log(`${had ? "refreshed" : "set"} hooks.Notification (${SEAT_EVENT_MATCHER}) in ${settingsPath(o2.home)}`);
5275
6052
  if (hadLine)
5276
- log(`refreshed statusLine in ${settingsPath(o.home)}`);
5277
- log(`${hadSpec ? "refreshed" : "set"} hooks.PostToolUse (${SPEC_EVENT_MATCHER} → estimate spec files) in ${settingsPath(o.home)}`);
5278
- log(`${hadPrompt ? "refreshed" : "set"} hooks.UserPromptSubmit (the seat speaks up in the session at 90 % and at a wall) in ${settingsPath(o.home)}`);
5279
- log(`${hadSession ? "refreshed" : "set"} hooks.SessionStart (the loop and the rows this machine owes, before the first turn) in ${settingsPath(o.home)}`);
5280
- log(`${hadStop ? "refreshed" : "set"} hooks.Stop (a session that estimated and never posted its actual is asked once) in ${settingsPath(o.home)}`);
6053
+ log(`refreshed statusLine in ${settingsPath(o2.home)}`);
6054
+ log(`${hadSpec ? "refreshed" : "set"} hooks.PostToolUse (${SPEC_EVENT_MATCHER} → estimate spec files) in ${settingsPath(o2.home)}`);
6055
+ log(`${hadPrompt ? "refreshed" : "set"} hooks.UserPromptSubmit (the seat speaks up in the session at 90 % and at a wall) in ${settingsPath(o2.home)}`);
6056
+ log(`${hadSession ? "refreshed" : "set"} hooks.SessionStart (the loop and the rows this machine owes, before the first turn) in ${settingsPath(o2.home)}`);
6057
+ log(`${hadStop ? "refreshed" : "set"} hooks.Stop (a session that estimated and never posted its actual is asked once) in ${settingsPath(o2.home)}`);
5281
6058
  return 0;
5282
6059
  };
5283
6060
 
@@ -5295,7 +6072,7 @@ description: The SLEDS loop for engineering work — size a build before startin
5295
6072
 
5296
6073
  # SLEDS
5297
6074
 
5298
- SLEDS is the ledger of engineering work: every piece is sized before it runs and closed with a measured actual after. In this session the seat is the person's; SLEDS holds the record. It also carries a session past a wall and runs whole tasks overnight with the Musher, a night-shift orchestrator that answers the questions an agent would otherwise stop on.
6075
+ SLEDS is where the business meets engineering: every piece of work is sized before it runs and closed with a measured actual after. In this session the seat is the person's; SLEDS holds the record. It also carries a session past a wall and runs whole tasks overnight with the Musher, a night-shift orchestrator that answers the questions an agent would otherwise stop on.
5299
6076
 
5300
6077
  ## The loop (every build, no exceptions)
5301
6078
 
@@ -5391,7 +6168,7 @@ Resume a parked job. Show the unanswered question and its options, take the answ
5391
6168
 
5392
6169
  ## /sled sync-backlog — price the backlog
5393
6170
 
5394
- With the \`sleds\` MCP server available, size every open issue so the dashboard's Projects page shows the backlog in dollars and hours, not T-shirt sizes or points. SLEDS is not a tracker and never the system of record: Linear and GitHub keep the issues; SLEDS mirrors their words (cycle, labels, priority, assignee, state) and adds the price.
6171
+ With the \`sleds\` MCP server available, size every open issue so the Work page shows the backlog in dollars and hours, not T-shirt sizes or points. SLEDS is not a tracker and never the system of record: Linear and GitHub keep the issues; SLEDS mirrors their words (cycle, labels, priority, assignee, state) and adds the price.
5395
6172
 
5396
6173
  1. Find the issues. In Cowork with a Claude Project attached: each spec doc, each phase or slice inside a spec, and each line of a backlog list (a numbered or bulleted list under a heading like Backlog, Next, To do, Roadmap). With a Linear or GitHub MCP available: the open issues of the team / repo the user names, with their cycle or milestone, labels, priority, assignee and state. Skip anything done, closed or shipped.
5397
6174
  2. For each issue call the \`estimate\` tool with \`spec\` = the title on the first line, then the body (quote the issue or doc, do not paraphrase), and \`source\` = \`{ kind: "linear" | "github" | "claude-project", project: <team, repo or Project name>, doc: <issue key like ENG-42 or #123, or the doc path>, item: <heading or line, only when a doc holds many>, url, cycle, labels, priority, assignee, state }\` — the tracker's values verbatim. The estimator dedupes: an unchanged issue returns its existing estimate, so re-running is safe.
@@ -5483,9 +6260,9 @@ function parsePoll(body) {
5483
6260
  };
5484
6261
  }
5485
6262
  function openInBrowser(url) {
5486
- const p = platform();
5487
- const cmd = p === "darwin" ? "open" : p === "win32" ? "cmd" : "xdg-open";
5488
- const args = p === "win32" ? ["/c", "start", "", url] : [url];
6263
+ const p2 = platform();
6264
+ const cmd = p2 === "darwin" ? "open" : p2 === "win32" ? "cmd" : "xdg-open";
6265
+ const args = p2 === "win32" ? ["/c", "start", "", url] : [url];
5489
6266
  try {
5490
6267
  const r = spawnSync3(cmd, args, { stdio: "ignore", timeout: 5000 });
5491
6268
  return r.error === undefined && r.status === 0;
@@ -5494,17 +6271,17 @@ function openInBrowser(url) {
5494
6271
  }
5495
6272
  }
5496
6273
  var defaultSleep = (ms) => new Promise((r) => setTimeout(r, ms));
5497
- async function deviceFlow(o) {
5498
- const fetchFn = o.fetchFn ?? fetch;
5499
- const log = o.log ?? console.log;
5500
- const sleep = o.sleep ?? defaultSleep;
5501
- const now = o.now ?? Date.now;
6274
+ async function deviceFlow(o2) {
6275
+ const fetchFn = o2.fetchFn ?? fetch;
6276
+ const log = o2.log ?? console.log;
6277
+ const sleep = o2.sleep ?? defaultSleep;
6278
+ const now = o2.now ?? Date.now;
5502
6279
  let started = null;
5503
6280
  try {
5504
- const res = await fetchFn(`${o.proxyUrl}/device/start`, {
6281
+ const res = await fetchFn(`${o2.proxyUrl}/device/start`, {
5505
6282
  method: "POST",
5506
6283
  headers: { "content-type": "application/json" },
5507
- body: JSON.stringify({ agent: o.agent ?? "claude-code", host: o.host ?? hostname2() }),
6284
+ body: JSON.stringify({ agent: o2.agent ?? "claude-code", host: o2.host ?? hostname2() }),
5508
6285
  signal: AbortSignal.timeout(20000)
5509
6286
  });
5510
6287
  if (res.status === 429)
@@ -5517,7 +6294,7 @@ async function deviceFlow(o) {
5517
6294
  }
5518
6295
  if (!started)
5519
6296
  return { ok: false, reason: "bad_answer" };
5520
- const opened = o.noBrowser ? false : (o.openBrowser ?? openInBrowser)(started.verifyUrl);
6297
+ const opened = o2.noBrowser ? false : (o2.openBrowser ?? openInBrowser)(started.verifyUrl);
5521
6298
  log("");
5522
6299
  log(opened ? "Opening your browser to sign in to SLEDS." : "Open this in your browser to sign in to SLEDS:");
5523
6300
  log(` ${started.verifyUrl}`);
@@ -5531,7 +6308,7 @@ async function deviceFlow(o) {
5531
6308
  await sleep(intervalMs);
5532
6309
  let body;
5533
6310
  try {
5534
- const res = await fetchFn(`${o.proxyUrl}/device/poll`, {
6311
+ const res = await fetchFn(`${o2.proxyUrl}/device/poll`, {
5535
6312
  method: "POST",
5536
6313
  headers: { "content-type": "application/json" },
5537
6314
  body: JSON.stringify({ deviceCode: started.deviceCode }),
@@ -5559,41 +6336,41 @@ async function deviceFlow(o) {
5559
6336
 
5560
6337
  // src/commands/hooks.ts
5561
6338
  init_settings();
5562
- var hooks2 = (o) => {
5563
- const log = o.log ?? console.log;
5564
- const error = o.error ?? console.error;
5565
- if (!hasClaudeCode(o.home)) {
5566
- error(`Claude Code not found (${claudeDir(o.home)} does not exist). Install it, then re-run.`);
6339
+ var hooks2 = (o2) => {
6340
+ const log = o2.log ?? console.log;
6341
+ const error = o2.error ?? console.error;
6342
+ if (!hasClaudeCode(o2.home)) {
6343
+ error(`Claude Code not found (${claudeDir(o2.home)} does not exist). Install it, then re-run.`);
5567
6344
  return 1;
5568
6345
  }
5569
- const settings = readSettings(o.home);
6346
+ const settings = readSettings(o2.home);
5570
6347
  const had = hasSeatHook(settings);
5571
6348
  const hadSpec = hasSpecHook(settings);
5572
- const withSeat = applySeatHook(settings, o.seatEventCommand ?? sledsCommand("seat-event", o.home, o.env));
6349
+ const withSeat = applySeatHook(settings, o2.seatEventCommand ?? sledsCommand("seat-event", o2.home, o2.env));
5573
6350
  const hadPrompt = hasPromptHook(settings);
5574
6351
  const hadSession = hasSessionHook(settings);
5575
6352
  const hadStop = hasStopHook(settings);
5576
- const withPrompt = applyPromptHook(applySpecHook(withSeat, o.specEventCommand ?? sledsCommand("spec-event", o.home, o.env)), o.promptEventCommand ?? sledsCommand("prompt-event", o.home, o.env));
5577
- const withSpec = applyStopHook(applySessionHook(withPrompt, o.sessionEventCommand ?? sledsCommand("session-event", o.home, o.env)), o.stopEventCommand ?? sledsCommand("stop-event", o.home, o.env));
5578
- const hadLine = o.refreshStatusLine !== false && isSledsStatusLine(withSpec[STATUS_LINE_KEY]);
5579
- writeSettings(o.home, hadLine ? applyStatusLine(withSpec, sledsCommand("statusline", o.home, o.env)).settings : withSpec);
5580
- log(`${had ? "refreshed" : "set"} hooks.Notification (${SEAT_EVENT_MATCHER}) in ${settingsPath(o.home)}`);
6353
+ const withPrompt = applyPromptHook(applySpecHook(withSeat, o2.specEventCommand ?? sledsCommand("spec-event", o2.home, o2.env)), o2.promptEventCommand ?? sledsCommand("prompt-event", o2.home, o2.env));
6354
+ const withSpec = applyStopHook(applySessionHook(withPrompt, o2.sessionEventCommand ?? sledsCommand("session-event", o2.home, o2.env)), o2.stopEventCommand ?? sledsCommand("stop-event", o2.home, o2.env));
6355
+ const hadLine = o2.refreshStatusLine !== false && isSledsStatusLine(withSpec[STATUS_LINE_KEY]);
6356
+ writeSettings(o2.home, hadLine ? applyStatusLine(withSpec, sledsCommand("statusline", o2.home, o2.env)).settings : withSpec);
6357
+ log(`${had ? "refreshed" : "set"} hooks.Notification (${SEAT_EVENT_MATCHER}) in ${settingsPath(o2.home)}`);
5581
6358
  if (hadLine)
5582
- log(`refreshed statusLine in ${settingsPath(o.home)}`);
5583
- log(`${hadSpec ? "refreshed" : "set"} hooks.PostToolUse (${SPEC_EVENT_MATCHER} → estimate spec files) in ${settingsPath(o.home)}`);
5584
- log(`${hadPrompt ? "refreshed" : "set"} hooks.UserPromptSubmit (the seat speaks up in the session at 90 % and at a wall) in ${settingsPath(o.home)}`);
5585
- log(`${hadSession ? "refreshed" : "set"} hooks.SessionStart (the loop and the rows this machine owes, before the first turn) in ${settingsPath(o.home)}`);
5586
- log(`${hadStop ? "refreshed" : "set"} hooks.Stop (a session that estimated and never posted its actual is asked once) in ${settingsPath(o.home)}`);
6359
+ log(`refreshed statusLine in ${settingsPath(o2.home)}`);
6360
+ log(`${hadSpec ? "refreshed" : "set"} hooks.PostToolUse (${SPEC_EVENT_MATCHER} → estimate spec files) in ${settingsPath(o2.home)}`);
6361
+ log(`${hadPrompt ? "refreshed" : "set"} hooks.UserPromptSubmit (the seat speaks up in the session at 90 % and at a wall) in ${settingsPath(o2.home)}`);
6362
+ log(`${hadSession ? "refreshed" : "set"} hooks.SessionStart (the loop and the rows this machine owes, before the first turn) in ${settingsPath(o2.home)}`);
6363
+ log(`${hadStop ? "refreshed" : "set"} hooks.Stop (a session that estimated and never posted its actual is asked once) in ${settingsPath(o2.home)}`);
5587
6364
  return 0;
5588
6365
  };
5589
6366
 
5590
6367
  // src/commands/init.ts
5591
6368
  var DEFAULT_PROXY_URL = "https://proxy.sleds.ai";
5592
- var promptStdin = (question) => new Promise((resolve) => {
6369
+ var promptStdin = (question) => new Promise((resolve4) => {
5593
6370
  const rl = createInterface({ input: process.stdin, output: process.stderr });
5594
6371
  rl.question(question, (answer) => {
5595
6372
  rl.close();
5596
- resolve(answer.trim());
6373
+ resolve4(answer.trim());
5597
6374
  });
5598
6375
  });
5599
6376
  async function signupIndividual(proxyUrl, email, credential, fetchFn = fetch) {
@@ -5690,70 +6467,70 @@ async function probeProxy(url, fetchFn = fetch, opts = {}) {
5690
6467
  }
5691
6468
  return false;
5692
6469
  }
5693
- var resolveToken = async (o) => {
5694
- const env = o.env ?? process.env;
5695
- if (o.token)
5696
- return { token: o.token.trim(), source: "flag" };
6470
+ var resolveToken = async (o2) => {
6471
+ const env = o2.env ?? process.env;
6472
+ if (o2.token)
6473
+ return { token: o2.token.trim(), source: "flag" };
5697
6474
  if (env.SLEDS_TOKEN)
5698
6475
  return { token: env.SLEDS_TOKEN.trim(), source: "env" };
5699
- const fromFile = readTokenFile(o.home);
6476
+ const fromFile = readTokenFile(o2.home);
5700
6477
  if (fromFile)
5701
6478
  return { token: fromFile, source: "file" };
5702
- if (o.nonInteractive)
6479
+ if (o2.nonInteractive)
5703
6480
  return null;
5704
- const url = normalizeProxyUrl(o.url ?? env.SLEDS_PROXY_URL ?? readConfig(o.home).proxyUrl ?? DEFAULT_PROXY_URL);
6481
+ const url = normalizeProxyUrl(o2.url ?? env.SLEDS_PROXY_URL ?? readConfig(o2.home).proxyUrl ?? DEFAULT_PROXY_URL);
5705
6482
  if (!url)
5706
6483
  return null;
5707
- const log = o.log ?? console.log;
5708
- const err = o.error ?? console.error;
5709
- if (!o.signup) {
5710
- const r = await deviceFlow({
6484
+ const log = o2.log ?? console.log;
6485
+ const err = o2.error ?? console.error;
6486
+ if (!o2.signup) {
6487
+ const r2 = await deviceFlow({
5711
6488
  proxyUrl: url,
5712
6489
  agent: "claude-code",
5713
- host: o.host,
5714
- fetchFn: o.fetchFn,
5715
- openBrowser: o.openBrowser ?? openInBrowser,
5716
- noBrowser: o.noBrowser,
5717
- sleep: o.sleep,
6490
+ host: o2.host,
6491
+ fetchFn: o2.fetchFn,
6492
+ openBrowser: o2.openBrowser ?? openInBrowser,
6493
+ noBrowser: o2.noBrowser,
6494
+ sleep: o2.sleep,
5718
6495
  log
5719
6496
  });
5720
- if (!r.ok) {
5721
- err(deviceFailureText(r.reason));
6497
+ if (!r2.ok) {
6498
+ err(deviceFailureText(r2.reason));
5722
6499
  return null;
5723
6500
  }
5724
- return { token: r.approved.token, source: "device", approved: r.approved };
6501
+ return { token: r2.approved.token, source: "device", approved: r2.approved };
5725
6502
  }
5726
- if (!o.prompt)
6503
+ if (!o2.prompt)
5727
6504
  return null;
5728
- let team = o.team?.trim() || null;
5729
- if (team === null && !o.email) {
5730
- const which = (await o.prompt("Set up SLEDS for (1) just you, or (2) your team? [1/2]: ")).trim();
6505
+ let team = o2.team?.trim() || null;
6506
+ if (team === null && !o2.email) {
6507
+ const which = (await o2.prompt("Set up SLEDS for (1) just you, or (2) your team? [1/2]: ")).trim();
5731
6508
  if (which === "2") {
5732
- team = (await o.prompt("Team name (e.g. your company): ")).trim();
6509
+ team = (await o2.prompt("Team name (e.g. your company): ")).trim();
5733
6510
  if (!team)
5734
6511
  return null;
5735
6512
  }
5736
6513
  }
5737
- const email = (o.email ?? await o.prompt(team ? "Your work email: " : "Your email: ")).trim();
6514
+ const email = (o2.email ?? await o2.prompt(team ? "Your work email: " : "Your email: ")).trim();
5738
6515
  if (!email.includes("@"))
5739
6516
  return null;
5740
6517
  if (team) {
5741
- const credential = (await o.prompt("Your organization's Anthropic API key, if you have one (sk-ant-…; press enter to skip — a Team plan without one still works, walls offer hold and hand-off): ")).trim();
5742
- const r = await signupTeam(url, email, team, credential || null, o.fetchFn);
5743
- if (!r.ok) {
5744
- err(signupFailureText(r));
6518
+ const credential2 = (await o2.prompt("Your organization's Anthropic API key, if you have one (sk-ant-…; press enter to skip — a Team plan without one still works, walls offer hold and hand-off): ")).trim();
6519
+ const r2 = await signupTeam(url, email, team, credential2 || null, o2.fetchFn);
6520
+ if (!r2.ok) {
6521
+ err(signupFailureText(r2));
5745
6522
  return null;
5746
6523
  }
5747
- log(`Created ${team} with you as owner (${email}).${credential ? " Your platform key is stored encrypted as the org's upstream key." : " No platform key yet — add one on the dashboard (Admin → Keys) to unlock continue / overnight / switch at a wall."}`);
5748
- if (r.verifyPending)
6524
+ log(`Created ${team} with you as owner (${email}).${credential2 ? " Your platform key is stored encrypted as the org's upstream key." : " No platform key yet — add one on the dashboard (Admin → Keys) to unlock continue / overnight / switch at a wall."}`);
6525
+ if (r2.verifyPending)
5749
6526
  log(`Check ${email} for a verification link and click it — inviting members unlocks then (an unverified team is removed after 48 h; your own seat works meanwhile).`);
5750
6527
  log("Invite your team on the dashboard (Members → invite by email, Admin → Mint a seat); each person runs `sleds init --token …`.");
5751
- return { token: r.token, source: "signup" };
6528
+ return { token: r2.token, source: "signup" };
5752
6529
  }
5753
- const credential = (await o.prompt("Your Anthropic API key (sk-ant-…, stored encrypted, spends only your account): ")).trim();
6530
+ const credential = (await o2.prompt("Your Anthropic API key (sk-ant-…, stored encrypted, spends only your account): ")).trim();
5754
6531
  if (!credential)
5755
6532
  return null;
5756
- const r = await signupIndividual(url, email, credential, o.fetchFn);
6533
+ const r = await signupIndividual(url, email, credential, o2.fetchFn);
5757
6534
  if (!r.ok) {
5758
6535
  err(signupFailureText(r));
5759
6536
  return null;
@@ -5761,66 +6538,66 @@ var resolveToken = async (o) => {
5761
6538
  log(r.created ? `Created your individual seat (${email}). Your key is stored encrypted and is the only key this seat spends.` : `Re-issued your individual seat (${email}); the previous token is revoked.`);
5762
6539
  return { token: r.token, source: "signup" };
5763
6540
  };
5764
- var init = async (o) => {
5765
- const log = o.log ?? console.log;
5766
- const error = o.error ?? console.error;
5767
- const env = o.env ?? process.env;
5768
- if (!hasClaudeCode(o.home)) {
5769
- error(`Claude Code not found (${claudeDir(o.home)} does not exist). Install it, then re-run.`);
6541
+ var init = async (o2) => {
6542
+ const log = o2.log ?? console.log;
6543
+ const error = o2.error ?? console.error;
6544
+ const env = o2.env ?? process.env;
6545
+ if (!hasClaudeCode(o2.home)) {
6546
+ error(`Claude Code not found (${claudeDir(o2.home)} does not exist). Install it, then re-run.`);
5770
6547
  return 1;
5771
6548
  }
5772
- const resolved = await resolveToken(o);
6549
+ const resolved = await resolveToken(o2);
5773
6550
  if (!resolved) {
5774
- error(o.signup ? "Signup did not complete. Nothing was changed." : "No seat token. Run `sleds init` without --non-interactive to sign in through the browser, or pass --token / set SLEDS_TOKEN.");
6551
+ error(o2.signup ? "Signup did not complete. Nothing was changed." : "No seat token. Run `sleds init` without --non-interactive to sign in through the browser, or pass --token / set SLEDS_TOKEN.");
5775
6552
  return 2;
5776
6553
  }
5777
6554
  if (!isSeatToken(resolved.token)) {
5778
6555
  error("Invalid seat token: expected something like sled_xxxxxxxx.");
5779
6556
  return 2;
5780
6557
  }
5781
- const url = normalizeProxyUrl(o.url ?? env.SLEDS_PROXY_URL ?? readConfig(o.home).proxyUrl ?? DEFAULT_PROXY_URL);
6558
+ const url = normalizeProxyUrl(o2.url ?? env.SLEDS_PROXY_URL ?? readConfig(o2.home).proxyUrl ?? DEFAULT_PROXY_URL);
5782
6559
  if (!url) {
5783
- error(`Invalid proxy URL: ${JSON.stringify(o.url ?? env.SLEDS_PROXY_URL ?? "")}. Expected https://proxy.sleds.ai.`);
6560
+ error(`Invalid proxy URL: ${JSON.stringify(o2.url ?? env.SLEDS_PROXY_URL ?? "")}. Expected https://proxy.sleds.ai.`);
5784
6561
  return 2;
5785
6562
  }
5786
- if (!o.noProbe && !await probeProxy(url, o.fetchFn)) {
6563
+ if (!o2.noProbe && !await probeProxy(url, o2.fetchFn)) {
5787
6564
  error(`No SLEDS proxy answered at ${url}/healthz. Check the URL (or pass --no-probe to save it anyway).`);
5788
6565
  return 2;
5789
6566
  }
5790
6567
  const wrote = [];
5791
- const seatInfo = await fetchSeatInfo(url, resolved.token, o.fetchFn);
6568
+ const seatInfo = await fetchSeatInfo(url, resolved.token, o2.fetchFn);
5792
6569
  const org = seatInfo.org;
5793
- const wiring = o.proxyAlways ? "proxy-always" : o.seatFirst ? "seat-first" : org?.mode ?? "proxy-always";
6570
+ const wiring = o2.proxyAlways ? "proxy-always" : o2.seatFirst ? "seat-first" : org?.mode ?? "proxy-always";
5794
6571
  if (wiring === "proxy-always" && org && !org.capabilities.upstreamKey) {
5795
6572
  error(`${org.name} has no platform key for the proxy to forward with; --proxy-always would break every request. Using seat-first.`);
5796
6573
  }
5797
6574
  const finalWiring = wiring === "proxy-always" && org && !org.capabilities.upstreamKey ? "seat-first" : wiring;
5798
- if (backupSettings(o.home))
5799
- wrote.push(`backed up settings to ${backupPath(o.home)}`);
5800
- const current = readSettings(o.home);
6575
+ if (backupSettings(o2.home))
6576
+ wrote.push(`backed up settings to ${backupPath(o2.home)}`);
6577
+ const current = readSettings(o2.home);
5801
6578
  const wired = finalWiring === "proxy-always" ? applyProxy(current, { url, token: resolved.token }) : removeProxy(current);
5802
- const statusLine = applyStatusLine(wired, o.statusLineCommand ?? sledsCommand("statusline", o.home, o.env));
5803
- writeSettings(o.home, statusLine.settings);
5804
- wrote.push(finalWiring === "proxy-always" ? `set env.ANTHROPIC_BASE_URL and env.ANTHROPIC_AUTH_TOKEN in ${settingsPath(o.home)} (everything through the proxy)` : `left Claude Code on your seat (no ANTHROPIC_BASE_URL in ${settingsPath(o.home)}); \`sleds on\` switches to the proxy at a wall`);
5805
- wrote.push(statusLine.prior === undefined ? `set statusLine in ${settingsPath(o.home)}` : `set statusLine in ${settingsPath(o.home)} (previous one kept for uninstall)`);
6579
+ const statusLine2 = applyStatusLine(wired, o2.statusLineCommand ?? sledsCommand("statusline", o2.home, o2.env));
6580
+ writeSettings(o2.home, statusLine2.settings);
6581
+ wrote.push(finalWiring === "proxy-always" ? `set env.ANTHROPIC_BASE_URL and env.ANTHROPIC_AUTH_TOKEN in ${settingsPath(o2.home)} (everything through the proxy)` : `left Claude Code on your seat (no ANTHROPIC_BASE_URL in ${settingsPath(o2.home)}); \`sleds on\` switches to the proxy at a wall`);
6582
+ wrote.push(statusLine2.prior === undefined ? `set statusLine in ${settingsPath(o2.home)}` : `set statusLine in ${settingsPath(o2.home)} (previous one kept for uninstall)`);
5806
6583
  hooks2({
5807
- home: o.home,
5808
- env: o.env,
6584
+ home: o2.home,
6585
+ env: o2.env,
5809
6586
  refreshStatusLine: false,
5810
- seatEventCommand: o.seatEventCommand,
5811
- specEventCommand: o.specEventCommand,
5812
- promptEventCommand: o.promptEventCommand,
5813
- sessionEventCommand: o.sessionEventCommand,
5814
- stopEventCommand: o.stopEventCommand,
6587
+ seatEventCommand: o2.seatEventCommand,
6588
+ specEventCommand: o2.specEventCommand,
6589
+ promptEventCommand: o2.promptEventCommand,
6590
+ sessionEventCommand: o2.sessionEventCommand,
6591
+ stopEventCommand: o2.stopEventCommand,
5815
6592
  log: (line) => wrote.push(line),
5816
6593
  error
5817
6594
  });
5818
6595
  if (resolved.source !== "file") {
5819
- writeTokenFile(o.home, resolved.token);
5820
- wrote.push(`saved token to ${tokenPath(o.home)} (0600)`);
6596
+ writeTokenFile(o2.home, resolved.token);
6597
+ wrote.push(`saved token to ${tokenPath(o2.home)} (0600)`);
5821
6598
  }
5822
- const prior = readConfig(o.home);
5823
- writeConfig(o.home, {
6599
+ const prior = readConfig(o2.home);
6600
+ writeConfig(o2.home, {
5824
6601
  ...prior,
5825
6602
  token: resolved.token,
5826
6603
  proxyUrl: url,
@@ -5828,14 +6605,14 @@ var init = async (o) => {
5828
6605
  agentKind: "claude-code",
5829
6606
  ...seatInfo.email ? { email: seatInfo.email } : {},
5830
6607
  ...org ? { org } : {},
5831
- ...statusLine.prior !== undefined ? { priorStatusLine: statusLine.prior } : {}
6608
+ ...statusLine2.prior !== undefined ? { priorStatusLine: statusLine2.prior } : {}
5832
6609
  });
5833
- wrote.push(`saved token and proxy URL to ${configPath(o.home)} (0600)`);
5834
- mkdirSync8(skillDir(o.home), { recursive: true });
5835
- writeFileSync8(skillPath(o.home), SKILL_MD);
5836
- wrote.push(`installed skill at ${skillPath(o.home)}`);
5837
- if (o.installMusher) {
5838
- const r = o.installMusher();
6610
+ wrote.push(`saved token and proxy URL to ${configPath(o2.home)} (0600)`);
6611
+ mkdirSync8(skillDir(o2.home), { recursive: true });
6612
+ writeFileSync8(skillPath(o2.home), SKILL_MD);
6613
+ wrote.push(`installed skill at ${skillPath(o2.home)}`);
6614
+ if (o2.installMusher) {
6615
+ const r = o2.installMusher();
5839
6616
  if (r)
5840
6617
  wrote.push(r);
5841
6618
  }
@@ -5872,9 +6649,9 @@ var init = async (o) => {
5872
6649
  };
5873
6650
 
5874
6651
  // src/commands/mcp.ts
5875
- var mcp = async (o) => {
5876
- const stdin = o.stdin ?? process.stdin;
5877
- const write = o.write ?? ((line) => process.stdout.write(`${line}
6652
+ var mcp = async (o2) => {
6653
+ const stdin = o2.stdin ?? process.stdin;
6654
+ const write = o2.write ?? ((line) => process.stdout.write(`${line}
5878
6655
  `));
5879
6656
  let buffer = "";
5880
6657
  for await (const chunk of stdin) {
@@ -5884,7 +6661,7 @@ var mcp = async (o) => {
5884
6661
  while (nl !== -1) {
5885
6662
  const line = buffer.slice(0, nl);
5886
6663
  buffer = buffer.slice(nl + 1);
5887
- const out = await handleLine2(line, { home: o.home });
6664
+ const out = await handleLine2(line, { home: o2.home });
5888
6665
  if (out !== null)
5889
6666
  write(out);
5890
6667
  nl = buffer.indexOf(`
@@ -5892,7 +6669,7 @@ var mcp = async (o) => {
5892
6669
  }
5893
6670
  }
5894
6671
  if (buffer.trim().length > 0) {
5895
- const out = await handleLine2(buffer, { home: o.home });
6672
+ const out = await handleLine2(buffer, { home: o2.home });
5896
6673
  if (out !== null)
5897
6674
  write(out);
5898
6675
  }
@@ -5902,15 +6679,15 @@ var mcp = async (o) => {
5902
6679
  // src/commands/meter.ts
5903
6680
  init_config();
5904
6681
  init_meter();
5905
- var meter = async (o) => {
5906
- const log = o.log ?? console.log;
5907
- const now = (o.now ?? Date.now)();
5908
- const src = meterSource(o.home);
6682
+ var meter = async (o2) => {
6683
+ const log = o2.log ?? console.log;
6684
+ const now = (o2.now ?? Date.now)();
6685
+ const src = meterSource(o2.home);
5909
6686
  if (!src) {
5910
- log(`SLEDS is not set up (${configPath(o.home)}). Run \`sleds init\` first.`);
6687
+ log(`SLEDS is not set up (${configPath(o2.home)}). Run \`sleds init\` first.`);
5911
6688
  return 1;
5912
6689
  }
5913
- const m = await loadMeter({ home: o.home, now, fetchFn: o.fetchFn, timeoutMs: o.timeoutMs });
6690
+ const m = await loadMeter({ home: o2.home, now, fetchFn: o2.fetchFn, timeoutMs: o2.timeoutMs });
5914
6691
  if (!m) {
5915
6692
  log(`sleds offline. ${src.proxyUrl} did not answer → \`sleds status\` for the proxy health.`);
5916
6693
  return 2;
@@ -5930,9 +6707,9 @@ import { dirname as dirname5 } from "node:path";
5930
6707
  var defaultWhich3 = (cmd) => {
5931
6708
  const path = process.env.PATH ?? "";
5932
6709
  for (const dir of path.split(":").filter(Boolean)) {
5933
- const p = `${dir}/${cmd}`;
5934
- if (existsSync10(p))
5935
- return p;
6710
+ const p2 = `${dir}/${cmd}`;
6711
+ if (existsSync10(p2))
6712
+ return p2;
5936
6713
  }
5937
6714
  return null;
5938
6715
  };
@@ -5942,68 +6719,68 @@ var findClaude2 = (home, configured, which) => {
5942
6719
  const found = which("claude");
5943
6720
  if (found)
5944
6721
  return found;
5945
- for (const p of [
6722
+ for (const p2 of [
5946
6723
  `${home}/.local/bin/claude`,
5947
6724
  "/opt/homebrew/bin/claude",
5948
6725
  "/usr/local/bin/claude",
5949
6726
  `${home}/.npm-global/bin/claude`
5950
6727
  ])
5951
- if (existsSync10(p))
5952
- return p;
6728
+ if (existsSync10(p2))
6729
+ return p2;
5953
6730
  return null;
5954
6731
  };
5955
- var musherInstall = (o) => {
5956
- const log = o.log ?? console.log;
5957
- const error = o.error ?? console.error;
5958
- const platform = o.platform ?? process.platform;
5959
- if (platform !== "darwin") {
5960
- error(`sleds musher --install needs launchd (macOS). On ${platform}, run \`sleds musher tick\` from cron every 5 minutes.`);
6732
+ var musherInstall = (o2) => {
6733
+ const log = o2.log ?? console.log;
6734
+ const error = o2.error ?? console.error;
6735
+ const platform2 = o2.platform ?? process.platform;
6736
+ if (platform2 !== "darwin") {
6737
+ error(`sleds musher --install needs launchd (macOS). On ${platform2}, run \`sleds musher tick\` from cron every 5 minutes.`);
5961
6738
  return 1;
5962
6739
  }
5963
- const env = o.env ?? process.env;
5964
- const plist = musherPlistPath(o.home, env);
6740
+ const env = o2.env ?? process.env;
6741
+ const plist = musherPlistPath(o2.home, env);
5965
6742
  const label = musherLabel(env);
5966
- const dir = configDir(o.home, env);
6743
+ const dir = configDir(o2.home, env);
5967
6744
  mkdirSync9(dirname5(plist), { recursive: true });
5968
6745
  mkdirSync9(dir, { recursive: true, mode: 448 });
5969
- const execPath = o.sledsArgv[0] ?? process.execPath;
6746
+ const execPath = o2.sledsArgv[0] ?? process.execPath;
5970
6747
  const agentEnv = {
5971
- PATH: musherPath(o.home, execPath, env.PATH ?? ""),
5972
- HOME: o.home,
6748
+ PATH: musherPath(o2.home, execPath, env.PATH ?? ""),
6749
+ HOME: o2.home,
5973
6750
  ...env.SLEDS_HOME ? { SLEDS_HOME: env.SLEDS_HOME } : {},
5974
6751
  ...env.CLAUDE_CONFIG_DIR ? { CLAUDE_CONFIG_DIR: env.CLAUDE_CONFIG_DIR } : {}
5975
6752
  };
5976
- const exec = o.exec ?? defaultExecSync;
6753
+ const exec = o2.exec ?? defaultExecSync;
5977
6754
  if (existsSync10(plist))
5978
6755
  exec("launchctl", ["unload", plist]);
5979
- writeFileSync9(plist, buildMusherPlist({ sledsArgv: o.sledsArgv, env: agentEnv, logPath: musherLogPath(dir), label }));
6756
+ writeFileSync9(plist, buildMusherPlist({ sledsArgv: o2.sledsArgv, env: agentEnv, logPath: musherLogPath(dir), label }));
5980
6757
  const r = exec("launchctl", ["load", plist]);
5981
6758
  if (!r.ok) {
5982
6759
  error(`launchctl load failed: ${r.stderr.trim() || "unknown"}`);
5983
6760
  return 1;
5984
6761
  }
5985
- const cfg = readConfig(o.home);
5986
- writeConfig(o.home, { ...cfg, musher: { ...cfg.musher ?? {}, agent: "launchd" } });
5987
- const claude = findClaude2(o.home, cfg.musher?.claudePath, o.which ?? defaultWhich3);
6762
+ const cfg = readConfig(o2.home);
6763
+ writeConfig(o2.home, { ...cfg, musher: { ...cfg.musher ?? {}, agent: "launchd" } });
6764
+ const claude = findClaude2(o2.home, cfg.musher?.claudePath, o2.which ?? defaultWhich3);
5988
6765
  log(`musher installed: launchd agent ${label}, every 5 min · log ${musherLogPath(dir)}`);
5989
6766
  if (!claude)
5990
6767
  log("warn: `claude` not found on PATH — set it with `sleds musher --claude /path/to/claude`");
5991
6768
  return 0;
5992
6769
  };
5993
- var musherUninstall = (o) => {
5994
- const log = o.log ?? console.log;
5995
- const env = o.env ?? process.env;
5996
- const plist = musherPlistPath(o.home, env);
5997
- const exec = o.exec ?? defaultExecSync;
6770
+ var musherUninstall = (o2) => {
6771
+ const log = o2.log ?? console.log;
6772
+ const env = o2.env ?? process.env;
6773
+ const plist = musherPlistPath(o2.home, env);
6774
+ const exec = o2.exec ?? defaultExecSync;
5998
6775
  if (existsSync10(plist)) {
5999
6776
  exec("launchctl", ["unload", plist]);
6000
6777
  rmSync2(plist, { force: true });
6001
6778
  log(`musher removed: ${musherLabel(env)}`);
6002
6779
  } else
6003
6780
  log("musher was not installed.");
6004
- const cfg = readConfig(o.home);
6781
+ const cfg = readConfig(o2.home);
6005
6782
  if (cfg.musher)
6006
- writeConfig(o.home, { ...cfg, musher: { ...cfg.musher, agent: "none" } });
6783
+ writeConfig(o2.home, { ...cfg, musher: { ...cfg.musher, agent: "none" } });
6007
6784
  return 0;
6008
6785
  };
6009
6786
  var formatMusherStatus = (list, now) => {
@@ -6018,23 +6795,23 @@ var formatMusherStatus = (list, now) => {
6018
6795
  lines.push("nothing deferred on this seat.");
6019
6796
  return lines;
6020
6797
  };
6021
- var clientFor = (o) => {
6022
- if (o.client)
6023
- return o.client;
6024
- const src = meterSource(o.home);
6025
- return src ? musherClient({ ...src, fetchFn: o.fetchFn }) : null;
6026
- };
6027
- var musherStatus = async (o) => {
6028
- const log = o.log ?? console.log;
6029
- const now = (o.now ?? Date.now)();
6030
- const env = o.env ?? process.env;
6031
- const plist = musherPlistPath(o.home, env);
6032
- const cfg = readConfig(o.home);
6798
+ var clientFor = (o2) => {
6799
+ if (o2.client)
6800
+ return o2.client;
6801
+ const src = meterSource(o2.home);
6802
+ return src ? musherClient({ ...src, fetchFn: o2.fetchFn }) : null;
6803
+ };
6804
+ var musherStatus = async (o2) => {
6805
+ const log = o2.log ?? console.log;
6806
+ const now = (o2.now ?? Date.now)();
6807
+ const env = o2.env ?? process.env;
6808
+ const plist = musherPlistPath(o2.home, env);
6809
+ const cfg = readConfig(o2.home);
6033
6810
  log(existsSync10(plist) ? `agent ${musherLabel(env)} installed (${plist})` : "agent not installed — sleds musher --install");
6034
- const claude = findClaude2(o.home, cfg.musher?.claudePath, o.which ?? defaultWhich3);
6811
+ const claude = findClaude2(o2.home, cfg.musher?.claudePath, o2.which ?? defaultWhich3);
6035
6812
  log(`claude ${claude ?? "not found — sleds musher --claude /path/to/claude"}`);
6036
6813
  log(`mode ${cfg.musher?.permissionMode ?? DEFAULT_PERMISSION_MODE} · timeout ${cfg.musher?.timeoutMinutes ?? DEFAULT_TIMEOUT_MINUTES} min`);
6037
- const client = clientFor(o);
6814
+ const client = clientFor(o2);
6038
6815
  if (!client) {
6039
6816
  log("seat not initialised (sleds init)");
6040
6817
  return 1;
@@ -6048,9 +6825,9 @@ var musherStatus = async (o) => {
6048
6825
  log(line);
6049
6826
  return 0;
6050
6827
  };
6051
- var musherTick = async (o) => {
6052
- const log = o.log ?? console.log;
6053
- const client = clientFor(o);
6828
+ var musherTick = async (o2) => {
6829
+ const log = o2.log ?? console.log;
6830
+ const client = clientFor(o2);
6054
6831
  if (!client) {
6055
6832
  log("musher: seat not initialised; nothing to do");
6056
6833
  return 1;
@@ -6062,19 +6839,19 @@ var musherTick = async (o) => {
6062
6839
  }
6063
6840
  if (list.due.length === 0)
6064
6841
  return 0;
6065
- const cfg = readConfig(o.home);
6066
- const claude = findClaude2(o.home, cfg.musher?.claudePath, o.which ?? defaultWhich3) ?? "claude";
6067
- const seat = readSeatState(o.home);
6842
+ const cfg = readConfig(o2.home);
6843
+ const claude = findClaude2(o2.home, cfg.musher?.claudePath, o2.which ?? defaultWhich3) ?? "claude";
6844
+ const seat = readSeatState(o2.home);
6068
6845
  for (const job of list.due) {
6069
6846
  const out = await runJob({
6070
6847
  job,
6071
6848
  client,
6072
6849
  fallbackSession: seat.session,
6073
- host: o.host ?? hostname3(),
6850
+ host: o2.host ?? hostname3(),
6074
6851
  claudePath: claude,
6075
6852
  permissionMode: cfg.musher?.permissionMode ?? DEFAULT_PERMISSION_MODE,
6076
6853
  timeoutMs: (cfg.musher?.timeoutMinutes ?? DEFAULT_TIMEOUT_MINUTES) * 60000,
6077
- exec: o.execCapture,
6854
+ exec: o2.execCapture,
6078
6855
  log
6079
6856
  });
6080
6857
  if (out.kind === "skipped")
@@ -6082,9 +6859,9 @@ var musherTick = async (o) => {
6082
6859
  }
6083
6860
  return 0;
6084
6861
  };
6085
- var musherConfigure = (o, flags) => {
6086
- const log = o.log ?? console.log;
6087
- const cfg = readConfig(o.home);
6862
+ var musherConfigure = (o2, flags) => {
6863
+ const log = o2.log ?? console.log;
6864
+ const cfg = readConfig(o2.home);
6088
6865
  const musher = { ...cfg.musher ?? {} };
6089
6866
  if (flags.claude)
6090
6867
  musher.claudePath = flags.claude;
@@ -6093,12 +6870,12 @@ var musherConfigure = (o, flags) => {
6093
6870
  if (flags.timeout) {
6094
6871
  const n = Number.parseInt(flags.timeout, 10);
6095
6872
  if (!Number.isFinite(n) || n <= 0) {
6096
- (o.error ?? console.error)("--timeout takes minutes, a positive number");
6873
+ (o2.error ?? console.error)("--timeout takes minutes, a positive number");
6097
6874
  return 1;
6098
6875
  }
6099
6876
  musher.timeoutMinutes = n;
6100
6877
  }
6101
- writeConfig(o.home, { ...cfg, musher });
6878
+ writeConfig(o2.home, { ...cfg, musher });
6102
6879
  log(`musher settings: claude ${musher.claudePath ?? "(PATH)"} · mode ${musher.permissionMode ?? DEFAULT_PERMISSION_MODE} · timeout ${musher.timeoutMinutes ?? DEFAULT_TIMEOUT_MINUTES} min`);
6103
6880
  return 0;
6104
6881
  };
@@ -6108,8 +6885,8 @@ var defaultExecSync = (cmd, args) => {
6108
6885
  return { ok: false, stderr: r.error.message };
6109
6886
  return { ok: r.status === 0, stderr: r.stderr ?? "" };
6110
6887
  };
6111
- var musher = async (o) => {
6112
- const args = [...o.argv];
6888
+ var musher = async (o2) => {
6889
+ const args = [...o2.argv];
6113
6890
  const flags = {};
6114
6891
  const positional = [];
6115
6892
  for (let i = 0;i < args.length; i++) {
@@ -6125,16 +6902,16 @@ var musher = async (o) => {
6125
6902
  positional.push(a);
6126
6903
  }
6127
6904
  if (flags.install)
6128
- return musherInstall(o);
6905
+ return musherInstall(o2);
6129
6906
  if (flags.uninstall)
6130
- return musherUninstall(o);
6907
+ return musherUninstall(o2);
6131
6908
  if (flags.claude || flags.mode || flags.timeout)
6132
- return musherConfigure(o, flags);
6909
+ return musherConfigure(o2, flags);
6133
6910
  if (positional[0] === "tick")
6134
- return musherTick(o);
6911
+ return musherTick(o2);
6135
6912
  if (flags.status || positional.length === 0)
6136
- return musherStatus(o);
6137
- (o.error ?? console.error)(`sleds musher: unknown argument ${positional[0]}`);
6913
+ return musherStatus(o2);
6914
+ (o2.error ?? console.error)(`sleds musher: unknown argument ${positional[0]}`);
6138
6915
  return 1;
6139
6916
  };
6140
6917
 
@@ -6182,12 +6959,12 @@ var systemdCalendar = (deadline) => `${deadline.getFullYear()}-${pad2(deadline.g
6182
6959
  var scheduleRevert = (d, deadlineMs) => {
6183
6960
  const deadline = new Date(deadlineMs);
6184
6961
  if (d.platform === "darwin") {
6185
- const p = plistPath(d.home);
6962
+ const p2 = plistPath(d.home);
6186
6963
  try {
6187
6964
  mkdirSync10(join9(d.home, "Library", "LaunchAgents"), { recursive: true });
6188
- d.exec("launchctl", ["unload", p]);
6189
- writeFileSync10(p, buildLaunchdPlist(d.sledsArgv, deadline));
6190
- const r = d.exec("launchctl", ["load", p]);
6965
+ d.exec("launchctl", ["unload", p2]);
6966
+ writeFileSync10(p2, buildLaunchdPlist(d.sledsArgv, deadline));
6967
+ const r = d.exec("launchctl", ["load", p2]);
6191
6968
  if (r.ok)
6192
6969
  return { kind: "launchd", detail: `launchd agent ${REVERT_LABEL}` };
6193
6970
  return { kind: "manual", detail: `launchctl load failed: ${r.stderr.trim() || "unknown"}` };
@@ -6212,10 +6989,10 @@ var scheduleRevert = (d, deadlineMs) => {
6212
6989
  };
6213
6990
  var cancelRevert = (d, kind) => {
6214
6991
  if (kind === "launchd" || d.platform === "darwin") {
6215
- const p = plistPath(d.home);
6216
- if (existsSync11(p)) {
6217
- d.exec("launchctl", ["unload", p]);
6218
- rmSync3(p, { force: true });
6992
+ const p2 = plistPath(d.home);
6993
+ if (existsSync11(p2)) {
6994
+ d.exec("launchctl", ["unload", p2]);
6995
+ rmSync3(p2, { force: true });
6219
6996
  }
6220
6997
  }
6221
6998
  if (kind === "systemd" || d.platform === "linux") {
@@ -6225,15 +7002,15 @@ var cancelRevert = (d, kind) => {
6225
7002
 
6226
7003
  // src/commands/off.ts
6227
7004
  init_settings();
6228
- var off = (o) => {
6229
- const log = o.log ?? console.log;
6230
- const cfg = readConfig(o.home);
6231
- const settings = readSettings(o.home);
7005
+ var off = (o2) => {
7006
+ const log = o2.log ?? console.log;
7007
+ const cfg = readConfig(o2.home);
7008
+ const settings = readSettings(o2.home);
6232
7009
  const wasOn = cfg.mode === "on" || isPointedAtProxy(settings);
6233
7010
  if (wasOn)
6234
- writeSettings(o.home, switchOff(settings, cfg.priorEnv ?? {}));
6235
- if (o.scheduler)
6236
- cancelRevert(o.scheduler, cfg.schedule);
7011
+ writeSettings(o2.home, switchOff(settings, cfg.priorEnv ?? {}));
7012
+ if (o2.scheduler)
7013
+ cancelRevert(o2.scheduler, cfg.schedule);
6237
7014
  const next = {
6238
7015
  ...cfg,
6239
7016
  mode: "off",
@@ -6243,7 +7020,7 @@ var off = (o) => {
6243
7020
  priorEnv: undefined,
6244
7021
  schedule: undefined
6245
7022
  };
6246
- writeConfig(o.home, next);
7023
+ writeConfig(o2.home, next);
6247
7024
  if (!wasOn) {
6248
7025
  log("Sleds already off. Claude Code is on your seat.");
6249
7026
  return 0;
@@ -6262,19 +7039,19 @@ init_settings();
6262
7039
  var DEFAULT_PROXY_URL2 = "https://proxy.sleds.ai";
6263
7040
 
6264
7041
  // src/commands/on.ts
6265
- var on = (o) => {
6266
- const log = o.log ?? console.log;
6267
- const error = o.error ?? console.error;
6268
- const env = o.env ?? process.env;
6269
- const now = (o.now ?? Date.now)();
6270
- if (!hasClaudeCode(o.home)) {
6271
- error(`Claude Code not found (${claudeDir(o.home)} does not exist). Install it, then re-run.`);
7042
+ var on = (o2) => {
7043
+ const log = o2.log ?? console.log;
7044
+ const error = o2.error ?? console.error;
7045
+ const env = o2.env ?? process.env;
7046
+ const now = (o2.now ?? Date.now)();
7047
+ if (!hasClaudeCode(o2.home)) {
7048
+ error(`Claude Code not found (${claudeDir(o2.home)} does not exist). Install it, then re-run.`);
6272
7049
  return 1;
6273
7050
  }
6274
- const cfg = readConfig(o.home);
6275
- const token = cfg.token ?? readTokenFile(o.home) ?? env.SLEDS_TOKEN?.trim();
7051
+ const cfg = readConfig(o2.home);
7052
+ const token = cfg.token ?? readTokenFile(o2.home) ?? env.SLEDS_TOKEN?.trim();
6276
7053
  if (!token) {
6277
- error(`No seat token in ${configPath(o.home)}. Run \`sleds init\` first.`);
7054
+ error(`No seat token in ${configPath(o2.home)}. Run \`sleds init\` first.`);
6278
7055
  return 2;
6279
7056
  }
6280
7057
  if (!isSeatToken(token)) {
@@ -6285,28 +7062,28 @@ var on = (o) => {
6285
7062
  error(`${cfg.org.name} has no platform key, so there is no platform key to switch to. Hold until the reset, or hand off with /sled 5. An admin can add a key on the dashboard.`);
6286
7063
  return 2;
6287
7064
  }
6288
- const url = (o.url ?? cfg.proxyUrl ?? env.SLEDS_PROXY_URL ?? DEFAULT_PROXY_URL2).replace(/\/+$/, "");
7065
+ const url = (o2.url ?? cfg.proxyUrl ?? env.SLEDS_PROXY_URL ?? DEFAULT_PROXY_URL2).replace(/\/+$/, "");
6289
7066
  let untilResetMs;
6290
- if (o.untilReset !== undefined) {
7067
+ if (o2.untilReset !== undefined) {
6291
7068
  try {
6292
- untilResetMs = parseUntilReset(o.untilReset, now);
7069
+ untilResetMs = parseUntilReset(o2.untilReset, now);
6293
7070
  } catch (err) {
6294
7071
  error(err instanceof Error ? err.message : String(err));
6295
7072
  return 2;
6296
7073
  }
6297
7074
  }
6298
- const settings = readSettings(o.home);
7075
+ const settings = readSettings(o2.home);
6299
7076
  const priorEnv = cfg.mode === "on" && cfg.priorEnv ? cfg.priorEnv : capturePriorEnv(settings);
6300
- const backedUp = backupSettings(o.home);
6301
- writeSettings(o.home, switchOn(settings, { url, token }));
7077
+ const backedUp = backupSettings(o2.home);
7078
+ writeSettings(o2.home, switchOn(settings, { url, token }));
6302
7079
  let schedule;
6303
7080
  let scheduleNote;
6304
- if (untilResetMs !== undefined && !o.noSchedule && o.scheduler && hasHomeOverride(env)) {
7081
+ if (untilResetMs !== undefined && !o2.noSchedule && o2.scheduler && hasHomeOverride(env)) {
6305
7082
  error("SLEDS_HOME / CLAUDE_CONFIG_DIR is set: the auto-revert timer would act on the default seat. Re-run with --no-schedule and run `sleds off` yourself at the reset.");
6306
7083
  return 2;
6307
7084
  }
6308
- if (untilResetMs !== undefined && !o.noSchedule && o.scheduler) {
6309
- const r = scheduleRevert(o.scheduler, untilResetMs);
7085
+ if (untilResetMs !== undefined && !o2.noSchedule && o2.scheduler) {
7086
+ const r = scheduleRevert(o2.scheduler, untilResetMs);
6310
7087
  schedule = r.kind;
6311
7088
  scheduleNote = r.kind === "manual" ? r.detail : undefined;
6312
7089
  }
@@ -6322,19 +7099,19 @@ var on = (o) => {
6322
7099
  next.untilReset = new Date(untilResetMs).toISOString();
6323
7100
  else
6324
7101
  next.untilReset = undefined;
6325
- next.reason = o.reason?.trim() || undefined;
7102
+ next.reason = o2.reason?.trim() || undefined;
6326
7103
  next.schedule = schedule;
6327
- writeConfig(o.home, next);
7104
+ writeConfig(o2.home, next);
6328
7105
  log(`Sleds on. Claude Code now runs on the platform key through ${url}. Restart claude to apply.`);
6329
7106
  if (untilResetMs !== undefined) {
6330
- log(`Reverts at ${formatLocal(untilResetMs, o.tz)} — run \`sleds off\` earlier if you want.`);
7107
+ log(`Reverts at ${formatLocal(untilResetMs, o2.tz)} — run \`sleds off\` earlier if you want.`);
6331
7108
  if (schedule === undefined || schedule === "manual") {
6332
7109
  const why = scheduleNote ? ` (${scheduleNote})` : "";
6333
7110
  log(`Auto-revert not scheduled${why}. Run \`sleds off\` after the reset.`);
6334
7111
  }
6335
7112
  }
6336
7113
  if (backedUp)
6337
- log(`Backed up ${settingsPath(o.home)} to ${backupPath(o.home)}.`);
7114
+ log(`Backed up ${settingsPath(o2.home)} to ${backupPath(o2.home)}.`);
6338
7115
  return 0;
6339
7116
  };
6340
7117
 
@@ -6382,22 +7159,22 @@ var exitsLine = (hasUpstreamKey) => hasUpstreamKey ? "`/sled handoff <what you w
6382
7159
  var approachingContext = (bar, usedPct, resetsAt, hasUpstreamKey, now) => `[SLEDS] This seat is at ${usedPct !== undefined ? `${Math.round(usedPct)}%` : "90%+"} of its ${LABEL[bar]} limit; it resets in ${fmtIn(resetsAt - now)}. Tell the user in one short line before you answer, and offer the exits: ${exitsLine(hasUpstreamKey)} Do not mention this again unless asked.`;
6383
7160
  var hitContext = (bar, resetsAt, hasUpstreamKey, now) => `[SLEDS] This seat hit its ${LABEL[bar]} limit; it resets in ${fmtIn(resetsAt - now)}. If this reply fails or the user is stuck, the exits are: ${exitsLine(hasUpstreamKey)} Say so in one line.`;
6384
7161
  var creditsBlockText = (hasUpstreamKey) => `SLEDS: this seat is out of usage credits — the next reply would fail, so this prompt was not sent. ${hasUpstreamKey ? "Exits: /sled handoff <task> (a buddy picks it up), sleds on (continue on the workspace's platform key), or /model to a cheaper model." : "Exits: /sled handoff <task> (a buddy picks it up), sleds defer (resume when credits are topped up), or /model to a cheaper model."} Re-send your prompt after choosing; SLEDS will not block again.`;
6385
- var promptEvent = async (o) => {
6386
- const log = o.log ?? console.log;
6387
- const error = o.error ?? console.error;
6388
- const now = (o.now ?? Date.now)();
6389
- if (o.stdin === undefined)
7162
+ var promptEvent = async (o2) => {
7163
+ const log = o2.log ?? console.log;
7164
+ const error = o2.error ?? console.error;
7165
+ const now = (o2.now ?? Date.now)();
7166
+ if (o2.stdin === undefined)
6390
7167
  await readStdin(HOOK_STDIN_TIMEOUT_MS);
6391
7168
  let state;
6392
7169
  try {
6393
- state = readSeatState(o.home);
7170
+ state = readSeatState(o2.home);
6394
7171
  } catch {
6395
7172
  return 0;
6396
7173
  }
6397
7174
  const pending = untold(state);
6398
7175
  if (pending.length === 0)
6399
7176
  return 0;
6400
- const hasKey = readConfig(o.home).org?.capabilities.upstreamKey !== false;
7177
+ const hasKey = readConfig(o2.home).org?.capabilities.upstreamKey !== false;
6401
7178
  const told = { ...state.told ?? {} };
6402
7179
  const mark = (bar, stage, at) => {
6403
7180
  told[bar] = { ...told[bar] ?? {}, [stage]: at };
@@ -6417,7 +7194,7 @@ var promptEvent = async (o) => {
6417
7194
  lines.push(e.stage === "approaching" ? approachingContext(e.bar, pct, e.resetsAt, hasKey, now) : hitContext(e.bar, e.resetsAt, hasKey, now));
6418
7195
  }
6419
7196
  try {
6420
- writeSeatState(o.home, { ...state, told });
7197
+ writeSeatState(o2.home, { ...state, told });
6421
7198
  } catch {}
6422
7199
  if (code === 0 && lines.length > 0)
6423
7200
  log(lines.join(`
@@ -6429,16 +7206,16 @@ var promptEvent = async (o) => {
6429
7206
  init_config();
6430
7207
  init_meter();
6431
7208
  import { hostname as hostname4 } from "node:os";
6432
- var run = async (o) => {
6433
- const log = o.log ?? console.log;
6434
- const error = o.error ?? console.error;
6435
- if (!o.jobId) {
7209
+ var run = async (o2) => {
7210
+ const log = o2.log ?? console.log;
7211
+ const error = o2.error ?? console.error;
7212
+ if (!o2.jobId) {
6436
7213
  error("usage: sleds run <jobId>");
6437
7214
  return 2;
6438
7215
  }
6439
- const client = o.client ?? (() => {
6440
- const src = meterSource(o.home);
6441
- return src ? musherClient({ ...src, fetchFn: o.fetchFn }) : null;
7216
+ const client = o2.client ?? (() => {
7217
+ const src = meterSource(o2.home);
7218
+ return src ? musherClient({ ...src, fetchFn: o2.fetchFn }) : null;
6442
7219
  })();
6443
7220
  if (!client) {
6444
7221
  error("No seat on this machine. Run `sleds init` first.");
@@ -6449,13 +7226,13 @@ var run = async (o) => {
6449
7226
  error("Could not reach the SLEDS proxy.");
6450
7227
  return 1;
6451
7228
  }
6452
- const job = [...list.due, ...list.upcoming].find((j) => j.jobId === o.jobId);
7229
+ const job = [...list.due, ...list.upcoming].find((j) => j.jobId === o2.jobId);
6453
7230
  if (!job) {
6454
- error(`Job ${o.jobId} is not a scheduled local job on this seat (sleds musher --status lists them).`);
7231
+ error(`Job ${o2.jobId} is not a scheduled local job on this seat (sleds musher --status lists them).`);
6455
7232
  return 1;
6456
7233
  }
6457
- const cfg = readConfig(o.home);
6458
- const claude = findClaude(o.home, cfg.musher?.claudePath, o.which ?? defaultWhich);
7234
+ const cfg = readConfig(o2.home);
7235
+ const claude = findClaude(o2.home, cfg.musher?.claudePath, o2.which ?? defaultWhich);
6459
7236
  if (!claude) {
6460
7237
  error("`claude` not found. Install Claude Code, or `sleds musher --claude /path/to/claude`.");
6461
7238
  return 1;
@@ -6463,12 +7240,12 @@ var run = async (o) => {
6463
7240
  const out = await runJob({
6464
7241
  job,
6465
7242
  client,
6466
- fallbackSession: readSeatState(o.home).session,
6467
- host: o.host ?? hostname4(),
7243
+ fallbackSession: readSeatState(o2.home).session,
7244
+ host: o2.host ?? hostname4(),
6468
7245
  claudePath: claude,
6469
7246
  permissionMode: cfg.musher?.permissionMode ?? DEFAULT_PERMISSION_MODE,
6470
7247
  timeoutMs: (cfg.musher?.timeoutMinutes ?? DEFAULT_TIMEOUT_MINUTES) * 60000,
6471
- exec: o.execCapture,
7248
+ exec: o2.execCapture,
6472
7249
  log
6473
7250
  });
6474
7251
  if (out.kind === "skipped") {
@@ -6501,25 +7278,25 @@ var notificationType = (text) => {
6501
7278
  return;
6502
7279
  }
6503
7280
  };
6504
- var seatEvent = async (o) => {
6505
- const log = o.log ?? console.log;
6506
- const now = (o.now ?? Date.now)();
6507
- const input = o.stdin ?? await readStdin(HOOK_STDIN_TIMEOUT_MS2);
7281
+ var seatEvent = async (o2) => {
7282
+ const log = o2.log ?? console.log;
7283
+ const now = (o2.now ?? Date.now)();
7284
+ const input = o2.stdin ?? await readStdin(HOOK_STDIN_TIMEOUT_MS2);
6508
7285
  const kind = notificationType(input);
6509
7286
  try {
6510
- const state = readSeatState(o.home);
7287
+ const state = readSeatState(o2.home);
6511
7288
  const week = state.window?.sevenDay;
6512
- const src = meterSource(o.home);
7289
+ const src = meterSource(o2.home);
6513
7290
  if (src) {
6514
- await postSeatWall({ ...src, fetchFn: o.fetchFn, timeoutMs: o.timeoutMs ?? SEAT_POST_TIMEOUT_MS }, {
7291
+ await postSeatWall({ ...src, fetchFn: o2.fetchFn, timeoutMs: o2.timeoutMs ?? SEAT_POST_TIMEOUT_MS }, {
6515
7292
  ...week ? { resetsAt: week.resetsAt, usedPct: week.usedPct } : {},
6516
7293
  ...kind ? { notification: kind } : {}
6517
7294
  });
6518
7295
  }
6519
7296
  if (week && week.resetsAt > now)
6520
- writeSeatState(o.home, { ...state, lastWallResetsAt: week.resetsAt });
7297
+ writeSeatState(o2.home, { ...state, lastWallResetsAt: week.resetsAt });
6521
7298
  } catch {}
6522
- const line = seatWallLine(readConfig(o.home).org?.capabilities.upstreamKey !== false);
7299
+ const line = seatWallLine(readConfig(o2.home).org?.capabilities.upstreamKey !== false);
6523
7300
  log(line);
6524
7301
  return 0;
6525
7302
  };
@@ -6539,11 +7316,11 @@ var isBun = () => typeof globalThis.Bun !== "undefined";
6539
7316
  async function queryRows(dbPath) {
6540
7317
  if (isBun()) {
6541
7318
  const { Database } = await import("bun:sqlite");
6542
- const conn = new Database(dbPath, { readonly: true });
7319
+ const conn2 = new Database(dbPath, { readonly: true });
6543
7320
  try {
6544
- return conn.query(QUERY).all();
7321
+ return conn2.query(QUERY).all();
6545
7322
  } finally {
6546
- conn.close();
7323
+ conn2.close();
6547
7324
  }
6548
7325
  }
6549
7326
  const mod = nodeSqlite();
@@ -6649,19 +7426,19 @@ function parseSeatSyncArgs(argv) {
6649
7426
  return { error: `--profile does not apply to --browser ${source.browser}` };
6650
7427
  return { source };
6651
7428
  }
6652
- function resolveProfileDir(localStateJson, profile) {
7429
+ function resolveProfileDir(localStateJson, profile3) {
6653
7430
  let cache = {};
6654
7431
  if (localStateJson) {
6655
7432
  try {
6656
7433
  const raw = JSON.parse(localStateJson);
6657
- const p = isObject11(raw) && isObject11(raw.profile) ? raw.profile : null;
6658
- if (p && isObject11(p.info_cache))
6659
- cache = p.info_cache;
7434
+ const p2 = isObject11(raw) && isObject11(raw.profile) ? raw.profile : null;
7435
+ if (p2 && isObject11(p2.info_cache))
7436
+ cache = p2.info_cache;
6660
7437
  } catch {}
6661
7438
  }
6662
- if (Object.hasOwn(cache, profile))
6663
- return { dir: profile };
6664
- const want = profile.toLowerCase();
7439
+ if (Object.hasOwn(cache, profile3))
7440
+ return { dir: profile3 };
7441
+ const want = profile3.toLowerCase();
6665
7442
  const hits = [];
6666
7443
  for (const [dir, info] of Object.entries(cache)) {
6667
7444
  if (!isObject11(info))
@@ -6677,7 +7454,7 @@ function resolveProfileDir(localStateJson, profile) {
6677
7454
  return { dir: hits[0] ?? null };
6678
7455
  if (hits.length > 1)
6679
7456
  return { dir: null, ambiguous: hits };
6680
- return { dir: Object.keys(cache).length === 0 ? profile : null };
7457
+ return { dir: Object.keys(cache).length === 0 ? profile3 : null };
6681
7458
  }
6682
7459
  function cookieDbCandidates(profileDir) {
6683
7460
  return [`${profileDir}/Network/Cookies`, `${profileDir}/Cookies`];
@@ -6847,11 +7624,11 @@ function findFile(root, name) {
6847
7624
  continue;
6848
7625
  }
6849
7626
  for (const e of entries) {
6850
- const p = join11(dir, e.name);
7627
+ const p2 = join11(dir, e.name);
6851
7628
  if (e.isDirectory())
6852
- stack.push(p);
7629
+ stack.push(p2);
6853
7630
  else if (e.name === name)
6854
- return p;
7631
+ return p2;
6855
7632
  }
6856
7633
  }
6857
7634
  return null;
@@ -6862,10 +7639,10 @@ function findCookieDb(home, source) {
6862
7639
  if (!existsSync12(root))
6863
7640
  throw new Error(`no ${source.browser} data at ${root} (is it installed?)`);
6864
7641
  if (!b.profiled) {
6865
- const db = findFile(root, "Cookies");
6866
- if (!db)
7642
+ const db2 = findFile(root, "Cookies");
7643
+ if (!db2)
6867
7644
  throw new Error(`no cookie store under ${root}`);
6868
- return db;
7645
+ return db2;
6869
7646
  }
6870
7647
  const localStatePath = join11(root, "Local State");
6871
7648
  const localState = existsSync12(localStatePath) ? readFileSync10(localStatePath, "utf8") : null;
@@ -6875,7 +7652,7 @@ function findCookieDb(home, source) {
6875
7652
  throw new Error(`"${wanted}" names ${ambiguous.length} ${source.browser} profiles (${ambiguous.join(", ")}) — pass the directory or the account email instead`);
6876
7653
  if (!dir)
6877
7654
  throw new Error(`no ${source.browser} profile named "${wanted}" (check chrome://version)`);
6878
- const db = cookieDbCandidates(join11(root, dir)).find((p) => existsSync12(p));
7655
+ const db = cookieDbCandidates(join11(root, dir)).find((p2) => existsSync12(p2));
6879
7656
  if (!db)
6880
7657
  throw new Error(`profile "${dir}" has no cookie store yet (open claude.ai in it once)`);
6881
7658
  return db;
@@ -6906,8 +7683,8 @@ var curlUsage = (org, cookie) => {
6906
7683
  return { status: 0, body: "" };
6907
7684
  }
6908
7685
  };
6909
- function fetchSeatUsage(jar, org, now, run) {
6910
- const { status, body } = run(org, cookieHeader(jar, org));
7686
+ function fetchSeatUsage(jar, org, now, run2) {
7687
+ const { status, body } = run2(org, cookieHeader(jar, org));
6911
7688
  if (status !== 200)
6912
7689
  return { usage: null, status };
6913
7690
  try {
@@ -6968,24 +7745,24 @@ function uninstall(home, source, log) {
6968
7745
  log(existsSync12(path) ? `seat-sync timer removed (${path} can be deleted)` : "no seat-sync timer");
6969
7746
  return 0;
6970
7747
  }
6971
- var seatSync = async (o) => {
6972
- const log = o.log ?? console.log;
6973
- const now = (o.now ?? Date.now)();
6974
- const parsed = parseSeatSyncArgs(o.argv ?? process.argv.slice(3));
7748
+ var seatSync = async (o2) => {
7749
+ const log = o2.log ?? console.log;
7750
+ const now = (o2.now ?? Date.now)();
7751
+ const parsed = parseSeatSyncArgs(o2.argv ?? process.argv.slice(3));
6975
7752
  if ("error" in parsed) {
6976
7753
  log(`seat-sync: ${parsed.error}`);
6977
7754
  return 1;
6978
7755
  }
6979
7756
  const { source } = parsed;
6980
7757
  if (source.uninstall)
6981
- return uninstall(o.home, source, log);
7758
+ return uninstall(o2.home, source, log);
6982
7759
  if (source.install)
6983
- return install(o.home, [process.execPath, process.argv[1] ?? ""], source, log);
6984
- if (platform2() !== "darwin" && !o.readCookieRows) {
7760
+ return install(o2.home, [process.execPath, process.argv[1] ?? ""], source, log);
7761
+ if (platform2() !== "darwin" && !o2.readCookieRows) {
6985
7762
  log("seat-sync is macOS-only for now.");
6986
7763
  return 2;
6987
7764
  }
6988
- const saved = meterSource(o.home);
7765
+ const saved = meterSource(o2.home);
6989
7766
  const proxyUrl = saved?.proxyUrl;
6990
7767
  const token = source.token ?? saved?.token;
6991
7768
  if (!proxyUrl || !token) {
@@ -6994,13 +7771,13 @@ var seatSync = async (o) => {
6994
7771
  }
6995
7772
  let rows;
6996
7773
  try {
6997
- rows = o.readCookieRows ? o.readCookieRows(o.home, source) : await readCookieRowsBun(o.home, source);
7774
+ rows = o2.readCookieRows ? o2.readCookieRows(o2.home, source) : await readCookieRowsBun(o2.home, source);
6998
7775
  } catch (e) {
6999
7776
  log(`seat-sync: ${e instanceof Error ? e.message : String(e)}`);
7000
7777
  return 1;
7001
7778
  }
7002
7779
  const service = BROWSERS[source.browser].keychainService;
7003
- const pw = (o.safeStorageKey ?? keychainKey)(service);
7780
+ const pw = (o2.safeStorageKey ?? keychainKey)(service);
7004
7781
  if (!pw) {
7005
7782
  log(`seat-sync: could not read the "${service}" key from your Keychain.`);
7006
7783
  return 1;
@@ -7020,16 +7797,16 @@ var seatSync = async (o) => {
7020
7797
  log("seat-sync: no active org in the session cookie (pass --org <uuid>).");
7021
7798
  return 1;
7022
7799
  }
7023
- const { usage, status } = fetchSeatUsage(jar, org, now, o.runUsage ?? curlUsage);
7800
+ const { usage, status } = fetchSeatUsage(jar, org, now, o2.runUsage ?? curlUsage);
7024
7801
  if (!usage) {
7025
7802
  const why = status === 403 ? "claude.ai refused the read (403) — session expired, or this org is not readable by this session." : status === 0 ? "could not reach claude.ai." : `unexpected HTTP ${status}.`;
7026
7803
  log(`seat-sync: usage read failed — ${why}`);
7027
7804
  return 2;
7028
7805
  }
7029
7806
  try {
7030
- writeSeatState(o.home, { ...readSeatState(o.home), window: usageAsWindow(usage) });
7807
+ writeSeatState(o2.home, { ...readSeatState(o2.home), window: usageAsWindow(usage) });
7031
7808
  } catch {}
7032
- const posted = await postSeat(proxyUrl, token, seatSyncBody(usage), o.fetchFn ?? fetch);
7809
+ const posted = await postSeat(proxyUrl, token, seatSyncBody(usage), o2.fetchFn ?? fetch);
7033
7810
  const wk = usage.sevenDay ? `wk ${Math.round(usage.sevenDay.usedPct)}%` : "wk —";
7034
7811
  const models = Object.keys(usage.models).length;
7035
7812
  const credits = usage.usedCreditsUsd !== undefined ? ` · $${usage.usedCreditsUsd.toFixed(2)}` : "";
@@ -7081,14 +7858,14 @@ function sessionContext(a) {
7081
7858
  return lines.join(`
7082
7859
  `);
7083
7860
  }
7084
- var sessionEvent = async (o) => {
7085
- const log = o.log ?? console.log;
7086
- const now = (o.now ?? Date.now)();
7087
- const raw = o.stdin ?? await readStdin(HOOK_STDIN_TIMEOUT_MS);
7861
+ var sessionEvent = async (o2) => {
7862
+ const log = o2.log ?? console.log;
7863
+ const now = (o2.now ?? Date.now)();
7864
+ const raw = o2.stdin ?? await readStdin(HOOK_STDIN_TIMEOUT_MS);
7088
7865
  const payload = parseSessionPayload(raw);
7089
7866
  if (payload.session_id) {
7090
7867
  try {
7091
- writeSession(o.home, {
7868
+ writeSession(o2.home, {
7092
7869
  sessionId: payload.session_id,
7093
7870
  startedAt: now,
7094
7871
  ...payload.source ? { source: payload.source } : {}
@@ -7098,13 +7875,13 @@ var sessionEvent = async (o) => {
7098
7875
  let email;
7099
7876
  let org;
7100
7877
  try {
7101
- const cfg = readConfig(o.home);
7878
+ const cfg = readConfig(o2.home);
7102
7879
  email = cfg.email;
7103
7880
  org = cfg.org?.slug;
7104
7881
  } catch {}
7105
7882
  let owed = [];
7106
7883
  try {
7107
- owed = readOwed(o.home, now);
7884
+ owed = readOwed(o2.home, now);
7108
7885
  } catch {
7109
7886
  owed = [];
7110
7887
  }
@@ -7149,13 +7926,13 @@ function parseHookInput(raw) {
7149
7926
  }
7150
7927
  if (typeof parsed !== "object" || parsed === null)
7151
7928
  return null;
7152
- const p = parsed;
7153
- const toolName = typeof p.tool_name === "string" ? p.tool_name : "";
7154
- const input = typeof p.tool_input === "object" && p.tool_input !== null ? p.tool_input : {};
7929
+ const p2 = parsed;
7930
+ const toolName = typeof p2.tool_name === "string" ? p2.tool_name : "";
7931
+ const input = typeof p2.tool_input === "object" && p2.tool_input !== null ? p2.tool_input : {};
7155
7932
  const filePath = typeof input.file_path === "string" ? input.file_path : "";
7156
7933
  if (!filePath)
7157
7934
  return null;
7158
- const cwd = typeof p.cwd === "string" ? p.cwd : "";
7935
+ const cwd = typeof p2.cwd === "string" ? p2.cwd : "";
7159
7936
  return { toolName, filePath, cwd };
7160
7937
  }
7161
7938
  function projectKey(filePath, cwd) {
@@ -7175,16 +7952,16 @@ function readFileOrNull(path) {
7175
7952
  return null;
7176
7953
  }
7177
7954
  }
7178
- var specEvent = async (o) => {
7179
- const log = o.log ?? console.log;
7180
- const raw = o.stdin ?? await readStdin(HOOK_STDIN_TIMEOUT_MS3);
7955
+ var specEvent = async (o2) => {
7956
+ const log = o2.log ?? console.log;
7957
+ const raw = o2.stdin ?? await readStdin(HOOK_STDIN_TIMEOUT_MS3);
7181
7958
  const input = raw ? parseHookInput(raw) : null;
7182
7959
  if (!input || !isSpecPath(input.filePath))
7183
7960
  return 0;
7184
- const src = meterSource(o.home);
7961
+ const src = meterSource(o2.home);
7185
7962
  if (!src)
7186
7963
  return 0;
7187
- const body = (o.readFile ?? readFileOrNull)(input.filePath);
7964
+ const body = (o2.readFile ?? readFileOrNull)(input.filePath);
7188
7965
  if (!body || !looksLikeSpec(body))
7189
7966
  return 0;
7190
7967
  const project = projectKey(input.filePath, input.cwd);
@@ -7194,7 +7971,7 @@ var specEvent = async (o) => {
7194
7971
  repoHint: input.cwd ? basename2(input.cwd) : undefined
7195
7972
  };
7196
7973
  try {
7197
- const res = await (o.fetchFn ?? fetch)(`${src.proxyUrl}/proxy/estimate`, {
7974
+ const res = await (o2.fetchFn ?? fetch)(`${src.proxyUrl}/proxy/estimate`, {
7198
7975
  method: "POST",
7199
7976
  headers: { authorization: `Bearer ${src.token}`, "content-type": "application/json" },
7200
7977
  body: JSON.stringify({ spec, project }),
@@ -7209,15 +7986,15 @@ var specEvent = async (o) => {
7209
7986
  log(`sleds: ${project} sized at $${b.lowUsd.toFixed(2)}–${b.highUsd.toFixed(2)} · ${min(b.lowMinutes)}–${min(b.highMinutes)} min`);
7210
7987
  if (typeof b.lowMinutes === "number" && typeof b.highMinutes === "number") {
7211
7988
  try {
7212
- writeSeatState(o.home, {
7213
- ...readSeatState(o.home),
7989
+ writeSeatState(o2.home, {
7990
+ ...readSeatState(o2.home),
7214
7991
  estimate: {
7215
7992
  project,
7216
7993
  lowUsd: b.lowUsd,
7217
7994
  highUsd: b.highUsd,
7218
7995
  lowMin: b.lowMinutes,
7219
7996
  highMin: b.highMinutes,
7220
- at: (o.now ?? Date.now)()
7997
+ at: (o2.now ?? Date.now)()
7221
7998
  }
7222
7999
  });
7223
8000
  } catch {}
@@ -7231,7 +8008,8 @@ var specEvent = async (o) => {
7231
8008
  init_config();
7232
8009
  init_settings();
7233
8010
  import { existsSync as existsSync13 } from "node:fs";
7234
- var checkHealth2 = async (url, fetchFn = fetch, timeoutMs = 1000) => {
8011
+ var HEALTH_TIMEOUT_MS2 = 4000;
8012
+ var checkHealth2 = async (url, fetchFn = fetch, timeoutMs = HEALTH_TIMEOUT_MS2) => {
7235
8013
  try {
7236
8014
  const res = await fetchFn(`${url}/healthz`, { signal: AbortSignal.timeout(timeoutMs) });
7237
8015
  return res.ok ? "ok" : "unreachable";
@@ -7239,7 +8017,7 @@ var checkHealth2 = async (url, fetchFn = fetch, timeoutMs = 1000) => {
7239
8017
  return "unreachable";
7240
8018
  }
7241
8019
  };
7242
- var fetchProxyStatus = async (url, fetchFn = fetch, timeoutMs = 1000) => {
8020
+ var fetchProxyStatus = async (url, fetchFn = fetch, timeoutMs = HEALTH_TIMEOUT_MS2) => {
7243
8021
  try {
7244
8022
  const res = await fetchFn(`${url}/status`, { signal: AbortSignal.timeout(timeoutMs) });
7245
8023
  if (!res.ok)
@@ -7300,16 +8078,16 @@ var formatStatus = (s) => {
7300
8078
  }
7301
8079
  return lines;
7302
8080
  };
7303
- var status = async (o) => {
7304
- const log = o.log ?? console.log;
7305
- const nowMs = (o.now ?? Date.now)();
7306
- const cfg = readConfig(o.home);
7307
- const settings = existsSync13(settingsPath(o.home)) ? readSettings(o.home) : {};
8081
+ var status = async (o2) => {
8082
+ const log = o2.log ?? console.log;
8083
+ const nowMs = (o2.now ?? Date.now)();
8084
+ const cfg = readConfig(o2.home);
8085
+ const settings = existsSync13(settingsPath(o2.home)) ? readSettings(o2.home) : {};
7308
8086
  const inSettings = readProxy(settings);
7309
8087
  const proxyUrl = inSettings?.url ?? cfg.proxyUrl;
7310
8088
  const token = inSettings?.token ?? cfg.token;
7311
8089
  if (!proxyUrl && !token && cfg.mode === undefined) {
7312
- log(`SLEDS is not set up (${configPath(o.home)} and ${settingsPath(o.home)}).`);
8090
+ log(`SLEDS is not set up (${configPath(o2.home)} and ${settingsPath(o2.home)}).`);
7313
8091
  log("Run `sleds init` first.");
7314
8092
  return 1;
7315
8093
  }
@@ -7317,8 +8095,8 @@ var status = async (o) => {
7317
8095
  mode: cfg.mode ?? "off",
7318
8096
  pointed: inSettings !== null,
7319
8097
  nowMs,
7320
- settingsFile: settingsPath(o.home),
7321
- configFile: configPath(o.home)
8098
+ settingsFile: settingsPath(o2.home),
8099
+ configFile: configPath(o2.home)
7322
8100
  };
7323
8101
  if (proxyUrl)
7324
8102
  info.proxyUrl = proxyUrl;
@@ -7338,8 +8116,8 @@ var status = async (o) => {
7338
8116
  };
7339
8117
  if (cfg.reason)
7340
8118
  info.reason = cfg.reason;
7341
- if (o.tz)
7342
- info.tz = o.tz;
8119
+ if (o2.tz)
8120
+ info.tz = o2.tz;
7343
8121
  const since = cfg.since ? Date.parse(cfg.since) : Number.NaN;
7344
8122
  if (!Number.isNaN(since))
7345
8123
  info.sinceMs = since;
@@ -7348,8 +8126,8 @@ var status = async (o) => {
7348
8126
  info.untilResetMs = until;
7349
8127
  if (proxyUrl) {
7350
8128
  const [health, proxy] = await Promise.all([
7351
- checkHealth2(proxyUrl, o.fetchFn, o.timeoutMs),
7352
- fetchProxyStatus(proxyUrl, o.fetchFn, o.timeoutMs)
8129
+ checkHealth2(proxyUrl, o2.fetchFn, o2.timeoutMs),
8130
+ fetchProxyStatus(proxyUrl, o2.fetchFn, o2.timeoutMs)
7353
8131
  ]);
7354
8132
  info.health = health;
7355
8133
  info.proxy = proxy;
@@ -7362,62 +8140,62 @@ var status = async (o) => {
7362
8140
  // src/commands/statusline.ts
7363
8141
  init_config();
7364
8142
  init_meter();
7365
- var statusline = async (o) => {
7366
- const log = o.log ?? console.log;
7367
- const now = (o.now ?? Date.now)();
7368
- const input = o.stdin ?? await readStdin(STDIN_TIMEOUT_MS);
8143
+ var statusline = async (o2) => {
8144
+ const log = o2.log ?? console.log;
8145
+ const now = (o2.now ?? Date.now)();
8146
+ const input = o2.stdin ?? await readStdin(STDIN_TIMEOUT_MS);
7369
8147
  const window = seatWindowFromStdin(input, now);
7370
8148
  const session = seatSessionFromStdin(input, now);
7371
8149
  let posts = [];
7372
8150
  let events = [];
7373
8151
  try {
7374
8152
  if (window)
7375
- ({ posts, events } = rememberSeat(o, window, session, now, input));
8153
+ ({ posts, events } = rememberSeat(o2, window, session, now, input));
7376
8154
  else {
7377
- const st = readSeatState(o.home);
7378
- const credits = creditsEvent(o, st, input, now);
8155
+ const st = readSeatState(o2.home);
8156
+ const credits = creditsEvent(o2, st, input, now);
7379
8157
  if (session || credits.scan) {
7380
8158
  const next = {
7381
8159
  ...st,
7382
8160
  ...session ? { session } : {},
7383
8161
  ...credits.scan ? { transcriptScan: credits.scan } : {}
7384
8162
  };
7385
- writeSeatState(o.home, credits.event ? markWarned(next, [credits.event]) : next);
8163
+ writeSeatState(o2.home, credits.event ? markWarned(next, [credits.event]) : next);
7386
8164
  }
7387
8165
  if (credits.event) {
7388
8166
  events = [credits.event];
7389
- posts = announce(o, events);
8167
+ posts = announce(o2, events);
7390
8168
  }
7391
8169
  }
7392
8170
  } catch {}
7393
8171
  const seatFragment = formatSeatFragment(window, now);
7394
8172
  let line;
7395
8173
  try {
7396
- const meter = await loadMeter({
7397
- home: o.home,
8174
+ const meter2 = await loadMeter({
8175
+ home: o2.home,
7398
8176
  now,
7399
- fetchFn: o.fetchFn,
7400
- timeoutMs: o.timeoutMs
8177
+ fetchFn: o2.fetchFn,
8178
+ timeoutMs: o2.timeoutMs
7401
8179
  });
7402
- line = formatMeterLine(meter, now, seatFragment);
8180
+ line = formatMeterLine(meter2, now, seatFragment);
7403
8181
  } catch {
7404
8182
  line = formatMeterLine(null, now, seatFragment);
7405
8183
  }
7406
8184
  log(line);
7407
- posts.push(speakToCockpit(o, window, events, now));
8185
+ posts.push(speakToCockpit(o2, window, events, now));
7408
8186
  await Promise.allSettled(posts);
7409
8187
  return 0;
7410
8188
  };
7411
- var speakToCockpit = async (o, window, events, now) => {
7412
- const cockpit = detectCockpit(o.env ?? process.env);
8189
+ var speakToCockpit = async (o2, window, events, now) => {
8190
+ const cockpit = detectCockpit(o2.env ?? process.env);
7413
8191
  if (!cockpit)
7414
8192
  return;
7415
8193
  try {
7416
- const st = readSeatState(o.home);
8194
+ const st = readSeatState(o2.home);
7417
8195
  let feed;
7418
- const src = meterSource(o.home);
8196
+ const src = meterSource(o2.home);
7419
8197
  if (src && now - (st.cockpit?.feed?.at ?? 0) >= FEED_MIN_INTERVAL_MS) {
7420
- const got = await fetchFeed({ ...src, email: readConfig(o.home).email, fetchFn: o.fetchFn, timeoutMs: o.timeoutMs }, now);
8198
+ const got = await fetchFeed({ ...src, email: readConfig(o2.home).email, fetchFn: o2.fetchFn, timeoutMs: o2.timeoutMs }, now);
7421
8199
  if (got)
7422
8200
  feed = got;
7423
8201
  }
@@ -7428,32 +8206,32 @@ var speakToCockpit = async (o, window, events, now) => {
7428
8206
  const changed = r.argv.length > 0 || feed !== undefined;
7429
8207
  if (!changed)
7430
8208
  return;
7431
- writeSeatState(o.home, { ...readSeatState(o.home), cockpit: r.state });
8209
+ writeSeatState(o2.home, { ...readSeatState(o2.home), cockpit: r.state });
7432
8210
  if (r.argv.length)
7433
- await runCockpit(cockpit, r.argv, { spawn: o.spawn });
8211
+ await runCockpit(cockpit, r.argv, { spawn: o2.spawn });
7434
8212
  } catch {}
7435
8213
  };
7436
- var rememberSeat = (o, window, session, now, input) => {
7437
- const prior = readSeatState(o.home);
8214
+ var rememberSeat = (o2, window, session, now, input) => {
8215
+ const prior = readSeatState(o2.home);
7438
8216
  let state = { ...prior, window, ...session ? { session } : {} };
7439
- const src = meterSource(o.home);
8217
+ const src = meterSource(o2.home);
7440
8218
  const posts = [];
7441
8219
  if (src && shouldPostSeat(prior, window, now)) {
7442
8220
  state = markPosted(state, window, now);
7443
- posts.push(postSeatWindow({ ...src, fetchFn: o.fetchFn, timeoutMs: o.timeoutMs ?? SEAT_POST_TIMEOUT_MS }, window));
8221
+ posts.push(postSeatWindow({ ...src, fetchFn: o2.fetchFn, timeoutMs: o2.timeoutMs ?? SEAT_POST_TIMEOUT_MS }, window));
7444
8222
  }
7445
8223
  const events = seatWallEvents(prior, window);
7446
- const credits = creditsEvent(o, prior, input, now);
8224
+ const credits = creditsEvent(o2, prior, input, now);
7447
8225
  if (credits.scan)
7448
8226
  state = { ...state, transcriptScan: credits.scan };
7449
8227
  if (credits.event)
7450
8228
  events.push(credits.event);
7451
8229
  state = markWarned(state, events);
7452
- posts.push(...announce(o, events));
7453
- writeSeatState(o.home, state);
8230
+ posts.push(...announce(o2, events));
8231
+ writeSeatState(o2.home, state);
7454
8232
  return { posts, events };
7455
8233
  };
7456
- var creditsEvent = (o, prior, input, now) => {
8234
+ var creditsEvent = (o2, prior, input, now) => {
7457
8235
  const path = transcriptPathFromStdin(input);
7458
8236
  if (!path)
7459
8237
  return { event: null, scan: undefined };
@@ -7463,13 +8241,13 @@ var creditsEvent = (o, prior, input, now) => {
7463
8241
  return { event: null, scan: next };
7464
8242
  return { event: { bar: "credits", stage: "hit", usedPct: 100, resetsAt: now }, scan: next };
7465
8243
  };
7466
- var announce = (o, events) => {
8244
+ var announce = (o2, events) => {
7467
8245
  if (events.length === 0)
7468
8246
  return [];
7469
- const src = meterSource(o.home);
8247
+ const src = meterSource(o2.home);
7470
8248
  if (!src)
7471
8249
  return [];
7472
- return events.map((e) => postSeatWall({ ...src, fetchFn: o.fetchFn, timeoutMs: o.timeoutMs ?? SEAT_POST_TIMEOUT_MS }, {
8250
+ return events.map((e) => postSeatWall({ ...src, fetchFn: o2.fetchFn, timeoutMs: o2.timeoutMs ?? SEAT_POST_TIMEOUT_MS }, {
7473
8251
  bar: e.bar,
7474
8252
  stage: e.stage,
7475
8253
  usedPct: e.usedPct,
@@ -7491,7 +8269,7 @@ function sumTranscript(text) {
7491
8269
  let sub = 0;
7492
8270
  let messages = 0;
7493
8271
  const byModel = new Map;
7494
- const agents = new Set;
8272
+ const agents2 = new Set;
7495
8273
  let anySidechain = false;
7496
8274
  for (const line of text.split(`
7497
8275
  `)) {
@@ -7521,14 +8299,14 @@ function sumTranscript(text) {
7521
8299
  const cacheRead = n(u.cache_read_input_tokens);
7522
8300
  const cacheWrite = n(u.cache_creation_input_tokens);
7523
8301
  messages++;
7524
- const model = typeof m.model === "string" ? m.model : undefined;
7525
- if (model)
7526
- byModel.set(model, (byModel.get(model) ?? 0) + output);
8302
+ const model2 = typeof m.model === "string" ? m.model : undefined;
8303
+ if (model2)
8304
+ byModel.set(model2, (byModel.get(model2) ?? 0) + output);
7527
8305
  if (j.isSidechain === true) {
7528
8306
  anySidechain = true;
7529
8307
  sub += input + output + cacheRead + cacheWrite;
7530
8308
  if (typeof j.agentId === "string")
7531
- agents.add(j.agentId);
8309
+ agents2.add(j.agentId);
7532
8310
  } else {
7533
8311
  turn.input += input;
7534
8312
  turn.output += output;
@@ -7546,7 +8324,7 @@ function sumTranscript(text) {
7546
8324
  subagentTokens: sub,
7547
8325
  messages,
7548
8326
  ...model ? { model } : {},
7549
- subagentRuns: agents.size > 0 ? agents.size : anySidechain ? 1 : 0
8327
+ subagentRuns: agents2.size > 0 ? agents2.size : anySidechain ? 1 : 0
7550
8328
  };
7551
8329
  }
7552
8330
  function sessionBody(sessionId, sum, a) {
@@ -7568,15 +8346,15 @@ function sessionBody(sessionId, sum, a) {
7568
8346
 
7569
8347
  // src/commands/stopEvent.ts
7570
8348
  var SESSION_POST_TIMEOUT_MS = 2500;
7571
- async function postTranscript(o, payload, now) {
8349
+ async function postTranscript(o2, payload, now) {
7572
8350
  const sessionId = payload.session_id?.trim();
7573
8351
  const path = payload.transcript_path?.trim();
7574
8352
  if (!sessionId || !path)
7575
8353
  return false;
7576
- const src = meterSource(o.home);
8354
+ const src = meterSource(o2.home);
7577
8355
  if (!src)
7578
8356
  return false;
7579
- const read = o.readFile ?? ((p) => existsSync14(p) ? readFileSync12(p, "utf8") : null);
8357
+ const read = o2.readFile ?? ((p2) => existsSync14(p2) ? readFileSync12(p2, "utf8") : null);
7580
8358
  let text;
7581
8359
  try {
7582
8360
  text = read(path);
@@ -7588,7 +8366,7 @@ async function postTranscript(o, payload, now) {
7588
8366
  const sum = sumTranscript(text);
7589
8367
  if (sum.messages === 0)
7590
8368
  return false;
7591
- const fetchFn = o.fetchFn ?? fetch;
8369
+ const fetchFn = o2.fetchFn ?? fetch;
7592
8370
  try {
7593
8371
  const res = await fetchFn(`${src.proxyUrl.replace(/\/+$/, "")}/proxy/sessions`, {
7594
8372
  method: "POST",
@@ -7616,24 +8394,24 @@ function stopReason(rows) {
7616
8394
  function decideStop(a) {
7617
8395
  if (a.stopHookActive || !a.sessionId)
7618
8396
  return { block: false };
7619
- const due = owedBySession(a.rows, a.sessionId);
7620
- if (due.length === 0)
8397
+ const due2 = owedBySession(a.rows, a.sessionId);
8398
+ if (due2.length === 0)
7621
8399
  return { block: false };
7622
8400
  return {
7623
8401
  block: true,
7624
- reason: stopReason(due),
7625
- rows: markAsked(a.rows, due.map((r) => r.key), a.now)
8402
+ reason: stopReason(due2),
8403
+ rows: markAsked(a.rows, due2.map((r) => r.key), a.now)
7626
8404
  };
7627
8405
  }
7628
- var stopEvent = async (o) => {
7629
- const log = o.log ?? console.log;
7630
- const now = (o.now ?? Date.now)();
7631
- const raw = o.stdin ?? await readStdin(HOOK_STDIN_TIMEOUT_MS);
8406
+ var stopEvent = async (o2) => {
8407
+ const log = o2.log ?? console.log;
8408
+ const now = (o2.now ?? Date.now)();
8409
+ const raw = o2.stdin ?? await readStdin(HOOK_STDIN_TIMEOUT_MS);
7632
8410
  const payload = parseStopPayload(raw);
7633
- await postTranscript(o, payload, now);
8411
+ await postTranscript(o2, payload, now);
7634
8412
  let rows;
7635
8413
  try {
7636
- rows = readOwed(o.home, now);
8414
+ rows = readOwed(o2.home, now);
7637
8415
  } catch {
7638
8416
  return 0;
7639
8417
  }
@@ -7646,7 +8424,7 @@ var stopEvent = async (o) => {
7646
8424
  if (!d.block)
7647
8425
  return 0;
7648
8426
  try {
7649
- writeOwed(o.home, d.rows);
8427
+ writeOwed(o2.home, d.rows);
7650
8428
  } catch {}
7651
8429
  log(JSON.stringify({ decision: "block", reason: d.reason }));
7652
8430
  return 0;
@@ -7663,7 +8441,7 @@ import { dirname as dirname6, join as join12 } from "node:path";
7663
8441
  var PROVIDER_ID2 = "sleds";
7664
8442
  var codexDir2 = (home) => join12(home, ".codex");
7665
8443
  var codexConfigPath2 = (home) => join12(codexDir2(home), "config.toml");
7666
- function removeCodexProvider2(toml, o = {}) {
8444
+ function removeCodexProvider2(toml, o2 = {}) {
7667
8445
  const lines = toml.split(`
7668
8446
  `);
7669
8447
  const out = [];
@@ -7676,7 +8454,7 @@ function removeCodexProvider2(toml, o = {}) {
7676
8454
  }
7677
8455
  let text = out.join(`
7678
8456
  `);
7679
- if (!o.keepPrior) {
8457
+ if (!o2.keepPrior) {
7680
8458
  const prior = text.match(/^# sleds-prior-model-provider = "([^"]*)"\s*\n/m);
7681
8459
  if (prior) {
7682
8460
  text = text.replace(prior[0], "");
@@ -7708,72 +8486,72 @@ init_settings();
7708
8486
  var defaultUnload = (plist) => {
7709
8487
  spawnSync5("launchctl", ["unload", plist], { stdio: "ignore" });
7710
8488
  };
7711
- var uninstall2 = (o) => {
7712
- const codexLine = uninstallCodex(o.home);
8489
+ var uninstall2 = (o2) => {
8490
+ const codexLine = uninstallCodex(o2.home);
7713
8491
  if (codexLine)
7714
- (o.log ?? console.log)(` ${codexLine}`);
7715
- const log = o.log ?? console.log;
8492
+ (o2.log ?? console.log)(` ${codexLine}`);
8493
+ const log = o2.log ?? console.log;
7716
8494
  const removed = [];
7717
- if (existsSync16(settingsPath(o.home))) {
7718
- let settings = readSettings(o.home);
8495
+ if (existsSync16(settingsPath(o2.home))) {
8496
+ let settings = readSettings(o2.home);
7719
8497
  let changed = false;
7720
8498
  if (hasEitherKey(settings)) {
7721
8499
  settings = removeProxy(settings);
7722
8500
  changed = true;
7723
- removed.push(`env.ANTHROPIC_BASE_URL and env.ANTHROPIC_AUTH_TOKEN from ${settingsPath(o.home)}`);
8501
+ removed.push(`env.ANTHROPIC_BASE_URL and env.ANTHROPIC_AUTH_TOKEN from ${settingsPath(o2.home)}`);
7724
8502
  }
7725
8503
  if (isSledsStatusLine(settings[STATUS_LINE_KEY])) {
7726
- const cfg = readConfig(o.home);
8504
+ const cfg = readConfig(o2.home);
7727
8505
  settings = removeStatusLine(settings, cfg.priorStatusLine);
7728
8506
  changed = true;
7729
- removed.push(cfg.priorStatusLine === undefined ? `statusLine from ${settingsPath(o.home)}` : `statusLine from ${settingsPath(o.home)} (previous one restored)`);
8507
+ removed.push(cfg.priorStatusLine === undefined ? `statusLine from ${settingsPath(o2.home)}` : `statusLine from ${settingsPath(o2.home)} (previous one restored)`);
7730
8508
  if (cfg.priorStatusLine !== undefined) {
7731
8509
  const { priorStatusLine: _restored, ...rest } = cfg;
7732
- writeConfig(o.home, rest);
8510
+ writeConfig(o2.home, rest);
7733
8511
  }
7734
8512
  }
7735
8513
  if (hasSeatHook(settings)) {
7736
8514
  settings = removeSeatHook(settings);
7737
8515
  changed = true;
7738
- removed.push(`hooks.Notification seat-event entry from ${settingsPath(o.home)}`);
8516
+ removed.push(`hooks.Notification seat-event entry from ${settingsPath(o2.home)}`);
7739
8517
  }
7740
8518
  if (hasPromptHook(settings)) {
7741
8519
  settings = removePromptHook(settings);
7742
8520
  changed = true;
7743
- removed.push(`hooks.UserPromptSubmit prompt-event entry from ${settingsPath(o.home)}`);
8521
+ removed.push(`hooks.UserPromptSubmit prompt-event entry from ${settingsPath(o2.home)}`);
7744
8522
  }
7745
8523
  if (hasSpecHook(settings)) {
7746
8524
  settings = removeSpecHook(settings);
7747
8525
  changed = true;
7748
- removed.push(`hooks.PostToolUse spec-event entry from ${settingsPath(o.home)}`);
8526
+ removed.push(`hooks.PostToolUse spec-event entry from ${settingsPath(o2.home)}`);
7749
8527
  }
7750
8528
  if (hasSessionHook(settings)) {
7751
8529
  settings = removeSessionHook(settings);
7752
8530
  changed = true;
7753
- removed.push(`hooks.SessionStart session-event entry from ${settingsPath(o.home)}`);
8531
+ removed.push(`hooks.SessionStart session-event entry from ${settingsPath(o2.home)}`);
7754
8532
  }
7755
8533
  if (hasStopHook(settings)) {
7756
8534
  settings = removeStopHook(settings);
7757
8535
  changed = true;
7758
- removed.push(`hooks.Stop stop-event entry from ${settingsPath(o.home)}`);
8536
+ removed.push(`hooks.Stop stop-event entry from ${settingsPath(o2.home)}`);
7759
8537
  }
7760
8538
  if (changed)
7761
- writeSettings(o.home, settings);
8539
+ writeSettings(o2.home, settings);
7762
8540
  }
7763
- for (const file of [meterCachePath(o.home), seatStatePath(o.home)]) {
8541
+ for (const file of [meterCachePath(o2.home), seatStatePath(o2.home)]) {
7764
8542
  if (existsSync16(file)) {
7765
8543
  rmSync5(file, { force: true });
7766
8544
  removed.push(file);
7767
8545
  }
7768
8546
  }
7769
- const skill = skillDir(o.home);
8547
+ const skill = skillDir(o2.home);
7770
8548
  if (existsSync16(skill)) {
7771
8549
  rmSync5(skill, { recursive: true, force: true });
7772
8550
  removed.push(skill);
7773
8551
  }
7774
- const plist = musherPlistPath(o.home);
8552
+ const plist = musherPlistPath(o2.home);
7775
8553
  if (existsSync16(plist)) {
7776
- (o.unloadAgent ?? defaultUnload)(plist);
8554
+ (o2.unloadAgent ?? defaultUnload)(plist);
7777
8555
  rmSync5(plist, { force: true });
7778
8556
  removed.push(`launchd agent ${musherLabel()}`);
7779
8557
  }
@@ -7784,7 +8562,7 @@ var uninstall2 = (o) => {
7784
8562
  for (const r of removed)
7785
8563
  log(` ${r}`);
7786
8564
  }
7787
- log(`Kept ${tokenPath(o.home)} (delete it yourself if you want the token gone).`);
8565
+ log(`Kept ${tokenPath(o2.home)} (delete it yourself if you want the token gone).`);
7788
8566
  return 0;
7789
8567
  };
7790
8568
  var hasEitherKey = (settings) => {
@@ -7803,17 +8581,17 @@ var jobIdFromTarget = (target) => {
7803
8581
  return m[1];
7804
8582
  return /^[A-Za-z0-9_-]{3,64}$/.test(t) ? t : null;
7805
8583
  };
7806
- var verify = async (o) => {
7807
- const log = o.log ?? console.log;
7808
- const error = o.error ?? console.error;
7809
- const jobId = o.target ? jobIdFromTarget(o.target) : null;
8584
+ var verify = async (o2) => {
8585
+ const log = o2.log ?? console.log;
8586
+ const error = o2.error ?? console.error;
8587
+ const jobId = o2.target ? jobIdFromTarget(o2.target) : null;
7810
8588
  if (!jobId) {
7811
8589
  error("usage: sleds verify <jobId> (or paste the SLEDS-Attest line)");
7812
8590
  return 2;
7813
8591
  }
7814
- const client = o.client ?? (() => {
7815
- const src = meterSource(o.home);
7816
- return src ? musherClient({ ...src, fetchFn: o.fetchFn }) : null;
8592
+ const client = o2.client ?? (() => {
8593
+ const src = meterSource(o2.home);
8594
+ return src ? musherClient({ ...src, fetchFn: o2.fetchFn }) : null;
7817
8595
  })();
7818
8596
  if (!client) {
7819
8597
  error("No seat on this machine. Run `sleds init` first.");
@@ -7847,8 +8625,8 @@ init_settings();
7847
8625
  import { chmodSync as chmodSync2, existsSync as existsSync17, mkdirSync as mkdirSync13, readFileSync as readFileSync14, renameSync as renameSync6, writeFileSync as writeFileSync13 } from "node:fs";
7848
8626
  import { join as join13, resolve as resolve4 } from "node:path";
7849
8627
  var configDir2 = (home, env = process.env) => {
7850
- const o = env.SLEDS_HOME?.trim();
7851
- return o ? resolve4(home, o) : join13(home, ".config", "sleds");
8628
+ const o2 = env.SLEDS_HOME?.trim();
8629
+ return o2 ? resolve4(home, o2) : join13(home, ".config", "sleds");
7852
8630
  };
7853
8631
  var configPath2 = (home) => join13(configDir2(home), "config.json");
7854
8632
  var isObject13 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
@@ -7907,9 +8685,9 @@ var parseConfig2 = (raw) => {
7907
8685
  const org = parseOrgInfo2(raw.org);
7908
8686
  if (org)
7909
8687
  cfg.org = org;
7910
- const musher = parseMusher2(raw.musher);
7911
- if (musher)
7912
- cfg.musher = musher;
8688
+ const musher2 = parseMusher2(raw.musher);
8689
+ if (musher2)
8690
+ cfg.musher = musher2;
7913
8691
  return cfg;
7914
8692
  };
7915
8693
  var parseMusher2 = (raw) => {
@@ -7932,16 +8710,16 @@ var parseOrgInfo2 = (raw) => {
7932
8710
  if (!isObject13(raw) || !isObject13(raw.capabilities))
7933
8711
  return;
7934
8712
  const name = optString2(raw.name);
7935
- const slug = optString2(raw.slug);
7936
- const plan = raw.plan;
8713
+ const slug2 = optString2(raw.slug);
8714
+ const plan2 = raw.plan;
7937
8715
  const c = raw.capabilities;
7938
8716
  const src = c.upstreamSource;
7939
- if (name === undefined || slug === undefined || plan !== "team" && plan !== "enterprise" && plan !== "api" && plan !== "individual" || src !== "own" && src !== "shared" && src !== "none")
8717
+ if (name === undefined || slug2 === undefined || plan2 !== "team" && plan2 !== "enterprise" && plan2 !== "api" && plan2 !== "individual" || src !== "own" && src !== "shared" && src !== "none")
7940
8718
  return;
7941
8719
  return {
7942
8720
  name,
7943
- slug,
7944
- plan,
8721
+ slug: slug2,
8722
+ plan: plan2,
7945
8723
  capabilities: {
7946
8724
  upstreamKey: c.upstreamKey === true,
7947
8725
  adminKey: c.adminKey === true,
@@ -7952,10 +8730,10 @@ var parseOrgInfo2 = (raw) => {
7952
8730
  };
7953
8731
  };
7954
8732
  var readConfig2 = (home) => {
7955
- const p = configPath2(home);
7956
- if (!existsSync17(p))
8733
+ const p2 = configPath2(home);
8734
+ if (!existsSync17(p2))
7957
8735
  return {};
7958
- return parseConfig2(JSON.parse(readFileSync14(p, "utf8")));
8736
+ return parseConfig2(JSON.parse(readFileSync14(p2, "utf8")));
7959
8737
  };
7960
8738
 
7961
8739
  // src/schedule.ts
@@ -8092,8 +8870,8 @@ var stringFlag = (flags, name) => {
8092
8870
  var hookStdin = async () => {
8093
8871
  if (process.stdin.isTTY)
8094
8872
  return;
8095
- await Promise.resolve().then(() => init_seat());
8096
- const text = await readStdin2(300);
8873
+ const { readStdin: readStdin3 } = await Promise.resolve().then(() => (init_seat(), exports_seat));
8874
+ const text = await readStdin3(300);
8097
8875
  return text.trim() ? text : undefined;
8098
8876
  };
8099
8877
  var sledsArgv = () => {
@@ -8246,7 +9024,7 @@ ${renderHelpText(argv[1])}`);
8246
9024
  case "version":
8247
9025
  case "--version":
8248
9026
  case "-v":
8249
- console.log("sleds 0.1.25");
9027
+ console.log("sleds 0.1.26");
8250
9028
  return 0;
8251
9029
  default:
8252
9030
  console.error(`unknown command: ${cmd}