@sleds/cli 0.1.7 → 0.1.14

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 (3) hide show
  1. package/README.md +5 -2
  2. package/dist/sleds.mjs +1529 -561
  3. package/package.json +1 -1
package/dist/sleds.mjs CHANGED
@@ -1,47 +1,30 @@
1
1
  #!/usr/bin/env node
2
2
  // @bun
3
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
+ });
17
+ };
18
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
4
19
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
5
20
 
6
- // src/index.ts
7
- import { realpathSync } from "fs";
8
- import { homedir as homedir3, platform as platform2 } from "os";
9
- import { fileURLToPath } from "url";
10
-
11
- // src/commands/bar.ts
12
- import { execFileSync } from "node:child_process";
13
- import {
14
- chmodSync as chmodSync2,
15
- existsSync as existsSync5,
16
- lstatSync,
17
- mkdirSync as mkdirSync5,
18
- symlinkSync,
19
- unlinkSync,
20
- writeFileSync as writeFileSync5
21
- } from "node:fs";
22
- import { homedir } from "node:os";
23
- import { join as join5, resolve as resolve3 } from "node:path";
24
-
25
- // src/meter.ts
26
- import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync as renameSync3, writeFileSync as writeFileSync3 } from "node:fs";
27
- import { join as join3 } from "node:path";
28
-
29
- // src/config.ts
30
- import { chmodSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
31
- import { join as join2, resolve as resolve2 } from "node:path";
32
-
33
21
  // src/settings.ts
34
22
  import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
35
23
  import { dirname, join, resolve } from "node:path";
36
- var BASE_URL_KEY = "ANTHROPIC_BASE_URL";
37
- var AUTH_TOKEN_KEY = "ANTHROPIC_AUTH_TOKEN";
38
- var claudeDir = (home, env = process.env) => {
24
+ var BASE_URL_KEY = "ANTHROPIC_BASE_URL", AUTH_TOKEN_KEY = "ANTHROPIC_AUTH_TOKEN", claudeDir = (home, env = process.env) => {
39
25
  const o = env.CLAUDE_CONFIG_DIR?.trim();
40
26
  return o ? resolve(home, o) : join(home, ".claude");
41
- };
42
- var hasHomeOverride = (env = process.env) => Boolean(env.SLEDS_HOME?.trim() || env.CLAUDE_CONFIG_DIR?.trim());
43
- var settingsPath = (home) => join(claudeDir(home), "settings.json");
44
- var sledsCommand = (sub, home, env = process.env) => {
27
+ }, hasHomeOverride = (env = process.env) => Boolean(env.SLEDS_HOME?.trim() || env.CLAUDE_CONFIG_DIR?.trim()), settingsPath = (home) => join(claudeDir(home), "settings.json"), sledsCommand = (sub, home, env = process.env) => {
45
28
  const parts = [];
46
29
  const sh = env.SLEDS_HOME?.trim();
47
30
  const cc = env.CLAUDE_CONFIG_DIR?.trim();
@@ -51,8 +34,7 @@ var sledsCommand = (sub, home, env = process.env) => {
51
34
  parts.push(`CLAUDE_CONFIG_DIR=${shellWord(resolve(home, cc))}`);
52
35
  parts.push(`sleds ${sub}`);
53
36
  return parts.join(" ");
54
- };
55
- var sledsCommandsIn = (settings) => {
37
+ }, sledsCommandsIn = (settings) => {
56
38
  const out = [];
57
39
  const visit = (v) => {
58
40
  if (Array.isArray(v)) {
@@ -70,74 +52,50 @@ var sledsCommandsIn = (settings) => {
70
52
  visit(settings[STATUS_LINE_KEY]);
71
53
  visit(settings.hooks);
72
54
  return out;
73
- };
74
- var bakedHome = (command) => command.match(/(?:^|\s)SLEDS_HOME=('([^']*)'|(\S+))/)?.[2] ?? command.match(/(?:^|\s)SLEDS_HOME=(\S+)/)?.[1];
75
- var shellWord = (v) => /^[\w./~-]+$/.test(v) ? v : `'${v.replace(/'/g, "'\\''")}'`;
76
- var backupPath = (home) => join(claudeDir(home), "settings.json.sleds-backup");
77
- var tokenPath = (home, env = process.env) => {
55
+ }, 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) => {
78
56
  const o = env.SLEDS_HOME?.trim();
79
57
  return o ? join(resolve(home, o), ".sleds-token") : join(home, ".sleds-token");
80
- };
81
- var skillDir = (home) => join(claudeDir(home), "skills", "sled");
82
- var skillPath = (home) => join(skillDir(home), "SKILL.md");
83
- var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
84
- var envOf = (settings) => {
58
+ }, skillDir = (home) => join(claudeDir(home), "skills", "sled"), skillPath = (home) => join(skillDir(home), "SKILL.md"), isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v), envOf = (settings) => {
85
59
  const env = settings.env;
86
60
  return isObject(env) ? env : {};
87
- };
88
- var applyProxy = (settings, cfg) => ({
61
+ }, applyProxy = (settings, cfg) => ({
89
62
  ...settings,
90
63
  env: { ...envOf(settings), [BASE_URL_KEY]: cfg.url, [AUTH_TOKEN_KEY]: cfg.token }
91
- });
92
- var removeProxy = (settings) => {
64
+ }), removeProxy = (settings) => {
93
65
  if (!isObject(settings.env))
94
66
  return { ...settings };
95
67
  const { [BASE_URL_KEY]: _url, [AUTH_TOKEN_KEY]: _token, ...rest } = settings.env;
96
68
  return { ...settings, env: rest };
97
- };
98
- var readProxy = (settings) => {
69
+ }, readProxy = (settings) => {
99
70
  const env = envOf(settings);
100
71
  const url = env[BASE_URL_KEY];
101
72
  const token = env[AUTH_TOKEN_KEY];
102
73
  if (typeof url !== "string" || typeof token !== "string")
103
74
  return null;
104
75
  return { url, token };
105
- };
106
- var STATUS_LINE_KEY = "statusLine";
107
- var statusLineEntry = (command) => ({ type: "command", command });
108
- var isSledsStatusLine = (value) => isObject(value) && value.type === "command" && typeof value.command === "string" && /\bstatusline\b/.test(value.command);
109
- var applyStatusLine = (settings, command) => {
76
+ }, STATUS_LINE_KEY = "statusLine", statusLineEntry = (command) => ({ type: "command", command }), isSledsStatusLine = (value) => isObject(value) && value.type === "command" && typeof value.command === "string" && /\bstatusline\b/.test(value.command), applyStatusLine = (settings, command) => {
110
77
  const current = settings[STATUS_LINE_KEY];
111
78
  const prior = current === undefined || isSledsStatusLine(current) ? undefined : current;
112
79
  return { settings: { ...settings, [STATUS_LINE_KEY]: statusLineEntry(command) }, prior };
113
- };
114
- var removeStatusLine = (settings, prior) => {
80
+ }, removeStatusLine = (settings, prior) => {
115
81
  if (!isSledsStatusLine(settings[STATUS_LINE_KEY]))
116
82
  return { ...settings };
117
83
  const { [STATUS_LINE_KEY]: _ours, ...rest } = settings;
118
84
  return prior === undefined ? rest : { ...rest, [STATUS_LINE_KEY]: prior };
119
- };
120
- var HOOKS_KEY = "hooks";
121
- var NOTIFICATION_EVENT = "Notification";
122
- var SEAT_EVENT_MATCHER = "quota_auto_resume_fired|quota_auto_resume_stale|quota_auto_resume_disabled";
123
- var SEAT_EVENT_TIMEOUT_S = 10;
124
- var isSledsSeatHook = (entry) => {
85
+ }, HOOKS_KEY = "hooks", NOTIFICATION_EVENT = "Notification", SEAT_EVENT_MATCHER = "quota_auto_resume_fired|quota_auto_resume_stale|quota_auto_resume_disabled", SEAT_EVENT_TIMEOUT_S = 10, isSledsSeatHook = (entry) => {
125
86
  if (!isObject(entry) || !Array.isArray(entry.hooks))
126
87
  return false;
127
88
  return entry.hooks.some((h) => isObject(h) && h.type === "command" && typeof h.command === "string" && /\bseat-event\b/.test(h.command));
128
- };
129
- var seatHookEntry = (command) => ({
89
+ }, seatHookEntry = (command) => ({
130
90
  matcher: SEAT_EVENT_MATCHER,
131
91
  hooks: [{ type: "command", command, timeout: SEAT_EVENT_TIMEOUT_S }]
132
- });
133
- var notificationHooks = (settings) => {
92
+ }), notificationHooks = (settings) => {
134
93
  const hooks = settings[HOOKS_KEY];
135
94
  if (!isObject(hooks))
136
95
  return [];
137
96
  const list = hooks[NOTIFICATION_EVENT];
138
97
  return Array.isArray(list) ? list : [];
139
- };
140
- var withNotificationHooks = (settings, list) => {
98
+ }, withNotificationHooks = (settings, list) => {
141
99
  const hooks = isObject(settings[HOOKS_KEY]) ? settings[HOOKS_KEY] : {};
142
100
  if (list.length === 0) {
143
101
  const { [NOTIFICATION_EVENT]: _gone, ...restHooks } = hooks;
@@ -148,41 +106,31 @@ var withNotificationHooks = (settings, list) => {
148
106
  return { ...settings, [HOOKS_KEY]: restHooks };
149
107
  }
150
108
  return { ...settings, [HOOKS_KEY]: { ...hooks, [NOTIFICATION_EVENT]: list } };
151
- };
152
- var applySeatHook = (settings, command) => {
109
+ }, applySeatHook = (settings, command) => {
153
110
  const list = notificationHooks(settings);
154
111
  const idx = list.findIndex(isSledsSeatHook);
155
112
  const entry = seatHookEntry(command);
156
113
  const next = idx === -1 ? [...list, entry] : list.map((e, i) => i === idx ? entry : e);
157
114
  return withNotificationHooks(settings, next);
158
- };
159
- var removeSeatHook = (settings) => {
115
+ }, removeSeatHook = (settings) => {
160
116
  const list = notificationHooks(settings);
161
117
  if (!list.some(isSledsSeatHook))
162
118
  return { ...settings };
163
119
  return withNotificationHooks(settings, list.filter((e) => !isSledsSeatHook(e)));
164
- };
165
- var hasSeatHook = (settings) => notificationHooks(settings).some(isSledsSeatHook);
166
- var POST_TOOL_EVENT = "PostToolUse";
167
- var SPEC_EVENT_MATCHER = "Write|Edit|MultiEdit";
168
- var SPEC_EVENT_TIMEOUT_S = 5;
169
- var isSledsSpecHook = (entry) => {
120
+ }, hasSeatHook = (settings) => notificationHooks(settings).some(isSledsSeatHook), POST_TOOL_EVENT = "PostToolUse", SPEC_EVENT_MATCHER = "Write|Edit|MultiEdit", SPEC_EVENT_TIMEOUT_S = 5, isSledsSpecHook = (entry) => {
170
121
  if (!isObject(entry) || !Array.isArray(entry.hooks))
171
122
  return false;
172
123
  return entry.hooks.some((h) => isObject(h) && h.type === "command" && typeof h.command === "string" && /\bspec-event\b/.test(h.command));
173
- };
174
- var specHookEntry = (command) => ({
124
+ }, specHookEntry = (command) => ({
175
125
  matcher: SPEC_EVENT_MATCHER,
176
126
  hooks: [{ type: "command", command, timeout: SPEC_EVENT_TIMEOUT_S }]
177
- });
178
- var eventHooks = (settings, event) => {
127
+ }), eventHooks = (settings, event) => {
179
128
  const hooks = settings[HOOKS_KEY];
180
129
  if (!isObject(hooks))
181
130
  return [];
182
131
  const list = hooks[event];
183
132
  return Array.isArray(list) ? list : [];
184
- };
185
- var withEventHooks = (settings, event, list) => {
133
+ }, withEventHooks = (settings, event, list) => {
186
134
  const hooks = isObject(settings[HOOKS_KEY]) ? settings[HOOKS_KEY] : {};
187
135
  if (list.length === 0) {
188
136
  const { [event]: _gone, ...restHooks } = hooks;
@@ -193,27 +141,19 @@ var withEventHooks = (settings, event, list) => {
193
141
  return { ...settings, [HOOKS_KEY]: restHooks };
194
142
  }
195
143
  return { ...settings, [HOOKS_KEY]: { ...hooks, [event]: list } };
196
- };
197
- var applySpecHook = (settings, command) => {
144
+ }, applySpecHook = (settings, command) => {
198
145
  const list = eventHooks(settings, POST_TOOL_EVENT);
199
146
  const idx = list.findIndex(isSledsSpecHook);
200
147
  const entry = specHookEntry(command);
201
148
  const next = idx === -1 ? [...list, entry] : list.map((e, i) => i === idx ? entry : e);
202
149
  return withEventHooks(settings, POST_TOOL_EVENT, next);
203
- };
204
- var removeSpecHook = (settings) => {
150
+ }, removeSpecHook = (settings) => {
205
151
  const list = eventHooks(settings, POST_TOOL_EVENT);
206
152
  if (!list.some(isSledsSpecHook))
207
153
  return { ...settings };
208
154
  return withEventHooks(settings, POST_TOOL_EVENT, list.filter((e) => !isSledsSpecHook(e)));
209
- };
210
- var hasSpecHook = (settings) => eventHooks(settings, POST_TOOL_EVENT).some(isSledsSpecHook);
211
- var isSeatToken = (token) => /^sled_[A-Za-z0-9_-]+$/.test(token);
212
- var maskToken = (token) => token.length <= 9 ? `${token.slice(0, 5)}…` : `${token.slice(0, 9)}…`;
213
- var serialize = (settings) => `${JSON.stringify(settings, null, 2)}
214
- `;
215
- var hasClaudeCode = (home) => existsSync(claudeDir(home));
216
- var readSettings = (home) => {
155
+ }, hasSpecHook = (settings) => eventHooks(settings, POST_TOOL_EVENT).some(isSledsSpecHook), 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)}
156
+ `, hasClaudeCode = (home) => existsSync(claudeDir(home)), readSettings = (home) => {
217
157
  const p = settingsPath(home);
218
158
  if (!existsSync(p))
219
159
  return {};
@@ -221,44 +161,39 @@ var readSettings = (home) => {
221
161
  if (!isObject(parsed))
222
162
  throw new Error(`${p} is not a JSON object`);
223
163
  return parsed;
224
- };
225
- var writeSettings = (home, settings) => {
164
+ }, writeSettings = (home, settings) => {
226
165
  mkdirSync(claudeDir(home), { recursive: true });
227
166
  const target = settingsPath(home);
228
167
  const tmp = `${target}.${process.pid}.tmp`;
229
168
  writeFileSync(tmp, serialize(settings));
230
169
  renameSync(tmp, target);
231
- };
232
- var backupSettings = (home) => {
170
+ }, backupSettings = (home) => {
233
171
  const src = settingsPath(home);
234
172
  const dst = backupPath(home);
235
173
  if (!existsSync(src) || existsSync(dst))
236
174
  return false;
237
175
  writeFileSync(dst, readFileSync(src));
238
176
  return true;
239
- };
240
- var readTokenFile = (home) => {
177
+ }, readTokenFile = (home) => {
241
178
  const p = tokenPath(home);
242
179
  if (!existsSync(p))
243
180
  return null;
244
181
  const t = readFileSync(p, "utf8").trim();
245
182
  return t.length > 0 ? t : null;
246
- };
247
- var writeTokenFile = (home, token) => {
183
+ }, writeTokenFile = (home, token) => {
248
184
  mkdirSync(dirname(tokenPath(home)), { recursive: true, mode: 448 });
249
185
  writeFileSync(tokenPath(home), `${token}
250
186
  `, { mode: 384 });
251
187
  };
188
+ var init_settings = () => {};
252
189
 
253
190
  // src/config.ts
191
+ import { chmodSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
192
+ import { join as join2, resolve as resolve2 } from "node:path";
254
193
  var configDir = (home, env = process.env) => {
255
194
  const o = env.SLEDS_HOME?.trim();
256
195
  return o ? resolve2(home, o) : join2(home, ".config", "sleds");
257
- };
258
- var configPath = (home) => join2(configDir(home), "config.json");
259
- var isObject2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
260
- var optString = (v) => typeof v === "string" ? v : undefined;
261
- var parsePriorEnv = (v) => {
196
+ }, configPath = (home) => join2(configDir(home), "config.json"), isObject2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), optString = (v) => typeof v === "string" ? v : undefined, parsePriorEnv = (v) => {
262
197
  if (!isObject2(v))
263
198
  return;
264
199
  const out = {};
@@ -271,9 +206,7 @@ var parsePriorEnv = (v) => {
271
206
  if (typeof v.hadEnv === "boolean")
272
207
  out.hadEnv = v.hadEnv;
273
208
  return out;
274
- };
275
- var parseSchedule = (v) => v === "launchd" || v === "systemd" || v === "manual" ? v : undefined;
276
- var parseConfig = (raw) => {
209
+ }, parseSchedule = (v) => v === "launchd" || v === "systemd" || v === "manual" ? v : undefined, parseConfig = (raw) => {
277
210
  if (!isObject2(raw))
278
211
  return {};
279
212
  const cfg = {};
@@ -305,15 +238,58 @@ var parseConfig = (raw) => {
305
238
  cfg.schedule = schedule;
306
239
  if (raw.priorStatusLine !== undefined)
307
240
  cfg.priorStatusLine = raw.priorStatusLine;
241
+ if (raw.wiring === "seat-first" || raw.wiring === "proxy-always")
242
+ cfg.wiring = raw.wiring;
243
+ const org = parseOrgInfo(raw.org);
244
+ if (org)
245
+ cfg.org = org;
246
+ const musher = parseMusher(raw.musher);
247
+ if (musher)
248
+ cfg.musher = musher;
308
249
  return cfg;
309
- };
310
- var readConfig = (home) => {
250
+ }, parseMusher = (raw) => {
251
+ if (!isObject2(raw))
252
+ return;
253
+ const out = {};
254
+ const pm = optString(raw.permissionMode);
255
+ const cp = optString(raw.claudePath);
256
+ if (pm)
257
+ out.permissionMode = pm;
258
+ if (cp)
259
+ out.claudePath = cp;
260
+ if (typeof raw.timeoutMinutes === "number" && raw.timeoutMinutes > 0)
261
+ out.timeoutMinutes = raw.timeoutMinutes;
262
+ if (raw.agent === "launchd" || raw.agent === "none")
263
+ out.agent = raw.agent;
264
+ return out;
265
+ }, parseOrgInfo = (raw) => {
266
+ if (!isObject2(raw) || !isObject2(raw.capabilities))
267
+ return;
268
+ const name = optString(raw.name);
269
+ const slug = optString(raw.slug);
270
+ const plan = raw.plan;
271
+ const c = raw.capabilities;
272
+ const src = c.upstreamSource;
273
+ if (name === undefined || slug === undefined || plan !== "team" && plan !== "enterprise" && plan !== "api" && plan !== "individual" || src !== "own" && src !== "shared" && src !== "none")
274
+ return;
275
+ return {
276
+ name,
277
+ slug,
278
+ plan,
279
+ capabilities: {
280
+ upstreamKey: c.upstreamKey === true,
281
+ adminKey: c.adminKey === true,
282
+ seats: c.seats !== false,
283
+ upstreamSource: src
284
+ },
285
+ mode: raw.mode === "proxy-always" ? "proxy-always" : "seat-first"
286
+ };
287
+ }, readConfig = (home) => {
311
288
  const p = configPath(home);
312
289
  if (!existsSync2(p))
313
290
  return {};
314
291
  return parseConfig(JSON.parse(readFileSync2(p, "utf8")));
315
- };
316
- var writeConfig = (home, cfg) => {
292
+ }, writeConfig = (home, cfg) => {
317
293
  const dir = configDir(home);
318
294
  mkdirSync2(dir, { recursive: true, mode: 448 });
319
295
  const target = configPath(home);
@@ -323,14 +299,14 @@ var writeConfig = (home, cfg) => {
323
299
  renameSync2(tmp, target);
324
300
  chmodSync(target, 384);
325
301
  };
302
+ var init_config = __esm(() => {
303
+ init_settings();
304
+ });
326
305
 
327
306
  // src/meter.ts
328
- var METER_CACHE_TTL_MS = 1e4;
329
- var METER_TIMEOUT_MS = 1500;
330
- var isObject3 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
331
- var num = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined;
332
- var str = (v) => typeof v === "string" ? v : undefined;
333
- var parseMeter = (raw) => {
307
+ import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync as renameSync3, writeFileSync as writeFileSync3 } from "node:fs";
308
+ import { join as join3 } from "node:path";
309
+ var METER_CACHE_TTL_MS = 1e4, METER_TIMEOUT_MS = 1500, isObject3 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), num = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined, str = (v) => typeof v === "string" ? v : undefined, parseMeter = (raw) => {
334
310
  if (!isObject3(raw))
335
311
  return null;
336
312
  const seat = isObject3(raw.seat) ? str(raw.seat.email) : undefined;
@@ -385,18 +361,15 @@ var parseMeter = (raw) => {
385
361
  if (acc !== undefined)
386
362
  out.estimateAccuracyPct = acc;
387
363
  return out;
388
- };
389
- var usd = (n) => {
364
+ }, usd = (n) => {
390
365
  const abs = Math.abs(n);
391
366
  if (abs >= 1000)
392
367
  return `${n < 0 ? "-" : ""}$${Math.round(abs).toLocaleString("en-US")}`;
393
368
  return `${n < 0 ? "-" : ""}$${abs.toFixed(2)}`;
394
- };
395
- var usdRange = (low, high) => {
369
+ }, usdRange = (low, high) => {
396
370
  const d = high >= 10 ? 0 : 2;
397
371
  return `$${low.toFixed(d)}–${high.toFixed(d)}`;
398
- };
399
- var shortDuration = (ms) => {
372
+ }, shortDuration = (ms) => {
400
373
  const total = Math.max(0, Math.round(ms / 60000));
401
374
  const d = Math.floor(total / (24 * 60));
402
375
  const h = Math.floor(total % (24 * 60) / 60);
@@ -406,18 +379,7 @@ var shortDuration = (ms) => {
406
379
  if (h > 0)
407
380
  return `${h}h${String(m).padStart(2, "0")}m`;
408
381
  return `${m}m`;
409
- };
410
- var KIND_WORDS = {
411
- rate_limit: "rate limit hit",
412
- weekly_cap: "usage limit reached",
413
- budget: "budget exhausted",
414
- provider_down: "provider unavailable"
415
- };
416
- var kindInWords = (kind) => KIND_WORDS[kind] ?? kind.replace(/_/g, " ");
417
- var SEP = " · ";
418
- var PREFIX = "sleds ";
419
- var OFFLINE_LINE = `${PREFIX}offline`;
420
- var jobParts = (m) => {
382
+ }, KIND_WORDS, kindInWords = (kind) => KIND_WORDS[kind] ?? kind.replace(/_/g, " "), SEP = " · ", PREFIX = "sleds ", OFFLINE_LINE, jobParts = (m) => {
421
383
  const parts = [];
422
384
  const [low, high] = m.jobs.queuedEstimateUsd;
423
385
  if (m.jobs.queued > 0) {
@@ -429,8 +391,7 @@ var jobParts = (m) => {
429
391
  if (m.jobs.deliveredToday > 0)
430
392
  parts.push(`${m.jobs.deliveredToday} delivered`);
431
393
  return parts;
432
- };
433
- var formatMeterLine = (m, now, seatFragment = null) => {
394
+ }, formatMeterLine = (m, now, seatFragment = null) => {
434
395
  if (!m)
435
396
  return seatFragment ? `${OFFLINE_LINE}${SEP}${seatFragment}` : OFFLINE_LINE;
436
397
  const parts = [`${usd(m.today.spentUsd)} today`];
@@ -445,10 +406,7 @@ var formatMeterLine = (m, now, seatFragment = null) => {
445
406
  parts.push(`allowance ${usd(m.allowance.remainingUsd)}`);
446
407
  parts.push(...jobParts(m));
447
408
  return `${PREFIX}${parts.join(SEP)}`;
448
- };
449
- var row = (label, value) => `${label.padEnd(12)}${value}`;
450
- var plural = (n, word) => `${n} ${word}${n === 1 ? "" : "s"}`;
451
- var formatMeter = (m, now) => {
409
+ }, row = (label, value) => `${label.padEnd(12)}${value}`, plural = (n, word) => `${n} ${word}${n === 1 ? "" : "s"}`, formatMeter = (m, now) => {
452
410
  const lines = [row("Seat:", m.seat.email)];
453
411
  lines.push(row("Built today:", `${usd(m.today.spentUsd)}${SEP}${plural(m.today.requests, "request")}`));
454
412
  lines.push(row("Month:", m.month.ceilingUsd !== undefined ? `${usd(m.month.spentUsd)} of ${usd(m.month.ceilingUsd)} ceiling` : usd(m.month.spentUsd)));
@@ -472,9 +430,7 @@ var formatMeter = (m, now) => {
472
430
  if (m.estimateAccuracyPct !== undefined)
473
431
  lines.push(row("Estimates:", `${Math.round(m.estimateAccuracyPct)}% landed in band`));
474
432
  return lines;
475
- };
476
- var meterCachePath = (home) => join3(configDir(home), "meter.json");
477
- var readMeterCache = (home, now) => {
433
+ }, meterCachePath = (home) => join3(configDir(home), "meter.json"), readMeterCache = (home, now) => {
478
434
  const p = meterCachePath(home);
479
435
  if (!existsSync3(p))
480
436
  return null;
@@ -489,8 +445,7 @@ var readMeterCache = (home, now) => {
489
445
  } catch {
490
446
  return null;
491
447
  }
492
- };
493
- var writeMeterCache = (home, meter, now) => {
448
+ }, writeMeterCache = (home, meter, now) => {
494
449
  const dir = configDir(home);
495
450
  mkdirSync3(dir, { recursive: true, mode: 448 });
496
451
  const target = meterCachePath(home);
@@ -499,8 +454,7 @@ var writeMeterCache = (home, meter, now) => {
499
454
  writeFileSync3(tmp, `${JSON.stringify(file)}
500
455
  `, { mode: 384 });
501
456
  renameSync3(tmp, target);
502
- };
503
- var fetchMeter = async (o) => {
457
+ }, fetchMeter = async (o) => {
504
458
  const fetchFn = o.fetchFn ?? fetch;
505
459
  try {
506
460
  const res = await fetchFn(`${o.proxyUrl}/proxy/meter`, {
@@ -513,16 +467,14 @@ var fetchMeter = async (o) => {
513
467
  } catch {
514
468
  return null;
515
469
  }
516
- };
517
- var meterSource = (home) => {
470
+ }, meterSource = (home) => {
518
471
  const cfg = readConfig(home);
519
472
  const settings = existsSync3(settingsPath(home)) ? readSettings(home) : {};
520
473
  const inSettings = readProxy(settings);
521
474
  const proxyUrl = inSettings?.url ?? cfg.proxyUrl;
522
475
  const token = inSettings?.token ?? cfg.token;
523
476
  return proxyUrl && token ? { proxyUrl, token } : null;
524
- };
525
- var loadMeter = async (o) => {
477
+ }, loadMeter = async (o) => {
526
478
  const now = o.now ?? Date.now();
527
479
  const cached = readMeterCache(o.home, now);
528
480
  if (cached)
@@ -538,99 +490,548 @@ var loadMeter = async (o) => {
538
490
  }
539
491
  return fresh;
540
492
  };
493
+ var init_meter = __esm(() => {
494
+ init_config();
495
+ init_settings();
496
+ KIND_WORDS = {
497
+ rate_limit: "rate limit hit",
498
+ weekly_cap: "usage limit reached",
499
+ budget: "budget exhausted",
500
+ provider_down: "provider unavailable"
501
+ };
502
+ OFFLINE_LINE = `${PREFIX}offline`;
503
+ });
541
504
 
542
- // src/bar.ts
543
- var SEAT_BAR_FRESH_MS = 6 * 60 * 60 * 1000;
544
- var DASHBOARD_URL = "https://app.sleds.ai";
545
- var WARM_PCT = 75;
546
- var HOT_PCT = 90;
547
- var MONO = "font=Menlo size=12";
548
- var HOT_COLOR = "#ff453a";
549
- var WARM_COLOR = "#ff9f0a";
550
- var freshSeat = (w, now) => {
551
- if (!w)
505
+ // src/seat.ts
506
+ var exports_seat = {};
507
+ __export(exports_seat, {
508
+ SEAT_POST_MIN_DELTA_PCT: () => SEAT_POST_MIN_DELTA_PCT2,
509
+ SEAT_POST_MIN_INTERVAL_MS: () => SEAT_POST_MIN_INTERVAL_MS2,
510
+ SEAT_POST_TIMEOUT_MS: () => SEAT_POST_TIMEOUT_MS2,
511
+ SEAT_WALL_LINE: () => SEAT_WALL_LINE2,
512
+ SEAT_WALL_LINE_NO_KEY: () => SEAT_WALL_LINE_NO_KEY2,
513
+ STDIN_TIMEOUT_MS: () => STDIN_TIMEOUT_MS2,
514
+ bindingResetAt: () => bindingResetAt2,
515
+ formatSeatFragment: () => formatSeatFragment2,
516
+ markPosted: () => markPosted2,
517
+ parseResetsAt: () => parseResetsAt2,
518
+ parseSeatState: () => parseSeatState2,
519
+ parseSeatWindow: () => parseSeatWindow2,
520
+ postSeatWall: () => postSeatWall2,
521
+ postSeatWindow: () => postSeatWindow2,
522
+ readSeatState: () => readSeatState2,
523
+ readStdin: () => readStdin2,
524
+ seatSessionFromStdin: () => seatSessionFromStdin2,
525
+ seatStatePath: () => seatStatePath2,
526
+ seatWallDue: () => seatWallDue2,
527
+ seatWallLine: () => seatWallLine2,
528
+ seatWindowBody: () => seatWindowBody2,
529
+ seatWindowFromStdin: () => seatWindowFromStdin2,
530
+ shouldPostSeat: () => shouldPostSeat2,
531
+ writeSeatState: () => writeSeatState2
532
+ });
533
+ import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync10, renameSync as renameSync5, writeFileSync as writeFileSync10 } from "node:fs";
534
+ import { join as join10 } from "node:path";
535
+ var SEAT_POST_MIN_DELTA_PCT2 = 1, SEAT_POST_MIN_INTERVAL_MS2, SEAT_POST_TIMEOUT_MS2 = 1500, STDIN_TIMEOUT_MS2 = 300, isObject9 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), num5 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined, EPOCH_MS_THRESHOLD2 = 100000000000, parseResetsAt2 = (v) => {
536
+ const n = num5(v);
537
+ if (n !== undefined) {
538
+ if (n <= 0)
539
+ return;
540
+ return n >= EPOCH_MS_THRESHOLD2 ? Math.round(n) : Math.round(n * 1000);
541
+ }
542
+ if (typeof v === "string" && v.trim() !== "") {
543
+ const parsed = Date.parse(v);
544
+ return Number.isFinite(parsed) ? parsed : undefined;
545
+ }
546
+ return;
547
+ }, parseBar2 = (v) => {
548
+ if (!isObject9(v))
549
+ return;
550
+ const usedPct = num5(v.used_percentage) ?? num5(v.usedPct);
551
+ const resetsAt = parseResetsAt2(v.resets_at ?? v.resetsAt);
552
+ if (usedPct === undefined || usedPct < 0 || resetsAt === undefined)
553
+ return;
554
+ return { usedPct, resetsAt };
555
+ }, parseSeatWindow2 = (raw, capturedAt) => {
556
+ if (!isObject9(raw))
552
557
  return null;
553
- return now - w.capturedAt < SEAT_BAR_FRESH_MS ? w : null;
554
- };
555
- var modelLabel = (bucket) => bucket.replace(/^(seven_day|five_hour|weekly|daily)_/, "").toLowerCase();
556
- var seatBars = (w) => {
558
+ const limits = isObject9(raw.rate_limits) ? raw.rate_limits : raw;
559
+ const fiveHour = parseBar2(limits.five_hour ?? limits.fiveHour);
560
+ const sevenDay = parseBar2(limits.seven_day ?? limits.sevenDay);
561
+ const spendLimit = parseBar2(limits.spend_limit ?? limits.spendLimit);
562
+ const models = {};
563
+ if (isObject9(limits.models))
564
+ for (const [k, v] of Object.entries(limits.models)) {
565
+ const bar = parseBar2(v);
566
+ if (bar)
567
+ models[k] = bar;
568
+ }
569
+ const usedCreditsUsd = num5(limits.usedCreditsUsd);
570
+ const hasModels = Object.keys(models).length > 0;
571
+ if (!fiveHour && !sevenDay && !spendLimit && !hasModels && usedCreditsUsd === undefined)
572
+ return null;
573
+ const out = { capturedAt };
574
+ if (fiveHour)
575
+ out.fiveHour = fiveHour;
576
+ if (sevenDay)
577
+ out.sevenDay = sevenDay;
578
+ if (spendLimit)
579
+ out.spendLimit = spendLimit;
580
+ if (hasModels)
581
+ out.models = models;
582
+ if (usedCreditsUsd !== undefined)
583
+ out.usedCreditsUsd = usedCreditsUsd;
584
+ return out;
585
+ }, seatWindowFromStdin2 = (text, capturedAt) => {
586
+ const trimmed = text.trim();
587
+ if (!trimmed)
588
+ return null;
589
+ try {
590
+ return parseSeatWindow2(JSON.parse(trimmed), capturedAt);
591
+ } catch {
592
+ return null;
593
+ }
594
+ }, formatSeatFragment2 = (w) => {
557
595
  if (!w)
558
- return [];
559
- const out = [];
596
+ return null;
597
+ const parts = [];
560
598
  if (w.sevenDay)
561
- out.push({ label: "wk", bar: w.sevenDay });
599
+ parts.push(`wk ${Math.round(w.sevenDay.usedPct)}%`);
562
600
  if (w.fiveHour)
563
- out.push({ label: "5h", bar: w.fiveHour });
601
+ parts.push(`5h ${Math.round(w.fiveHour.usedPct)}%`);
564
602
  if (w.spendLimit)
565
- out.push({ label: "spend", bar: w.spendLimit });
566
- for (const k of Object.keys(w.models ?? {}).sort()) {
567
- const bar = w.models?.[k];
568
- if (bar)
569
- out.push({ label: modelLabel(k), bar });
603
+ parts.push(`spend ${Math.round(w.spendLimit.usedPct)}%`);
604
+ if (parts.length === 0)
605
+ return null;
606
+ return `seat ${parts.join(SEP)}`;
607
+ }, seatStatePath2 = (home) => join10(configDir(home), "seat.json"), parseWindowStored2 = (v) => {
608
+ if (!isObject9(v))
609
+ return;
610
+ const capturedAt = num5(v.capturedAt);
611
+ if (capturedAt === undefined)
612
+ return;
613
+ return parseSeatWindow2(v, capturedAt) ?? undefined;
614
+ }, parseSeatState2 = (raw) => {
615
+ if (!isObject9(raw))
616
+ return {};
617
+ const out = {};
618
+ const window = parseWindowStored2(raw.window);
619
+ if (window)
620
+ out.window = window;
621
+ const lastPostedAt = num5(raw.lastPostedAt);
622
+ if (lastPostedAt !== undefined)
623
+ out.lastPostedAt = lastPostedAt;
624
+ if (isObject9(raw.lastPosted)) {
625
+ const lp = {};
626
+ const f = num5(raw.lastPosted.fiveHour);
627
+ const s = num5(raw.lastPosted.sevenDay);
628
+ const sp = num5(raw.lastPosted.spendLimit);
629
+ if (f !== undefined)
630
+ lp.fiveHour = f;
631
+ if (s !== undefined)
632
+ lp.sevenDay = s;
633
+ if (sp !== undefined)
634
+ lp.spendLimit = sp;
635
+ out.lastPosted = lp;
570
636
  }
637
+ const lastWallResetsAt = num5(raw.lastWallResetsAt);
638
+ if (lastWallResetsAt !== undefined)
639
+ out.lastWallResetsAt = lastWallResetsAt;
640
+ const session = parseSeatSession2(raw.session);
641
+ if (session)
642
+ out.session = session;
643
+ return out;
644
+ }, parseSeatSession2 = (v) => {
645
+ if (!isObject9(v) || typeof v.id !== "string" || !v.id)
646
+ return;
647
+ const at = num5(v.at);
648
+ if (at === undefined)
649
+ return;
650
+ const out = { id: v.id, at };
651
+ if (typeof v.cwd === "string" && v.cwd)
652
+ out.cwd = v.cwd;
653
+ if (typeof v.model === "string" && v.model)
654
+ out.model = v.model;
571
655
  return out;
656
+ }, seatSessionFromStdin2 = (text, now) => {
657
+ const trimmed = text.trim();
658
+ if (!trimmed)
659
+ return null;
660
+ try {
661
+ const raw = JSON.parse(trimmed);
662
+ if (!isObject9(raw) || typeof raw.session_id !== "string" || !raw.session_id)
663
+ return null;
664
+ const out = { id: raw.session_id, at: now };
665
+ if (typeof raw.cwd === "string" && raw.cwd)
666
+ out.cwd = raw.cwd;
667
+ const model = isObject9(raw.model) ? raw.model.id : raw.model;
668
+ if (typeof model === "string" && model)
669
+ out.model = model;
670
+ return out;
671
+ } catch {
672
+ return null;
673
+ }
674
+ }, bindingResetAt2 = (w, now) => {
675
+ if (!w)
676
+ return;
677
+ const bars = [
678
+ ...w.fiveHour ? [w.fiveHour] : [],
679
+ ...w.sevenDay ? [w.sevenDay] : [],
680
+ ...w.spendLimit ? [w.spendLimit] : [],
681
+ ...Object.values(w.models ?? {})
682
+ ].filter((b) => b.resetsAt > now);
683
+ const full = bars.filter((b) => b.usedPct >= 100);
684
+ const pick = (full.length ? full : bars).map((b) => b.resetsAt);
685
+ return pick.length ? Math.min(...pick) : undefined;
686
+ }, readSeatState2 = (home) => {
687
+ const p = seatStatePath2(home);
688
+ if (!existsSync13(p))
689
+ return {};
690
+ try {
691
+ return parseSeatState2(JSON.parse(readFileSync10(p, "utf8")));
692
+ } catch {
693
+ return {};
694
+ }
695
+ }, writeSeatState2 = (home, state) => {
696
+ const dir = configDir(home);
697
+ mkdirSync10(dir, { recursive: true, mode: 448 });
698
+ const target = seatStatePath2(home);
699
+ const tmp = `${target}.${process.pid}.tmp`;
700
+ writeFileSync10(tmp, `${JSON.stringify(state)}
701
+ `, { mode: 384 });
702
+ renameSync5(tmp, target);
703
+ }, pctOf2 = (b) => b?.usedPct, shouldPostSeat2 = (state, next, now) => {
704
+ if (state.lastPostedAt === undefined || !state.lastPosted)
705
+ return true;
706
+ if (now - state.lastPostedAt >= SEAT_POST_MIN_INTERVAL_MS2)
707
+ return true;
708
+ const pairs = [
709
+ [state.lastPosted.fiveHour, pctOf2(next.fiveHour)],
710
+ [state.lastPosted.sevenDay, pctOf2(next.sevenDay)],
711
+ [state.lastPosted.spendLimit, pctOf2(next.spendLimit)]
712
+ ];
713
+ for (const [prev, cur] of pairs) {
714
+ if (prev === undefined && cur === undefined)
715
+ continue;
716
+ if (prev === undefined || cur === undefined)
717
+ return true;
718
+ if (Math.abs(cur - prev) >= SEAT_POST_MIN_DELTA_PCT2)
719
+ return true;
720
+ }
721
+ return false;
722
+ }, markPosted2 = (state, w, now) => {
723
+ const lastPosted = {};
724
+ if (w.fiveHour)
725
+ lastPosted.fiveHour = w.fiveHour.usedPct;
726
+ if (w.sevenDay)
727
+ lastPosted.sevenDay = w.sevenDay.usedPct;
728
+ if (w.spendLimit)
729
+ lastPosted.spendLimit = w.spendLimit.usedPct;
730
+ return { ...state, window: w, lastPostedAt: now, lastPosted };
731
+ }, seatWallDue2 = (state, w) => {
732
+ if (!w?.sevenDay || w.sevenDay.usedPct < 100)
733
+ return false;
734
+ return state.lastWallResetsAt === undefined || state.lastWallResetsAt < w.sevenDay.resetsAt;
735
+ }, seatWindowBody2 = (w) => ({
736
+ capturedAt: w.capturedAt,
737
+ ...w.fiveHour ? { fiveHour: w.fiveHour } : {},
738
+ ...w.sevenDay ? { sevenDay: w.sevenDay } : {},
739
+ ...w.spendLimit ? { spendLimit: w.spendLimit } : {}
740
+ }), postJson2 = async (o, path, body) => {
741
+ const fetchFn = o.fetchFn ?? fetch;
742
+ try {
743
+ const res = await fetchFn(`${o.proxyUrl}${path}`, {
744
+ method: "POST",
745
+ headers: { authorization: `Bearer ${o.token}`, "content-type": "application/json" },
746
+ body: JSON.stringify(body),
747
+ signal: AbortSignal.timeout(o.timeoutMs ?? SEAT_POST_TIMEOUT_MS2)
748
+ });
749
+ return res.ok;
750
+ } catch {
751
+ return false;
752
+ }
753
+ }, postSeatWindow2 = (o, w) => postJson2(o, "/proxy/seat", seatWindowBody2(w)), postSeatWall2 = (o, input) => postJson2(o, "/proxy/seat-wall", input), SEAT_WALL_LINE2 = "Seat limit hit. sleds on --until-reset to continue on the org key, or sleds defer to resume here at the reset.", SEAT_WALL_LINE_NO_KEY2 = "Seat limit hit. sleds defer resumes this session on this Mac at the reset; /sled 5 to hand off — this org has no platform key to switch to.", seatWallLine2 = (hasUpstreamKey) => hasUpstreamKey ? SEAT_WALL_LINE2 : SEAT_WALL_LINE_NO_KEY2, readStdin2 = (timeoutMs, stdin = process.stdin) => new Promise((resolve4) => {
754
+ if (stdin.isTTY) {
755
+ resolve4("");
756
+ return;
757
+ }
758
+ let data = "";
759
+ let settled = false;
760
+ const finish = () => {
761
+ if (settled)
762
+ return;
763
+ settled = true;
764
+ clearTimeout(timer);
765
+ resolve4(data);
766
+ };
767
+ const timer = setTimeout(finish, timeoutMs);
768
+ stdin.setEncoding("utf8");
769
+ stdin.on("data", (chunk) => {
770
+ data += chunk;
771
+ });
772
+ stdin.on("end", finish);
773
+ stdin.on("error", finish);
774
+ stdin.resume();
775
+ });
776
+ var init_seat = __esm(() => {
777
+ init_config();
778
+ init_meter();
779
+ SEAT_POST_MIN_INTERVAL_MS2 = 5 * 60000;
780
+ });
781
+
782
+ // src/index.ts
783
+ import { realpathSync } from "fs";
784
+ import { homedir, platform as platform2 } from "os";
785
+ import { fileURLToPath } from "url";
786
+
787
+ // src/commands/defer.ts
788
+ init_config();
789
+ init_meter();
790
+ import { existsSync as existsSync5 } from "node:fs";
791
+ import { hostname } from "node:os";
792
+
793
+ // src/musher.ts
794
+ import { spawnSync } from "node:child_process";
795
+ import { createPublicKey, verify as cryptoVerify } from "node:crypto";
796
+ import { dirname as dirname2, join as join4 } from "node:path";
797
+ var MUSHER_LABEL = "ai.sleds.musher";
798
+ var MUSHER_INTERVAL_S = 300;
799
+ var DEFAULT_PERMISSION_MODE = "acceptEdits";
800
+ var DEFAULT_TIMEOUT_MINUTES = 90;
801
+ var SUMMARY_MAX = 2000;
802
+ var musherPlistPath = (home) => join4(home, "Library", "LaunchAgents", `${MUSHER_LABEL}.plist`);
803
+ var musherLogPath = (configDir2) => join4(configDir2, "musher.log");
804
+ var xmlEscape = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
805
+ var musherPath = (home, execPath, currentPath = "") => {
806
+ const parts = [
807
+ dirname2(execPath),
808
+ join4(home, ".sleds", "bin"),
809
+ join4(home, ".local", "bin"),
810
+ join4(home, ".bun", "bin"),
811
+ "/opt/homebrew/bin",
812
+ "/usr/local/bin",
813
+ "/usr/bin",
814
+ "/bin",
815
+ ...currentPath.split(":").filter(Boolean)
816
+ ];
817
+ return [...new Set(parts)].join(":");
572
818
  };
573
- var hottest = (w) => seatBars(w).reduce((best, cur) => !best || cur.bar.usedPct > best.bar.usedPct ? cur : best, null);
574
- var toneOf = (pct) => pct === undefined ? null : pct >= HOT_PCT ? "hot" : pct >= WARM_PCT ? "warm" : null;
575
- var colorParam = (tone) => tone === "hot" ? ` color=${HOT_COLOR}` : tone === "warm" ? ` color=${WARM_COLOR}` : "";
576
- var barTitle = (m, seat) => {
577
- const head = m ? usd(m.today.spentUsd) : "offline";
578
- const wk = seat?.sevenDay ? `wk ${Math.round(seat.sevenDay.usedPct)}%` : null;
579
- const top = hottest(seat);
580
- const risk = top && top.label !== "wk" && toneOf(top.bar.usedPct) ? `${top.label} ${Math.round(top.bar.usedPct)}%` : null;
581
- return [`sleds ${head}`, ...wk ? [wk] : [], ...risk ? [risk] : []].join(SEP);
582
- };
583
- var resetIn = (bar, now) => bar.resetsAt > now ? `${SEP}resets in ${shortDuration(bar.resetsAt - now)}` : "";
584
- var formatBar = (m, seat, now) => {
585
- const tone = toneOf(hottest(seat)?.bar.usedPct);
586
- const lines = [`${barTitle(m, seat)}${colorParam(tone)}`, "---"];
587
- if (m) {
588
- for (const row2 of formatMeter(m, now))
589
- lines.push(`${row2} | ${MONO}`);
590
- } else {
591
- lines.push(`offline${SEP}proxy did not answer | ${MONO}`);
592
- }
593
- const bars = seatBars(seat);
594
- if (bars.length > 0 || seat?.usedCreditsUsd !== undefined) {
595
- lines.push("---");
596
- lines.push(`Seat limits${seat ? `${SEP}${shortDuration(now - seat.capturedAt)} ago` : ""} | ${MONO}`);
597
- for (const { label, bar } of bars) {
598
- const pct = Math.round(bar.usedPct);
599
- lines.push(`${label.padEnd(12)}${String(pct).padStart(3)}%${resetIn(bar, now)} | ${MONO}${colorParam(toneOf(bar.usedPct))}`);
819
+ var buildMusherPlist = (o) => {
820
+ const args = [...o.sledsArgv, "musher", "tick"].map((a) => ` <string>${xmlEscape(a)}</string>`).join(`
821
+ `);
822
+ const env = Object.entries(o.env).filter(([, v]) => v !== "").map(([k, v]) => ` <key>${xmlEscape(k)}</key>
823
+ <string>${xmlEscape(v)}</string>`).join(`
824
+ `);
825
+ return `<?xml version="1.0" encoding="UTF-8"?>
826
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
827
+ <plist version="1.0">
828
+ <dict>
829
+ <key>Label</key>
830
+ <string>${MUSHER_LABEL}</string>
831
+ <key>ProgramArguments</key>
832
+ <array>
833
+ ${args}
834
+ </array>
835
+ <key>EnvironmentVariables</key>
836
+ <dict>
837
+ ${env}
838
+ </dict>
839
+ <key>StartInterval</key>
840
+ <integer>${MUSHER_INTERVAL_S}</integer>
841
+ <key>RunAtLoad</key>
842
+ <true/>
843
+ <key>StandardOutPath</key>
844
+ <string>${xmlEscape(o.logPath)}</string>
845
+ <key>StandardErrorPath</key>
846
+ <string>${xmlEscape(o.logPath)}</string>
847
+ </dict>
848
+ </plist>
849
+ `;
850
+ };
851
+ var RESUME_PROMPT = [
852
+ "SLEDS musher: the usage limit that stopped this session has reset, and the seat's owner",
853
+ "scheduled this unattended run to continue it. Pick up exactly where the session left off:",
854
+ "finish the task that was in flight, run the checks you would normally run, follow the repo's",
855
+ "own conventions for branches and commits, and do not start unrelated work. If you are blocked",
856
+ "on a decision only the owner can make, stop there and say so. Finish with a summary under",
857
+ "200 words: what was done, what remains, anything the owner must decide."
858
+ ].join(" ");
859
+ var NO_SESSION_PROMPT = [
860
+ "SLEDS musher: a deferred job started on this seat, but no Claude Code session was recorded",
861
+ "to resume. Do not guess at work. Reply with one line saying so, and stop."
862
+ ].join(" ");
863
+ var claudeArgs = (o) => [
864
+ "-p",
865
+ o.sessionId ? RESUME_PROMPT : NO_SESSION_PROMPT,
866
+ ...o.sessionId ? ["--resume", o.sessionId] : [],
867
+ ...o.model ? ["--model", o.model] : [],
868
+ "--output-format",
869
+ "json",
870
+ "--permission-mode",
871
+ o.permissionMode
872
+ ];
873
+ var parseClaudeOutput = (stdout, exitCode) => {
874
+ const lines = stdout.split(`
875
+ `).map((l) => l.trim()).filter(Boolean);
876
+ for (let i = lines.length - 1;i >= 0; i--) {
877
+ const line = lines[i] ?? "";
878
+ if (!line.startsWith("{"))
879
+ continue;
880
+ try {
881
+ const j = JSON.parse(line);
882
+ if (j.type !== "result" && typeof j.result !== "string")
883
+ continue;
884
+ const isError = j.is_error === true || typeof j.subtype === "string" && j.subtype !== "success";
885
+ const text = typeof j.result === "string" ? j.result : "";
886
+ const models = j.modelUsage;
887
+ const model = typeof j.model === "string" ? j.model : models && typeof models === "object" ? Object.keys(models)[0] : undefined;
888
+ return {
889
+ ok: !isError && exitCode === 0,
890
+ summary: (text || (isError ? "Claude Code reported an error" : "")).slice(0, SUMMARY_MAX),
891
+ ...typeof j.session_id === "string" ? { sessionId: j.session_id } : {},
892
+ ...model ? { model } : {},
893
+ ...typeof j.duration_ms === "number" ? { durationMs: j.duration_ms } : {},
894
+ ...typeof j.total_cost_usd === "number" ? { costUsd: j.total_cost_usd } : {}
895
+ };
896
+ } catch {}
897
+ }
898
+ const tail = lines.slice(-5).join(" ").slice(0, SUMMARY_MAX);
899
+ return { ok: false, summary: tail || `claude exited ${exitCode ?? "without a code"}` };
900
+ };
901
+ var defaultExecCapture = (cmd, args, o) => {
902
+ const r = spawnSync(cmd, [...args], {
903
+ cwd: o.cwd,
904
+ encoding: "utf8",
905
+ timeout: o.timeoutMs,
906
+ maxBuffer: 64 * 1024 * 1024,
907
+ stdio: ["ignore", "pipe", "pipe"],
908
+ env: { ...process.env, SLEDS_MUSHER: "1" }
909
+ });
910
+ return {
911
+ stdout: r.stdout ?? "",
912
+ stderr: r.stderr ?? "",
913
+ status: r.status,
914
+ ...r.error ? { error: r.error.message } : {}
915
+ };
916
+ };
917
+ var musherClient = (o) => {
918
+ const fetchFn = o.fetchFn ?? fetch;
919
+ const headers = { authorization: `Bearer ${o.token}`, "content-type": "application/json" };
920
+ const call = async (path, body) => {
921
+ try {
922
+ const res = await fetchFn(`${o.proxyUrl}${path}`, {
923
+ method: body === undefined ? "GET" : "POST",
924
+ headers,
925
+ ...body === undefined ? {} : { body: JSON.stringify(body) },
926
+ signal: AbortSignal.timeout(o.timeoutMs ?? 1e4)
927
+ });
928
+ if (!res.ok)
929
+ return null;
930
+ return await res.json();
931
+ } catch {
932
+ return null;
600
933
  }
601
- if (seat?.usedCreditsUsd !== undefined)
602
- lines.push(`${"credits".padEnd(12)}${usd(seat.usedCreditsUsd)} spent | ${MONO}`);
934
+ };
935
+ return {
936
+ list: () => call("/proxy/musher"),
937
+ start: (jobId, local) => call("/proxy/musher/start", { jobId, ...local }),
938
+ finish: async (input) => await call("/proxy/musher/finish", input) !== null,
939
+ defer: (input) => call("/proxy/defer", input),
940
+ attestation: (jobId) => call(`/proxy/attest/${encodeURIComponent(jobId)}`)
941
+ };
942
+ };
943
+ var gitHead = (cwd, exec) => {
944
+ if (!cwd)
945
+ return null;
946
+ const r = exec("git", ["rev-parse", "HEAD"], { cwd, timeoutMs: 5000 });
947
+ const sha = r.stdout.trim();
948
+ return r.status === 0 && /^[0-9a-f]{40}$/.test(sha) ? sha : null;
949
+ };
950
+ var gitNewCommits = (cwd, before, after, exec) => {
951
+ if (!cwd || !after || after === before)
952
+ return [];
953
+ if (!before)
954
+ return [after];
955
+ const r = exec("git", ["rev-list", `${before}..${after}`], { cwd, timeoutMs: 5000 });
956
+ if (r.status !== 0)
957
+ return [after];
958
+ return r.stdout.split(`
959
+ `).map((l) => l.trim()).filter((l) => /^[0-9a-f]{40}$/.test(l)).slice(0, 40);
960
+ };
961
+ var collectOutputs = (commits, summary) => {
962
+ const out = commits.map((c) => `git:${c}`);
963
+ for (const m of summary.matchAll(/https:\/\/github\.com\/[\w.-]+\/[\w.-]+\/pull\/\d+/g))
964
+ if (!out.includes(`pr:${m[0]}`))
965
+ out.push(`pr:${m[0]}`);
966
+ return out.slice(0, 50);
967
+ };
968
+ var runJob = async (o) => {
969
+ const log = o.log ?? (() => {});
970
+ const sessionId = o.job.claudeSessionId ?? o.fallbackSession?.id ?? null;
971
+ const cwd = o.job.cwd ?? o.fallbackSession?.cwd ?? undefined;
972
+ const started = await o.client.start(o.job.jobId, {
973
+ ...sessionId ? { claudeSessionId: sessionId } : {},
974
+ ...cwd ? { cwd } : {},
975
+ host: o.host
976
+ });
977
+ if (!started)
978
+ return { kind: "skipped", reason: "control plane unreachable" };
979
+ if (!started.ok)
980
+ return { kind: "skipped", reason: started.reason };
981
+ const model = o.job.model ?? started.model ?? o.fallbackSession?.model ?? null;
982
+ const args = claudeArgs({ sessionId, model, permissionMode: o.permissionMode });
983
+ log(`musher: running job ${o.job.jobId} (${sessionId ? `resume ${sessionId}` : "no session"}${model ? ` · ${model}` : ""}${cwd ? ` · ${cwd}` : ""})`);
984
+ const exec = o.exec ?? defaultExecCapture;
985
+ const headBefore = gitHead(cwd, exec);
986
+ const t0 = Date.now();
987
+ const r = exec(o.claudePath, args, { cwd, timeoutMs: o.timeoutMs });
988
+ const durationMs = Date.now() - t0;
989
+ const result = r.error ? { ok: false, summary: `could not run ${o.claudePath}: ${r.error}` } : parseClaudeOutput(r.stdout, r.status);
990
+ if (!r.error && r.status === null)
991
+ result.summary = `timed out after ${Math.round(o.timeoutMs / 60000)} min. ${result.summary}`.trim();
992
+ const outputs = collectOutputs(gitNewCommits(cwd, headBefore, gitHead(cwd, exec), exec), result.summary);
993
+ await o.client.finish({
994
+ jobId: o.job.jobId,
995
+ runId: started.runId,
996
+ ok: result.ok,
997
+ summary: result.summary,
998
+ ...outputs.length ? { outputs } : {},
999
+ ...result.model ?? model ? { model: result.model ?? model } : {},
1000
+ durationMs: result.durationMs ?? durationMs,
1001
+ ...result.sessionId ?? sessionId ? { claudeSessionId: result.sessionId ?? sessionId } : {}
1002
+ });
1003
+ log(`musher: job ${o.job.jobId} ${result.ok ? "delivered" : "failed"} in ${Math.round(durationMs / 1000)}s`);
1004
+ return { kind: "ran", ok: result.ok, summary: result.summary, durationMs, outputs };
1005
+ };
1006
+ var verifyAttestation = (payload, sig, publicKeyB64) => {
1007
+ try {
1008
+ const pub = createPublicKey({
1009
+ key: Buffer.from(publicKeyB64, "base64"),
1010
+ format: "der",
1011
+ type: "spki"
1012
+ });
1013
+ const raw = Buffer.from(sig.replace(/-/g, "+").replace(/_/g, "/"), "base64");
1014
+ return cryptoVerify(null, Buffer.from(payload, "utf8"), pub, raw);
1015
+ } catch {
1016
+ return false;
603
1017
  }
604
- lines.push("---");
605
- lines.push(`Open dashboard | href=${DASHBOARD_URL}`);
606
- lines.push("Refresh | refresh=true");
607
- return lines;
608
1018
  };
609
- var pluginScript = (nodePath, cliPath, env = {}) => [
610
- "#!/bin/bash",
611
- "# SLEDS menu-bar meter for SwiftBar — written by `sleds bar --install`; re-run it after moving the CLI.",
612
- "# <swiftbar.title>SLEDS</swiftbar.title>",
613
- "# <swiftbar.hideAbout>true</swiftbar.hideAbout>",
614
- "# <swiftbar.hideRunInTerminal>true</swiftbar.hideRunInTerminal>",
615
- "# <swiftbar.hideSwiftBar>true</swiftbar.hideSwiftBar>",
616
- ...env.sledsHome ? [`export SLEDS_HOME=${shellQuote(env.sledsHome)}`] : ["unset SLEDS_HOME"],
617
- ...env.claudeConfigDir ? [`export CLAUDE_CONFIG_DIR=${shellQuote(env.claudeConfigDir)}`] : ["unset CLAUDE_CONFIG_DIR"],
618
- 'export PATH="$HOME/.bun/bin:/opt/homebrew/bin:/usr/local/bin:$PATH"',
619
- `if [ -x ${shellQuote(nodePath)} ] && [ -f ${shellQuote(cliPath)} ]; then`,
620
- ` exec ${shellQuote(nodePath)} ${shellQuote(cliPath)} bar`,
621
- "fi",
622
- "if command -v sleds >/dev/null 2>&1; then exec sleds bar; fi",
623
- 'echo "sleds not found"',
624
- 'echo "---"',
625
- 'echo "Run \\`npx @sleds/cli bar --install\\` again. | font=Menlo size=12"',
626
- ""
627
- ].join(`
628
- `);
629
- var shellQuote = (s) => `'${s.replace(/'/g, `'\\''`)}'`;
1019
+ var parsePayload = (payload) => {
1020
+ const out = {};
1021
+ for (const line of payload.split(`
1022
+ `).slice(1)) {
1023
+ const eq = line.indexOf("=");
1024
+ if (eq > 0)
1025
+ out[line.slice(0, eq)] = line.slice(eq + 1);
1026
+ }
1027
+ return out;
1028
+ };
630
1029
 
631
1030
  // src/seat.ts
1031
+ init_config();
1032
+ init_meter();
632
1033
  import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync4, renameSync as renameSync4, writeFileSync as writeFileSync4 } from "node:fs";
633
- import { join as join4 } from "node:path";
1034
+ import { join as join5 } from "node:path";
634
1035
  var SEAT_POST_MIN_DELTA_PCT = 1;
635
1036
  var SEAT_POST_MIN_INTERVAL_MS = 5 * 60000;
636
1037
  var SEAT_POST_TIMEOUT_MS = 1500;
@@ -715,7 +1116,7 @@ var formatSeatFragment = (w) => {
715
1116
  return null;
716
1117
  return `seat ${parts.join(SEP)}`;
717
1118
  };
718
- var seatStatePath = (home) => join4(configDir(home), "seat.json");
1119
+ var seatStatePath = (home) => join5(configDir(home), "seat.json");
719
1120
  var parseWindowStored = (v) => {
720
1121
  if (!isObject4(v))
721
1122
  return;
@@ -750,8 +1151,56 @@ var parseSeatState = (raw) => {
750
1151
  const lastWallResetsAt = num2(raw.lastWallResetsAt);
751
1152
  if (lastWallResetsAt !== undefined)
752
1153
  out.lastWallResetsAt = lastWallResetsAt;
1154
+ const session = parseSeatSession(raw.session);
1155
+ if (session)
1156
+ out.session = session;
1157
+ return out;
1158
+ };
1159
+ var parseSeatSession = (v) => {
1160
+ if (!isObject4(v) || typeof v.id !== "string" || !v.id)
1161
+ return;
1162
+ const at = num2(v.at);
1163
+ if (at === undefined)
1164
+ return;
1165
+ const out = { id: v.id, at };
1166
+ if (typeof v.cwd === "string" && v.cwd)
1167
+ out.cwd = v.cwd;
1168
+ if (typeof v.model === "string" && v.model)
1169
+ out.model = v.model;
753
1170
  return out;
754
1171
  };
1172
+ var seatSessionFromStdin = (text, now) => {
1173
+ const trimmed = text.trim();
1174
+ if (!trimmed)
1175
+ return null;
1176
+ try {
1177
+ const raw = JSON.parse(trimmed);
1178
+ if (!isObject4(raw) || typeof raw.session_id !== "string" || !raw.session_id)
1179
+ return null;
1180
+ const out = { id: raw.session_id, at: now };
1181
+ if (typeof raw.cwd === "string" && raw.cwd)
1182
+ out.cwd = raw.cwd;
1183
+ const model = isObject4(raw.model) ? raw.model.id : raw.model;
1184
+ if (typeof model === "string" && model)
1185
+ out.model = model;
1186
+ return out;
1187
+ } catch {
1188
+ return null;
1189
+ }
1190
+ };
1191
+ var bindingResetAt = (w, now) => {
1192
+ if (!w)
1193
+ return;
1194
+ const bars = [
1195
+ ...w.fiveHour ? [w.fiveHour] : [],
1196
+ ...w.sevenDay ? [w.sevenDay] : [],
1197
+ ...w.spendLimit ? [w.spendLimit] : [],
1198
+ ...Object.values(w.models ?? {})
1199
+ ].filter((b) => b.resetsAt > now);
1200
+ const full = bars.filter((b) => b.usedPct >= 100);
1201
+ const pick = (full.length ? full : bars).map((b) => b.resetsAt);
1202
+ return pick.length ? Math.min(...pick) : undefined;
1203
+ };
755
1204
  var readSeatState = (home) => {
756
1205
  const p = seatStatePath(home);
757
1206
  if (!existsSync4(p))
@@ -827,167 +1276,37 @@ var postJson = async (o, path, body) => {
827
1276
  return false;
828
1277
  }
829
1278
  };
830
- var postSeatWindow = (o, w) => postJson(o, "/proxy/seat", seatWindowBody(w));
831
- var postSeatWall = (o, input) => postJson(o, "/proxy/seat-wall", input);
832
- var SEAT_WALL_LINE = "Seat limit hit. sleds on --until-reset to continue on the org key.";
833
- var readStdin = (timeoutMs, stdin = process.stdin) => new Promise((resolve3) => {
834
- if (stdin.isTTY) {
835
- resolve3("");
836
- return;
837
- }
838
- let data = "";
839
- let settled = false;
840
- const finish = () => {
841
- if (settled)
842
- return;
843
- settled = true;
844
- clearTimeout(timer);
845
- resolve3(data);
846
- };
847
- const timer = setTimeout(finish, timeoutMs);
848
- stdin.setEncoding("utf8");
849
- stdin.on("data", (chunk) => {
850
- data += chunk;
851
- });
852
- stdin.on("end", finish);
853
- stdin.on("error", finish);
854
- stdin.resume();
855
- });
856
-
857
- // src/commands/bar.ts
858
- function parseInstallArgs(argv, env) {
859
- const flag = (name2) => {
860
- const i = argv.indexOf(`--${name2}`);
861
- const v = i >= 0 ? argv[i + 1] : undefined;
862
- return v && !v.startsWith("--") ? v : undefined;
863
- };
864
- const sledsHome = flag("home") ?? (env.SLEDS_HOME?.trim() || undefined);
865
- const claudeConfigDir = flag("claude-config") ?? (env.CLAUDE_CONFIG_DIR?.trim() || undefined);
866
- const name = flag("name");
867
- return {
868
- ...sledsHome ? { sledsHome } : {},
869
- ...claudeConfigDir ? { claudeConfigDir } : {},
870
- ...name ? { name } : {}
871
- };
872
- }
873
- var PLUGIN_NAME = "sleds.1m.sh";
874
- var pluginName = (name) => name ? `sleds-${name}.1m.sh` : PLUGIN_NAME;
875
- var bar = async (o) => {
876
- const log = o.log ?? console.log;
877
- const argv = o.argv ?? [];
878
- if (argv.includes("--install"))
879
- return install(o, log);
880
- if (argv.includes("--uninstall"))
881
- return uninstall(o, log);
882
- const now = (o.now ?? Date.now)();
883
- const seat = freshSeat(readSeatState(o.home).window, now);
884
- if (!meterSource(o.home)) {
885
- log("sleds not set up");
886
- log("---");
887
- log("Run `sleds init` first | font=Menlo size=12");
888
- return 0;
889
- }
890
- const m = await loadMeter({ home: o.home, now, fetchFn: o.fetchFn, timeoutMs: o.timeoutMs });
891
- for (const line of formatBar(m, seat, now))
892
- log(line);
893
- return 0;
894
- };
895
- function swiftBarPluginDir() {
896
- try {
897
- const out = execFileSync("defaults", ["read", "com.ameba.SwiftBar", "PluginDirectory"], {
898
- encoding: "utf8",
899
- stdio: ["ignore", "pipe", "ignore"]
900
- }).trim();
901
- return out ? out.replace(/^~(?=$|\/)/, homedir()) : null;
902
- } catch {
903
- return null;
904
- }
905
- }
906
- var pluginPath = (home, name) => join5(configDir(home, {}), "swiftbar", pluginName(name));
907
- function install(o, log) {
908
- const opts = parseInstallArgs(o.argv ?? [], o.env ?? process.env);
909
- const script = pluginPath(o.home, opts.name);
910
- mkdirSync5(join5(script, ".."), { recursive: true, mode: 448 });
911
- writeFileSync5(script, pluginScript(o.nodePath ?? process.execPath, o.cliPath ?? process.argv[1] ?? "", {
912
- ...opts.sledsHome ? { sledsHome: resolve3(o.home, opts.sledsHome) } : {},
913
- ...opts.claudeConfigDir ? { claudeConfigDir: resolve3(o.home, opts.claudeConfigDir) } : {}
914
- }), {
915
- mode: 493
916
- });
917
- chmodSync2(script, 493);
918
- log(`wrote ${script}`);
919
- if (opts.sledsHome || opts.claudeConfigDir)
920
- log(`tracks the seat at ${[opts.sledsHome && `SLEDS_HOME=${opts.sledsHome}`, opts.claudeConfigDir && `CLAUDE_CONFIG_DIR=${opts.claudeConfigDir}`].filter(Boolean).join(" ")}`);
921
- const dir = (o.swiftBarPluginDir ?? swiftBarPluginDir)();
922
- if (!dir) {
923
- log("SwiftBar is not set up yet: `brew install --cask swiftbar`, launch it once and pick a plugin");
924
- log("folder, then run `sleds bar --install` again — or symlink the file above into that folder.");
925
- return 0;
926
- }
927
- const link = join5(dir, pluginName(opts.name));
928
- try {
929
- mkdirSync5(dir, { recursive: true });
930
- if (existsSync5(link) || isDanglingLink(link))
931
- unlinkSync(link);
932
- symlinkSync(script, link);
933
- log(`linked ${link}`);
934
- log("SwiftBar picks it up within a minute; the item reads `sleds $… · wk …%`.");
935
- return 0;
936
- } catch (e) {
937
- log(`could not link into ${dir}: ${e instanceof Error ? e.message : String(e)}`);
938
- log(`symlink it yourself: ln -sf ${script} ${link}`);
939
- return 1;
940
- }
941
- }
942
- function uninstall(o, log) {
943
- const { name } = parseInstallArgs(o.argv ?? [], {});
944
- const dir = (o.swiftBarPluginDir ?? swiftBarPluginDir)();
945
- const link = dir ? join5(dir, pluginName(name)) : null;
946
- if (link && (existsSync5(link) || isDanglingLink(link))) {
947
- unlinkSync(link);
948
- log(`removed ${link}`);
949
- } else
950
- log("no SwiftBar plugin link to remove");
951
- const script = pluginPath(o.home, name);
952
- if (existsSync5(script)) {
953
- unlinkSync(script);
954
- log(`removed ${script}`);
955
- }
956
- return 0;
957
- }
958
- var isDanglingLink = (p) => {
959
- try {
960
- return lstatSync(p).isSymbolicLink();
961
- } catch {
962
- return false;
963
- }
964
- };
965
-
966
- // src/commands/doctor.ts
967
- import { execFileSync as execFileSync3 } from "node:child_process";
968
- import { existsSync as existsSync6, lstatSync as lstatSync2, readFileSync as readFileSync5, readdirSync, readlinkSync } from "node:fs";
969
- import { join as join7, resolve as resolve5 } from "node:path";
970
-
971
- // src/commands/bar.ts
972
- import { execFileSync as execFileSync2 } from "node:child_process";
973
- import { homedir as homedir2 } from "node:os";
974
- import { join as join6, resolve as resolve4 } from "node:path";
975
- var PLUGIN_NAME2 = "sleds.1m.sh";
976
- var pluginName2 = (name) => name ? `sleds-${name}.1m.sh` : PLUGIN_NAME2;
977
- function swiftBarPluginDir2() {
978
- try {
979
- const out = execFileSync2("defaults", ["read", "com.ameba.SwiftBar", "PluginDirectory"], {
980
- encoding: "utf8",
981
- stdio: ["ignore", "pipe", "ignore"]
982
- }).trim();
983
- return out ? out.replace(/^~(?=$|\/)/, homedir2()) : null;
984
- } catch {
985
- return null;
1279
+ var postSeatWindow = (o, w) => postJson(o, "/proxy/seat", seatWindowBody(w));
1280
+ var postSeatWall = (o, input) => postJson(o, "/proxy/seat-wall", input);
1281
+ var SEAT_WALL_LINE = "Seat limit hit. sleds on --until-reset to continue on the org key, or sleds defer to resume here at the reset.";
1282
+ 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.";
1283
+ var seatWallLine = (hasUpstreamKey) => hasUpstreamKey ? SEAT_WALL_LINE : SEAT_WALL_LINE_NO_KEY;
1284
+ var readStdin = (timeoutMs, stdin = process.stdin) => new Promise((resolve3) => {
1285
+ if (stdin.isTTY) {
1286
+ resolve3("");
1287
+ return;
986
1288
  }
987
- }
988
- var pluginPath2 = (home, name) => join6(configDir(home, {}), "swiftbar", pluginName2(name));
1289
+ let data = "";
1290
+ let settled = false;
1291
+ const finish = () => {
1292
+ if (settled)
1293
+ return;
1294
+ settled = true;
1295
+ clearTimeout(timer);
1296
+ resolve3(data);
1297
+ };
1298
+ const timer = setTimeout(finish, timeoutMs);
1299
+ stdin.setEncoding("utf8");
1300
+ stdin.on("data", (chunk) => {
1301
+ data += chunk;
1302
+ });
1303
+ stdin.on("end", finish);
1304
+ stdin.on("error", finish);
1305
+ stdin.resume();
1306
+ });
989
1307
 
990
1308
  // src/switch.ts
1309
+ init_settings();
991
1310
  var isObject5 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
992
1311
  var envOf2 = (settings) => isObject5(settings.env) ? settings.env : {};
993
1312
  var capturePriorEnv = (settings) => {
@@ -1062,7 +1381,141 @@ var formatDuration = (ms) => {
1062
1381
  return m === 0 ? `${h}h` : `${h}h ${m}m`;
1063
1382
  };
1064
1383
 
1384
+ // src/commands/defer.ts
1385
+ var parseAt = (v, now) => {
1386
+ const rel = /^\+(\d+)([hm])$/.exec(v.trim());
1387
+ if (rel) {
1388
+ const n = Number.parseInt(rel[1] ?? "0", 10);
1389
+ return now + n * (rel[2] === "h" ? 3600000 : 60000);
1390
+ }
1391
+ const t = Date.parse(v);
1392
+ return Number.isFinite(t) ? t : undefined;
1393
+ };
1394
+ var parseFlags = (argv) => {
1395
+ const flags = {};
1396
+ for (let i = 0;i < argv.length; i++) {
1397
+ const a = argv[i] ?? "";
1398
+ if (!a.startsWith("--"))
1399
+ continue;
1400
+ const eq = a.indexOf("=");
1401
+ if (eq > 0)
1402
+ flags[a.slice(2, eq)] = a.slice(eq + 1);
1403
+ else {
1404
+ const next = argv[i + 1];
1405
+ if (next !== undefined && !next.startsWith("--")) {
1406
+ flags[a.slice(2)] = next;
1407
+ i++;
1408
+ } else
1409
+ flags[a.slice(2)] = "true";
1410
+ }
1411
+ }
1412
+ return flags;
1413
+ };
1414
+ var defer = async (o) => {
1415
+ const log = o.log ?? console.log;
1416
+ const error = o.error ?? console.error;
1417
+ const now = (o.now ?? Date.now)();
1418
+ const flags = parseFlags(o.argv);
1419
+ const client = o.client ?? (() => {
1420
+ const src = meterSource(o.home);
1421
+ return src ? musherClient({ ...src, fetchFn: o.fetchFn }) : null;
1422
+ })();
1423
+ if (!client) {
1424
+ error("No seat on this machine. Run `sleds init` first.");
1425
+ return 1;
1426
+ }
1427
+ const state = readSeatState(o.home);
1428
+ const piped = o.stdin ? seatSessionFromStdin(o.stdin, now) : null;
1429
+ const remembered = piped ?? state.session;
1430
+ const sessionId = flags.session ?? remembered?.id;
1431
+ const cwd = flags.cwd ?? remembered?.cwd;
1432
+ const model = flags.model ?? remembered?.model;
1433
+ let resetAt;
1434
+ if (flags.at) {
1435
+ resetAt = parseAt(flags.at, now);
1436
+ if (resetAt === undefined) {
1437
+ error(`--at takes +2h, +90m or an ISO timestamp (got ${flags.at})`);
1438
+ return 1;
1439
+ }
1440
+ } else
1441
+ resetAt = bindingResetAt(state.window, now);
1442
+ if (!sessionId)
1443
+ log("No Claude Code session remembered on this seat yet; the job will say so when it starts. Pass --session <id> to pick one.");
1444
+ const r = await client.defer({
1445
+ ...resetAt !== undefined ? { resetAt } : {},
1446
+ ...model ? { model } : {},
1447
+ ...sessionId ? { claudeSessionId: sessionId } : {},
1448
+ ...cwd ? { cwd } : {},
1449
+ host: o.host ?? hostname()
1450
+ });
1451
+ if (!r) {
1452
+ error("Could not reach the SLEDS proxy; nothing was scheduled.");
1453
+ return 1;
1454
+ }
1455
+ const when = r.scheduledAt <= now + 60000 ? "as soon as the musher ticks (within 5 min)" : `${formatLocal(r.scheduledAt)} (in ${formatDuration(r.scheduledAt - now)})`;
1456
+ log(`Deferred. This Mac resumes ${sessionId ? `session ${sessionId.slice(0, 8)}…` : "the work"}${model ? ` on ${model}` : ""} ${when}.`);
1457
+ log(` job ${r.jobId}${cwd ? ` · ${cwd}` : ""} · runs on your seat, no key · sleds musher --status to watch`);
1458
+ const cfg = readConfig(o.home);
1459
+ if (process.platform === "darwin" && !existsSync5(musherPlistPath(o.home)) && cfg.musher?.agent !== "launchd")
1460
+ 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.`);
1461
+ log(" Keep this Mac awake at that time (System Settings → Battery → prevent sleeping on power adapter).");
1462
+ return 0;
1463
+ };
1464
+
1465
+ // src/commands/doctor.ts
1466
+ init_config();
1467
+ init_meter();
1468
+ import { execFileSync } from "node:child_process";
1469
+ import { existsSync as existsSync7, lstatSync, readlinkSync } from "node:fs";
1470
+ import { resolve as resolve3 } from "node:path";
1471
+ init_settings();
1472
+
1473
+ // src/commands/musher.ts
1474
+ import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync5, rmSync, writeFileSync as writeFileSync5 } from "node:fs";
1475
+ init_config();
1476
+ init_meter();
1477
+ var defaultWhich = (cmd) => {
1478
+ const path = process.env.PATH ?? "";
1479
+ for (const dir of path.split(":").filter(Boolean)) {
1480
+ const p = `${dir}/${cmd}`;
1481
+ if (existsSync6(p))
1482
+ return p;
1483
+ }
1484
+ return null;
1485
+ };
1486
+ var findClaude = (home, configured, which) => {
1487
+ if (configured && existsSync6(configured))
1488
+ return configured;
1489
+ const found = which("claude");
1490
+ if (found)
1491
+ return found;
1492
+ for (const p of [
1493
+ `${home}/.local/bin/claude`,
1494
+ "/opt/homebrew/bin/claude",
1495
+ "/usr/local/bin/claude",
1496
+ `${home}/.npm-global/bin/claude`
1497
+ ])
1498
+ if (existsSync6(p))
1499
+ return p;
1500
+ return null;
1501
+ };
1502
+ var musherAgentState = (home, env = process.env) => {
1503
+ const plist = musherPlistPath(home);
1504
+ if (!existsSync6(plist))
1505
+ return { installed: false, thisSeat: false };
1506
+ try {
1507
+ const text = readFileSync5(plist, "utf8");
1508
+ const want = env.SLEDS_HOME?.trim();
1509
+ const has = /<key>SLEDS_HOME<\/key>\s*<string>([^<]*)<\/string>/.exec(text)?.[1];
1510
+ return { installed: true, thisSeat: (want ?? undefined) === (has ?? undefined) };
1511
+ } catch {
1512
+ return { installed: true, thisSeat: false };
1513
+ }
1514
+ };
1515
+
1065
1516
  // src/commands/status.ts
1517
+ init_config();
1518
+ init_settings();
1066
1519
  var checkHealth = async (url, fetchFn = fetch, timeoutMs = 1000) => {
1067
1520
  try {
1068
1521
  const res = await fetchFn(`${url}/healthz`, { signal: AbortSignal.timeout(timeoutMs) });
@@ -1080,16 +1533,6 @@ function nodeOk(version, min = NODE_MIN) {
1080
1533
  const [x, y, z] = parse(min);
1081
1534
  return (a ?? 0) !== (x ?? 0) ? (a ?? 0) > (x ?? 0) : (b ?? 0) !== (y ?? 0) ? (b ?? 0) > (y ?? 0) : (c ?? 0) >= (z ?? 0);
1082
1535
  }
1083
- function pluginEnv(body) {
1084
- const out = {};
1085
- const home = /^export SLEDS_HOME='([^']*)'/m.exec(body);
1086
- const cfg = /^export CLAUDE_CONFIG_DIR='([^']*)'/m.exec(body);
1087
- if (home?.[1])
1088
- out.sledsHome = home[1];
1089
- if (cfg?.[1])
1090
- out.claudeConfigDir = cfg[1];
1091
- return out;
1092
- }
1093
1536
  var MARK = { ok: "ok ", warn: "warn", fail: "FAIL" };
1094
1537
  function formatDoctor(checks) {
1095
1538
  const lines = checks.map((c) => `${MARK[c.level]} ${c.name.padEnd(16)}${c.detail}`);
@@ -1105,9 +1548,9 @@ function formatDoctor(checks) {
1105
1548
  lines.push(fails === 0 && warns === 0 ? "All good." : `${fails} problem${fails === 1 ? "" : "s"}, ${warns} warning${warns === 1 ? "" : "s"}.`);
1106
1549
  return lines;
1107
1550
  }
1108
- function defaultWhich(cmd) {
1551
+ function defaultWhich2(cmd) {
1109
1552
  try {
1110
- return execFileSync3("which", ["-a", cmd], {
1553
+ return execFileSync("which", ["-a", cmd], {
1111
1554
  encoding: "utf8",
1112
1555
  stdio: ["ignore", "pipe", "ignore"]
1113
1556
  }).split(`
@@ -1116,16 +1559,6 @@ function defaultWhich(cmd) {
1116
1559
  return [];
1117
1560
  }
1118
1561
  }
1119
- function defaultLaunchctl() {
1120
- try {
1121
- return execFileSync3("launchctl", ["list"], {
1122
- encoding: "utf8",
1123
- stdio: ["ignore", "pipe", "ignore"]
1124
- });
1125
- } catch {
1126
- return "";
1127
- }
1128
- }
1129
1562
  async function runDoctor(o) {
1130
1563
  const env = o.env ?? process.env;
1131
1564
  const checks = [];
@@ -1136,7 +1569,7 @@ async function runDoctor(o) {
1136
1569
  ].filter(Boolean);
1137
1570
  const cfgDir = configDir(home, env);
1138
1571
  const cfg = readConfig(home);
1139
- const cfgExists = existsSync6(configPath(home));
1572
+ const cfgExists = existsSync7(configPath(home));
1140
1573
  if (!cfgExists) {
1141
1574
  checks.push({
1142
1575
  level: "fail",
@@ -1152,7 +1585,7 @@ async function runDoctor(o) {
1152
1585
  });
1153
1586
  }
1154
1587
  const sPath = settingsPath(home);
1155
- const settings = existsSync6(sPath) ? readSettings(home) : null;
1588
+ const settings = existsSync7(sPath) ? readSettings(home) : null;
1156
1589
  const pointed = settings ? readProxy(settings) : null;
1157
1590
  if (!settings) {
1158
1591
  checks.push({
@@ -1196,7 +1629,7 @@ async function runDoctor(o) {
1196
1629
  detail: `seat-event ${seat2 ? "on" : "missing"} · spec-event ${spec ? "on" : "missing"}`,
1197
1630
  fix: seat2 && spec ? undefined : "sleds hooks"
1198
1631
  });
1199
- const want = env.SLEDS_HOME?.trim() ? resolve5(home, env.SLEDS_HOME.trim()) : undefined;
1632
+ const want = env.SLEDS_HOME?.trim() ? resolve3(home, env.SLEDS_HOME.trim()) : undefined;
1200
1633
  const cmds = sledsCommandsIn(settings);
1201
1634
  const wrong = cmds.filter((c) => {
1202
1635
  const got = bakedHome(c);
@@ -1210,7 +1643,7 @@ async function runDoctor(o) {
1210
1643
  fix: wrong.length === 0 ? undefined : `${overrides.length ? `${overrides.join(" ")} ` : ""}sleds hooks (re-writes the status line + hooks with this seat baked in)`
1211
1644
  });
1212
1645
  }
1213
- const skill = existsSync6(skillPath(home));
1646
+ const skill = existsSync7(skillPath(home));
1214
1647
  checks.push({
1215
1648
  level: skill ? "ok" : "warn",
1216
1649
  name: "skill",
@@ -1225,10 +1658,10 @@ async function runDoctor(o) {
1225
1658
  detail: `${nodeVersion}${nodeOk(nodeVersion) ? "" : ` — seat-sync needs ≥ ${NODE_MIN} (node:sqlite)`}`,
1226
1659
  fix: nodeOk(nodeVersion) ? undefined : `brew install node@22 && echo 'export PATH="/opt/homebrew/opt/node@22/bin:$PATH"' >> ~/.zshrc`
1227
1660
  });
1228
- const which = (o.which ?? defaultWhich)("sleds");
1661
+ const which = (o.which ?? defaultWhich2)("sleds");
1229
1662
  const stale = which.filter((p) => {
1230
1663
  try {
1231
- const target = lstatSync2(p).isSymbolicLink() ? readlinkSync(p) : p;
1664
+ const target = lstatSync(p).isSymbolicLink() ? readlinkSync(p) : p;
1232
1665
  return /\/src\/index\.ts$/.test(target) || /\.bun\/bin\/sleds$/.test(p);
1233
1666
  } catch {
1234
1667
  return false;
@@ -1243,49 +1676,64 @@ async function runDoctor(o) {
1243
1676
  });
1244
1677
  else if (which.length > 0)
1245
1678
  checks.push({ level: "ok", name: "path", detail: which[0] ?? "" });
1246
- const pluginBody = existsSync6(pluginPath2(home)) ? readFileSync5(pluginPath2(home), "utf8") : null;
1247
- const dir = (o.swiftBarPluginDir ?? swiftBarPluginDir2)();
1248
- if (pluginBody) {
1249
- const baked = pluginEnv(pluginBody);
1250
- const linked = dir ? existsSync6(join7(dir, PLUGIN_NAME2)) : false;
1251
- const seatDesc = baked.sledsHome || baked.claudeConfigDir ? `seat at ${[baked.sledsHome && `SLEDS_HOME=${baked.sledsHome}`, baked.claudeConfigDir && `CLAUDE_CONFIG_DIR=${baked.claudeConfigDir}`].filter(Boolean).join(" ")}` : "default seat";
1252
- checks.push({
1253
- level: linked ? "ok" : "warn",
1254
- name: "menu bar",
1255
- detail: linked ? `${PLUGIN_NAME2} linked · ${seatDesc}` : `plugin written but not linked into SwiftBar${dir ? ` (${dir})` : " (SwiftBar not set up)"}`,
1256
- fix: linked ? undefined : "sleds bar --install"
1257
- });
1258
- } else {
1259
- checks.push({
1260
- level: "warn",
1261
- name: "menu bar",
1262
- detail: "no SwiftBar plugin",
1263
- fix: "sleds bar --install"
1264
- });
1265
- }
1266
- const agents = join7(home, "Library", "LaunchAgents");
1267
- const plists = existsSync6(agents) ? readdirSync(agents).filter((f) => f.startsWith("ai.sleds.") && f.endsWith(".plist")) : [];
1268
- const loaded = (o.launchctlList ?? defaultLaunchctl)();
1269
1679
  const seat = readSeatState(home);
1270
1680
  const age = seat.window ? Math.round((Date.now() - seat.window.capturedAt) / 60000) : null;
1271
- if (plists.length === 0)
1272
- checks.push({
1681
+ checks.push({
1682
+ level: age === null ? "warn" : "ok",
1683
+ name: "seat quota",
1684
+ 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)}%` : ""}`,
1685
+ fix: age === null ? "open claude, say hi, exit — the status line posts the seat's quota" : undefined
1686
+ });
1687
+ if ((o.platform ?? process.platform) === "darwin") {
1688
+ const agent = musherAgentState(home, env);
1689
+ checks.push(!agent.installed ? {
1273
1690
  level: "warn",
1274
- name: "seat-sync",
1275
- detail: "no timer installed (seat bars stay empty)",
1276
- fix: "sleds seat-sync --install"
1277
- });
1278
- else {
1279
- const running = plists.filter((p) => loaded.includes(p.replace(/\.plist$/, "")));
1280
- checks.push({
1281
- level: running.length === plists.length ? age !== null && age < 6 * 60 ? "ok" : "warn" : "warn",
1282
- name: "seat-sync",
1283
- detail: `${running.length}/${plists.length} timer${plists.length === 1 ? "" : "s"} loaded${age !== null ? ` · last read ${age}m ago` : " · no read yet"}`,
1284
- fix: running.length === plists.length && age !== null && age < 6 * 60 ? undefined : "sleds seat-sync (run once by hand and read its message)"
1691
+ name: "musher",
1692
+ detail: "agent not installed — `sleds defer` jobs would wait for `sleds run`",
1693
+ fix: "sleds musher --install"
1694
+ } : !agent.thisSeat ? {
1695
+ level: "warn",
1696
+ name: "musher",
1697
+ detail: "agent installed for a different seat (SLEDS_HOME differs)",
1698
+ fix: "sleds musher --install"
1699
+ } : { level: "ok", name: "musher", detail: `launchd agent ${MUSHER_LABEL}, every 5 min` });
1700
+ const claude = findClaude(home, readConfig(home).musher?.claudePath, (c) => (o.which ?? defaultWhich2)(c)[0] ?? null);
1701
+ checks.push(claude ? { level: "ok", name: "claude cli", detail: claude } : {
1702
+ level: "warn",
1703
+ name: "claude cli",
1704
+ detail: "`claude` not on PATH — the musher cannot run Claude Code",
1705
+ fix: 'sleds musher --claude "$(which claude)"'
1285
1706
  });
1707
+ const sleep = (o.pmset ?? defaultPmset)();
1708
+ if (sleep !== null)
1709
+ checks.push(sleep.acSleepMinutes === 0 ? {
1710
+ level: "ok",
1711
+ name: "awake",
1712
+ detail: "does not sleep on power — deferred jobs can start"
1713
+ } : {
1714
+ level: "warn",
1715
+ name: "awake",
1716
+ detail: `sleeps after ${sleep.acSleepMinutes} min on power — a deferred job needs the Mac awake at the reset`,
1717
+ fix: "System Settings → Battery → Options → Prevent automatic sleeping on power adapter (or: sudo pmset -c sleep 0)"
1718
+ });
1286
1719
  }
1287
1720
  return checks;
1288
1721
  }
1722
+ function parsePmset(text) {
1723
+ const ac = text.split(/AC Power:/i)[1];
1724
+ const block = ac ?? text;
1725
+ const m = /^\s*sleep\s+(\d+)/m.exec(block);
1726
+ if (!m)
1727
+ return null;
1728
+ return { acSleepMinutes: Number.parseInt(m[1] ?? "0", 10) };
1729
+ }
1730
+ var defaultPmset = () => {
1731
+ try {
1732
+ return parsePmset(execFileSync("pmset", ["-g", "custom"], { encoding: "utf8", timeout: 2000 }));
1733
+ } catch {
1734
+ return null;
1735
+ }
1736
+ };
1289
1737
  var doctor = async (o) => {
1290
1738
  const log = o.log ?? console.log;
1291
1739
  const checks = await runDoctor(o);
@@ -1295,6 +1743,7 @@ var doctor = async (o) => {
1295
1743
  };
1296
1744
 
1297
1745
  // src/commands/hooks.ts
1746
+ init_settings();
1298
1747
  var hooks = (o) => {
1299
1748
  const log = o.log ?? console.log;
1300
1749
  const error = o.error ?? console.error;
@@ -1317,6 +1766,8 @@ var hooks = (o) => {
1317
1766
  };
1318
1767
 
1319
1768
  // src/commands/init.ts
1769
+ init_config();
1770
+ init_settings();
1320
1771
  import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync6 } from "node:fs";
1321
1772
  import { createInterface } from "node:readline";
1322
1773
 
@@ -1350,8 +1801,13 @@ When the proxy is active it answers a walled request with its options. The user
1350
1801
  /sled 3 run overnight at half price
1351
1802
  /sled 4 switch to a cheaper model for the rest of the session (offered when one saves ≥15%)
1352
1803
  /sled 5 hand off to an idle coworker, or park for the team (offered on a team of two or more)
1804
+ /sled 6 defer to reset: the job runs itself when the seat resets — same model, done in minutes, full price (offered when the wall has a reset and the org has a key)
1353
1805
  \`\`\`
1354
1806
 
1807
+ No key (Team plan, seat-first)? The musher still runs: \`sleds defer\` in a terminal schedules this Mac to resume the current session itself at the reset — \`claude --resume\` on the seat's own quota, the model pinned. \`sleds musher --status\` lists what is waiting; \`sleds run <jobId>\` runs one now; the Mac must be awake at the reset (\`sleds doctor\` checks). When the user says "defer this" or "pick it up at the reset" and the org has no key, tell them to run \`sleds defer\`.
1808
+
1809
+ A hand-off carries a brief (the packet): what, note, cost so far, how to pick it up. The \`handoffs\` MCP tool and the dashboard's Jobs page show it; read it before taking one.
1810
+
1355
1811
  ## Window reset
1356
1812
 
1357
1813
  When the user mentions their window has reset, or the deadline shown by \`sleds status\` has passed:
@@ -1364,9 +1820,9 @@ then restart \`claude\`. Settings go back to exactly what they were.
1364
1820
 
1365
1821
  ## Check
1366
1822
 
1367
- \`sleds status\` — on/off, since, reverts at, proxy health, wall mode.
1823
+ \`sleds status\` — on/off, since, reverts at, proxy health, wall mode, and the org's shape (\`Org:\` / \`Wiring:\`). An org with no platform key runs seat-first and its walls offer hold (\`/sled 2\`), \`sleds defer\` (this Mac resumes at the reset) and hand-off (\`/sled 5\`) — continue, overnight and switch need a key an admin adds on the dashboard.
1368
1824
 
1369
- The status line's \`seat wk 52% · 5h 12%\` is the user's own Pro/Max window as Claude Code reports it (weekly, then 5-hour); \`window\` is the org key's headroom through the proxy. At \`wk 100%\` the answer is \`sleds on --until-reset\`.
1825
+ The status line's \`seat wk 52% · 5h 12%\` is the user's own Pro/Max window as Claude Code reports it (weekly, then 5-hour); \`window\` is the org key's headroom through the proxy. At \`wk 100%\` the answer is \`sleds on --until-reset\` (org key) or \`sleds defer\` (this Mac resumes at the reset, no key).
1370
1826
 
1371
1827
  ## /sled — estimate the task, offer overnight
1372
1828
 
@@ -1441,6 +1897,7 @@ From Cowork or any MCP client (\`sleds mcp\`): the \`handoffs\` tool lists what
1441
1897
  `;
1442
1898
 
1443
1899
  // src/commands/hooks.ts
1900
+ init_settings();
1444
1901
  var hooks2 = (o) => {
1445
1902
  const log = o.log ?? console.log;
1446
1903
  const error = o.error ?? console.error;
@@ -1464,24 +1921,35 @@ var hooks2 = (o) => {
1464
1921
 
1465
1922
  // src/commands/init.ts
1466
1923
  var DEFAULT_PROXY_URL = "http://localhost:8787";
1467
- var promptStdin = (question) => new Promise((resolve6) => {
1924
+ var promptStdin = (question) => new Promise((resolve4) => {
1468
1925
  const rl = createInterface({ input: process.stdin, output: process.stderr });
1469
1926
  rl.question(question, (answer) => {
1470
1927
  rl.close();
1471
- resolve6(answer.trim());
1928
+ resolve4(answer.trim());
1472
1929
  });
1473
1930
  });
1474
1931
  async function signupIndividual(proxyUrl, email, credential, fetchFn = fetch) {
1932
+ return signupRequest(proxyUrl, { email, apiKey: credential }, fetchFn);
1933
+ }
1934
+ async function signupTeam(proxyUrl, email, team, credential, fetchFn = fetch) {
1935
+ return signupRequest(proxyUrl, { email, team, ...credential ? { apiKey: credential } : {} }, fetchFn);
1936
+ }
1937
+ async function signupRequest(proxyUrl, payload, fetchFn) {
1475
1938
  try {
1476
1939
  const res = await fetchFn(`${proxyUrl}/signup`, {
1477
1940
  method: "POST",
1478
1941
  headers: { "content-type": "application/json" },
1479
- body: JSON.stringify({ email, apiKey: credential }),
1942
+ body: JSON.stringify(payload),
1480
1943
  signal: AbortSignal.timeout(20000)
1481
1944
  });
1482
1945
  const body = await res.json().catch(() => ({}));
1483
1946
  if (res.ok && typeof body.token === "string")
1484
- return { ok: true, token: body.token, created: body.created === true };
1947
+ return {
1948
+ ok: true,
1949
+ token: body.token,
1950
+ created: body.created === true,
1951
+ verifyPending: body.verifyPending === true
1952
+ };
1485
1953
  return {
1486
1954
  ok: false,
1487
1955
  reason: typeof body.reason === "string" ? body.reason : `http_${res.status}`,
@@ -1497,6 +1965,9 @@ var SIGNUP_REASONS = {
1497
1965
  key_rejected: "Anthropic did not accept that API key. Check it at console.anthropic.com → API keys.",
1498
1966
  rate_limited: "too many signups from this network in the last hour. Try again later.",
1499
1967
  not_configured: "the proxy is not set up for self-serve signup yet.",
1968
+ team: "the team needs a name (2–80 characters).",
1969
+ personal_email: "a team needs a work email — that domain is a personal mailbox. Sign up as an individual instead, or use your company address.",
1970
+ org_exists: "someone at your company already set up SLEDS. Ask them for a seat (Members → invite, Admin → Mint a seat) and run `sleds init --token …`.",
1500
1971
  unavailable: "the proxy could not reach its control plane. Try again in a moment.",
1501
1972
  unreachable: "could not reach the proxy."
1502
1973
  };
@@ -1522,6 +1993,20 @@ function normalizeProxyUrl(raw) {
1522
1993
  return null;
1523
1994
  }
1524
1995
  }
1996
+ async function fetchOrgInfo(url, token, fetchFn = fetch) {
1997
+ try {
1998
+ const res = await fetchFn(`${url}/proxy/meter`, {
1999
+ headers: { authorization: `Bearer ${token}` },
2000
+ signal: AbortSignal.timeout(1e4)
2001
+ });
2002
+ if (!res.ok)
2003
+ return null;
2004
+ const body = await res.json();
2005
+ return body.org?.capabilities ? body.org : null;
2006
+ } catch {
2007
+ return null;
2008
+ }
2009
+ }
1525
2010
  async function probeProxy(url, fetchFn = fetch, opts = {}) {
1526
2011
  const tries = opts.tries ?? 2;
1527
2012
  const timeoutMs = opts.timeoutMs ?? 1e4;
@@ -1550,21 +2035,45 @@ var resolveToken = async (o) => {
1550
2035
  if (typed)
1551
2036
  return { token: typed, source: "prompt" };
1552
2037
  }
1553
- const url = normalizeProxyUrl(o.url ?? env.SLEDS_PROXY_URL ?? DEFAULT_PROXY_URL);
2038
+ const url = normalizeProxyUrl(o.url ?? env.SLEDS_PROXY_URL ?? readConfig(o.home).proxyUrl ?? DEFAULT_PROXY_URL);
1554
2039
  if (!url)
1555
2040
  return null;
1556
- const email = (await o.prompt("Your email: ")).trim();
2041
+ const log = o.log ?? console.log;
2042
+ const err = o.error ?? console.error;
2043
+ let team = o.team?.trim() || null;
2044
+ if (team === null && !o.email) {
2045
+ const which = (await o.prompt("Set up SLEDS for (1) just you, or (2) your team? [1/2]: ")).trim();
2046
+ if (which === "2") {
2047
+ team = (await o.prompt("Team name (e.g. your company): ")).trim();
2048
+ if (!team)
2049
+ return null;
2050
+ }
2051
+ }
2052
+ const email = (o.email ?? await o.prompt(team ? "Your work email: " : "Your email: ")).trim();
1557
2053
  if (!email.includes("@"))
1558
2054
  return null;
2055
+ if (team) {
2056
+ const credential2 = (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();
2057
+ const r2 = await signupTeam(url, email, team, credential2 || null, o.fetchFn);
2058
+ if (!r2.ok) {
2059
+ err(signupFailureText(r2));
2060
+ return null;
2061
+ }
2062
+ 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."}`);
2063
+ if (r2.verifyPending)
2064
+ 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).`);
2065
+ log("Invite your team on the dashboard (Members → invite by email, Admin → Mint a seat); each person runs `sleds init --token …`.");
2066
+ return { token: r2.token, source: "signup" };
2067
+ }
1559
2068
  const credential = (await o.prompt("Your Anthropic API key (sk-ant-…, stored encrypted, spends only your account): ")).trim();
1560
2069
  if (!credential)
1561
2070
  return null;
1562
2071
  const r = await signupIndividual(url, email, credential, o.fetchFn);
1563
2072
  if (!r.ok) {
1564
- (o.error ?? console.error)(signupFailureText(r));
2073
+ err(signupFailureText(r));
1565
2074
  return null;
1566
2075
  }
1567
- (o.log ?? console.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.`);
2076
+ 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.`);
1568
2077
  return { token: r.token, source: "signup" };
1569
2078
  };
1570
2079
  var init = async (o) => {
@@ -1584,7 +2093,7 @@ var init = async (o) => {
1584
2093
  error("Invalid seat token: expected something like sled_xxxxxxxx.");
1585
2094
  return 2;
1586
2095
  }
1587
- const url = normalizeProxyUrl(o.url ?? env.SLEDS_PROXY_URL ?? DEFAULT_PROXY_URL);
2096
+ const url = normalizeProxyUrl(o.url ?? env.SLEDS_PROXY_URL ?? readConfig(o.home).proxyUrl ?? DEFAULT_PROXY_URL);
1588
2097
  if (!url) {
1589
2098
  error(`Invalid proxy URL: ${JSON.stringify(o.url ?? env.SLEDS_PROXY_URL ?? "")}. Expected https://proxy.sleds.ai.`);
1590
2099
  return 2;
@@ -1594,12 +2103,19 @@ var init = async (o) => {
1594
2103
  return 2;
1595
2104
  }
1596
2105
  const wrote = [];
2106
+ const org = await fetchOrgInfo(url, resolved.token, o.fetchFn);
2107
+ const wiring = o.proxyAlways ? "proxy-always" : o.seatFirst ? "seat-first" : org?.mode ?? "proxy-always";
2108
+ if (wiring === "proxy-always" && org && !org.capabilities.upstreamKey) {
2109
+ error(`${org.name} has no platform key for the proxy to forward with; --proxy-always would break every request. Using seat-first.`);
2110
+ }
2111
+ const finalWiring = wiring === "proxy-always" && org && !org.capabilities.upstreamKey ? "seat-first" : wiring;
1597
2112
  if (backupSettings(o.home))
1598
2113
  wrote.push(`backed up settings to ${backupPath(o.home)}`);
1599
- const withProxy = applyProxy(readSettings(o.home), { url, token: resolved.token });
1600
- const statusLine = applyStatusLine(withProxy, o.statusLineCommand ?? sledsCommand("statusline", o.home, o.env));
2114
+ const current = readSettings(o.home);
2115
+ const wired = finalWiring === "proxy-always" ? applyProxy(current, { url, token: resolved.token }) : removeProxy(current);
2116
+ const statusLine = applyStatusLine(wired, o.statusLineCommand ?? sledsCommand("statusline", o.home, o.env));
1601
2117
  writeSettings(o.home, statusLine.settings);
1602
- wrote.push(`set env.ANTHROPIC_BASE_URL and env.ANTHROPIC_AUTH_TOKEN in ${settingsPath(o.home)}`);
2118
+ 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`);
1603
2119
  wrote.push(statusLine.prior === undefined ? `set statusLine in ${settingsPath(o.home)}` : `set statusLine in ${settingsPath(o.home)} (previous one kept for uninstall)`);
1604
2120
  hooks2({
1605
2121
  home: o.home,
@@ -1619,24 +2135,47 @@ var init = async (o) => {
1619
2135
  ...prior,
1620
2136
  token: resolved.token,
1621
2137
  proxyUrl: url,
2138
+ wiring: finalWiring,
2139
+ ...org ? { org } : {},
1622
2140
  ...statusLine.prior !== undefined ? { priorStatusLine: statusLine.prior } : {}
1623
2141
  });
1624
2142
  wrote.push(`saved token and proxy URL to ${configPath(o.home)} (0600)`);
1625
2143
  mkdirSync6(skillDir(o.home), { recursive: true });
1626
2144
  writeFileSync6(skillPath(o.home), SKILL_MD);
1627
2145
  wrote.push(`installed skill at ${skillPath(o.home)}`);
1628
- log("Claude Code now runs through SLEDS on the org key.");
1629
- log("");
1630
- for (const w of wrote)
1631
- log(` ${w}`);
1632
- log("");
1633
- log(`Every request goes to ${url} and is metered to this seat. Run \`sleds status\` to check.`);
1634
- log("The status line shows your meter: spend today, seat limits, window, allowance, queued jobs.");
1635
- log("Prefer to burn your own Pro/Max/Team seat first? `sleds off` puts Claude Code back on it; `sleds on --until-reset +5h` switches to the org key at a wall.");
2146
+ if (o.installMusher) {
2147
+ const r = o.installMusher();
2148
+ if (r)
2149
+ wrote.push(r);
2150
+ }
2151
+ const orgLine = org ? `${org.name} · ${org.plan}${org.capabilities.upstreamKey ? ` · ${org.capabilities.upstreamSource === "own" ? "org key" : "shared key"}` : " · no platform key"}` : "org unknown (proxy did not answer /proxy/meter)";
2152
+ if (finalWiring === "proxy-always") {
2153
+ log(`Claude Code now runs through SLEDS on the org key. (${orgLine})`);
2154
+ log("");
2155
+ for (const w of wrote)
2156
+ log(` ${w}`);
2157
+ log("");
2158
+ log(`Every request goes to ${url} and is metered to this seat. Run \`sleds status\` to check.`);
2159
+ log("The status line shows your meter: spend today, seat limits, window, allowance, queued jobs.");
2160
+ log("Prefer your seat first? `sleds init --seat-first` leaves Claude Code on it and switches only at a wall.");
2161
+ } else {
2162
+ log(`SLEDS is watching your seat. Nothing changes until a wall. (${orgLine})`);
2163
+ log("");
2164
+ for (const w of wrote)
2165
+ log(` ${w}`);
2166
+ log("");
2167
+ log("Claude Code keeps running on your seat; the status line reports its quota to SLEDS on every turn.");
2168
+ if (org && !org.capabilities.upstreamKey) {
2169
+ log("This org has no platform key, so at a wall the choices are hold until reset, `sleds defer` (this Mac resumes the session itself at the reset), or hand off to a teammate. An admin can add a key on the dashboard to unlock continue / overnight / switch.");
2170
+ } else {
2171
+ log("At a wall: `sleds on --until-reset +5h` (or /sled 1) switches to the org key through the proxy until the reset; `sleds off` puts you back.");
2172
+ }
2173
+ }
1636
2174
  return 0;
1637
2175
  };
1638
2176
 
1639
2177
  // src/mcp.ts
2178
+ init_meter();
1640
2179
  var PROTOCOL_VERSION = "2025-06-18";
1641
2180
  var SERVER_INFO = { name: "sleds", version: "0.0.1" };
1642
2181
  var MCP_TIMEOUT_MS = 5000;
@@ -1992,8 +2531,17 @@ async function handoffsTool(deps) {
1992
2531
  if (handoffs.length === 0)
1993
2532
  return { text: "No open hand-offs on your team. Park one with the handoff tool." };
1994
2533
  const now = (deps.now ?? Date.now)();
1995
- return { text: handoffLines(handoffs, now).slice(1).join(`
1996
- `) };
2534
+ const packets = handoffs.map((h) => str2(h.packet)).filter((p) => Boolean(p)).join(`
2535
+
2536
+ ---
2537
+
2538
+ `);
2539
+ return {
2540
+ text: [handoffLines(handoffs, now).slice(1).join(`
2541
+ `), packets ? `
2542
+ ${packets}` : ""].join(`
2543
+ `)
2544
+ };
1997
2545
  }
1998
2546
  async function handoffTool(deps, args) {
1999
2547
  if (!meterSource(deps.home))
@@ -2161,6 +2709,8 @@ var mcp = async (o) => {
2161
2709
  };
2162
2710
 
2163
2711
  // src/commands/meter.ts
2712
+ init_config();
2713
+ init_meter();
2164
2714
  var meter = async (o) => {
2165
2715
  const log = o.log ?? console.log;
2166
2716
  const now = (o.now ?? Date.now)();
@@ -2179,14 +2729,232 @@ var meter = async (o) => {
2179
2729
  return 0;
2180
2730
  };
2181
2731
 
2732
+ // src/commands/musher.ts
2733
+ init_config();
2734
+ init_meter();
2735
+ import { spawnSync as spawnSync2 } from "node:child_process";
2736
+ import { existsSync as existsSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync7, rmSync as rmSync2, writeFileSync as writeFileSync7 } from "node:fs";
2737
+ import { hostname as hostname2 } from "node:os";
2738
+ import { dirname as dirname3 } from "node:path";
2739
+ var defaultWhich3 = (cmd) => {
2740
+ const path = process.env.PATH ?? "";
2741
+ for (const dir of path.split(":").filter(Boolean)) {
2742
+ const p = `${dir}/${cmd}`;
2743
+ if (existsSync8(p))
2744
+ return p;
2745
+ }
2746
+ return null;
2747
+ };
2748
+ var findClaude2 = (home, configured, which) => {
2749
+ if (configured && existsSync8(configured))
2750
+ return configured;
2751
+ const found = which("claude");
2752
+ if (found)
2753
+ return found;
2754
+ for (const p of [
2755
+ `${home}/.local/bin/claude`,
2756
+ "/opt/homebrew/bin/claude",
2757
+ "/usr/local/bin/claude",
2758
+ `${home}/.npm-global/bin/claude`
2759
+ ])
2760
+ if (existsSync8(p))
2761
+ return p;
2762
+ return null;
2763
+ };
2764
+ var musherInstall = (o) => {
2765
+ const log = o.log ?? console.log;
2766
+ const error = o.error ?? console.error;
2767
+ const platform = o.platform ?? process.platform;
2768
+ if (platform !== "darwin") {
2769
+ error(`sleds musher --install needs launchd (macOS). On ${platform}, run \`sleds musher tick\` from cron every 5 minutes.`);
2770
+ return 1;
2771
+ }
2772
+ const env = o.env ?? process.env;
2773
+ const plist = musherPlistPath(o.home);
2774
+ const dir = configDir(o.home, env);
2775
+ mkdirSync7(dirname3(plist), { recursive: true });
2776
+ mkdirSync7(dir, { recursive: true, mode: 448 });
2777
+ const execPath = o.sledsArgv[0] ?? process.execPath;
2778
+ const agentEnv = {
2779
+ PATH: musherPath(o.home, execPath, env.PATH ?? ""),
2780
+ HOME: o.home,
2781
+ ...env.SLEDS_HOME ? { SLEDS_HOME: env.SLEDS_HOME } : {},
2782
+ ...env.CLAUDE_CONFIG_DIR ? { CLAUDE_CONFIG_DIR: env.CLAUDE_CONFIG_DIR } : {}
2783
+ };
2784
+ const exec = o.exec ?? defaultExecSync;
2785
+ if (existsSync8(plist))
2786
+ exec("launchctl", ["unload", plist]);
2787
+ writeFileSync7(plist, buildMusherPlist({ sledsArgv: o.sledsArgv, env: agentEnv, logPath: musherLogPath(dir) }));
2788
+ const r = exec("launchctl", ["load", plist]);
2789
+ if (!r.ok) {
2790
+ error(`launchctl load failed: ${r.stderr.trim() || "unknown"}`);
2791
+ return 1;
2792
+ }
2793
+ const cfg = readConfig(o.home);
2794
+ writeConfig(o.home, { ...cfg, musher: { ...cfg.musher ?? {}, agent: "launchd" } });
2795
+ const claude = findClaude2(o.home, cfg.musher?.claudePath, o.which ?? defaultWhich3);
2796
+ log(`musher installed: launchd agent ${MUSHER_LABEL}, every ${5} min · log ${musherLogPath(dir)}`);
2797
+ if (!claude)
2798
+ log("warn: `claude` not found on PATH — set it with `sleds musher --claude /path/to/claude`");
2799
+ return 0;
2800
+ };
2801
+ var musherUninstall = (o) => {
2802
+ const log = o.log ?? console.log;
2803
+ const plist = musherPlistPath(o.home);
2804
+ const exec = o.exec ?? defaultExecSync;
2805
+ if (existsSync8(plist)) {
2806
+ exec("launchctl", ["unload", plist]);
2807
+ rmSync2(plist, { force: true });
2808
+ log(`musher removed: ${MUSHER_LABEL}`);
2809
+ } else
2810
+ log("musher was not installed.");
2811
+ const cfg = readConfig(o.home);
2812
+ if (cfg.musher)
2813
+ writeConfig(o.home, { ...cfg, musher: { ...cfg.musher, agent: "none" } });
2814
+ return 0;
2815
+ };
2816
+ var formatMusherStatus = (list, now) => {
2817
+ const lines = [];
2818
+ for (const j of list.running)
2819
+ lines.push(`running ${j.jobId}${j.startedAt ? ` · since ${formatLocal(j.startedAt)} (${formatDuration(now - j.startedAt)})` : ""}`);
2820
+ for (const j of list.due)
2821
+ lines.push(`due now ${j.jobId}${j.model ? ` · ${j.model}` : ""} · was ${formatLocal(j.scheduledAt)}`);
2822
+ for (const j of list.upcoming)
2823
+ lines.push(`waiting ${j.jobId}${j.model ? ` · ${j.model}` : ""} · starts ${formatLocal(j.scheduledAt)} (in ${formatDuration(j.scheduledAt - now)})`);
2824
+ if (lines.length === 0)
2825
+ lines.push("nothing deferred on this seat.");
2826
+ return lines;
2827
+ };
2828
+ var clientFor = (o) => {
2829
+ if (o.client)
2830
+ return o.client;
2831
+ const src = meterSource(o.home);
2832
+ return src ? musherClient({ ...src, fetchFn: o.fetchFn }) : null;
2833
+ };
2834
+ var musherStatus = async (o) => {
2835
+ const log = o.log ?? console.log;
2836
+ const now = (o.now ?? Date.now)();
2837
+ const plist = musherPlistPath(o.home);
2838
+ const cfg = readConfig(o.home);
2839
+ log(existsSync8(plist) ? `agent ${MUSHER_LABEL} installed (${plist})` : "agent not installed — sleds musher --install");
2840
+ const claude = findClaude2(o.home, cfg.musher?.claudePath, o.which ?? defaultWhich3);
2841
+ log(`claude ${claude ?? "not found — sleds musher --claude /path/to/claude"}`);
2842
+ log(`mode ${cfg.musher?.permissionMode ?? DEFAULT_PERMISSION_MODE} · timeout ${cfg.musher?.timeoutMinutes ?? DEFAULT_TIMEOUT_MINUTES} min`);
2843
+ const client = clientFor(o);
2844
+ if (!client) {
2845
+ log("seat not initialised (sleds init)");
2846
+ return 1;
2847
+ }
2848
+ const list = await client.list();
2849
+ if (!list) {
2850
+ log("proxy unreachable");
2851
+ return 1;
2852
+ }
2853
+ for (const line of formatMusherStatus(list, now))
2854
+ log(line);
2855
+ return 0;
2856
+ };
2857
+ var musherTick = async (o) => {
2858
+ const log = o.log ?? console.log;
2859
+ const client = clientFor(o);
2860
+ if (!client) {
2861
+ log("musher: seat not initialised; nothing to do");
2862
+ return 1;
2863
+ }
2864
+ const list = await client.list();
2865
+ if (!list) {
2866
+ log("musher: proxy unreachable; will try again next tick");
2867
+ return 0;
2868
+ }
2869
+ if (list.due.length === 0)
2870
+ return 0;
2871
+ const cfg = readConfig(o.home);
2872
+ const claude = findClaude2(o.home, cfg.musher?.claudePath, o.which ?? defaultWhich3) ?? "claude";
2873
+ const seat = readSeatState(o.home);
2874
+ for (const job of list.due) {
2875
+ const out = await runJob({
2876
+ job,
2877
+ client,
2878
+ fallbackSession: seat.session,
2879
+ host: o.host ?? hostname2(),
2880
+ claudePath: claude,
2881
+ permissionMode: cfg.musher?.permissionMode ?? DEFAULT_PERMISSION_MODE,
2882
+ timeoutMs: (cfg.musher?.timeoutMinutes ?? DEFAULT_TIMEOUT_MINUTES) * 60000,
2883
+ exec: o.execCapture,
2884
+ log
2885
+ });
2886
+ if (out.kind === "skipped")
2887
+ log(`musher: job ${job.jobId} skipped — ${out.reason}`);
2888
+ }
2889
+ return 0;
2890
+ };
2891
+ var musherConfigure = (o, flags) => {
2892
+ const log = o.log ?? console.log;
2893
+ const cfg = readConfig(o.home);
2894
+ const musher = { ...cfg.musher ?? {} };
2895
+ if (flags.claude)
2896
+ musher.claudePath = flags.claude;
2897
+ if (flags.mode)
2898
+ musher.permissionMode = flags.mode;
2899
+ if (flags.timeout) {
2900
+ const n = Number.parseInt(flags.timeout, 10);
2901
+ if (!Number.isFinite(n) || n <= 0) {
2902
+ (o.error ?? console.error)("--timeout takes minutes, a positive number");
2903
+ return 1;
2904
+ }
2905
+ musher.timeoutMinutes = n;
2906
+ }
2907
+ writeConfig(o.home, { ...cfg, musher });
2908
+ log(`musher settings: claude ${musher.claudePath ?? "(PATH)"} · mode ${musher.permissionMode ?? DEFAULT_PERMISSION_MODE} · timeout ${musher.timeoutMinutes ?? DEFAULT_TIMEOUT_MINUTES} min`);
2909
+ return 0;
2910
+ };
2911
+ var defaultExecSync = (cmd, args) => {
2912
+ const r = spawnSync2(cmd, [...args], { stdio: ["ignore", "ignore", "pipe"], encoding: "utf8" });
2913
+ if (r.error)
2914
+ return { ok: false, stderr: r.error.message };
2915
+ return { ok: r.status === 0, stderr: r.stderr ?? "" };
2916
+ };
2917
+ var musher = async (o) => {
2918
+ const args = [...o.argv];
2919
+ const flags = {};
2920
+ const positional = [];
2921
+ for (let i = 0;i < args.length; i++) {
2922
+ const a = args[i] ?? "";
2923
+ if (a.startsWith("--")) {
2924
+ const next = args[i + 1];
2925
+ if (next !== undefined && !next.startsWith("--")) {
2926
+ flags[a.slice(2)] = next;
2927
+ i++;
2928
+ } else
2929
+ flags[a.slice(2)] = "true";
2930
+ } else
2931
+ positional.push(a);
2932
+ }
2933
+ if (flags.install)
2934
+ return musherInstall(o);
2935
+ if (flags.uninstall)
2936
+ return musherUninstall(o);
2937
+ if (flags.claude || flags.mode || flags.timeout)
2938
+ return musherConfigure(o, flags);
2939
+ if (positional[0] === "tick")
2940
+ return musherTick(o);
2941
+ if (flags.status || positional.length === 0)
2942
+ return musherStatus(o);
2943
+ (o.error ?? console.error)(`sleds musher: unknown argument ${positional[0]}`);
2944
+ return 1;
2945
+ };
2946
+
2947
+ // src/commands/off.ts
2948
+ init_config();
2949
+
2182
2950
  // src/schedule.ts
2183
- import { existsSync as existsSync7, mkdirSync as mkdirSync7, rmSync, writeFileSync as writeFileSync7 } from "node:fs";
2184
- import { join as join8 } from "node:path";
2951
+ import { existsSync as existsSync9, mkdirSync as mkdirSync8, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
2952
+ import { join as join7 } from "node:path";
2185
2953
  var REVERT_LABEL = "ai.sleds.revert";
2186
- var plistPath = (home) => join8(home, "Library", "LaunchAgents", `${REVERT_LABEL}.plist`);
2187
- var xmlEscape = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
2954
+ var plistPath = (home) => join7(home, "Library", "LaunchAgents", `${REVERT_LABEL}.plist`);
2955
+ var xmlEscape2 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
2188
2956
  var buildLaunchdPlist = (sledsArgv, deadline) => {
2189
- const args = [...sledsArgv, "off"].map((a) => ` <string>${xmlEscape(a)}</string>`).join(`
2957
+ const args = [...sledsArgv, "off"].map((a) => ` <string>${xmlEscape2(a)}</string>`).join(`
2190
2958
  `);
2191
2959
  return `<?xml version="1.0" encoding="UTF-8"?>
2192
2960
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -2222,9 +2990,9 @@ var scheduleRevert = (d, deadlineMs) => {
2222
2990
  if (d.platform === "darwin") {
2223
2991
  const p = plistPath(d.home);
2224
2992
  try {
2225
- mkdirSync7(join8(d.home, "Library", "LaunchAgents"), { recursive: true });
2993
+ mkdirSync8(join7(d.home, "Library", "LaunchAgents"), { recursive: true });
2226
2994
  d.exec("launchctl", ["unload", p]);
2227
- writeFileSync7(p, buildLaunchdPlist(d.sledsArgv, deadline));
2995
+ writeFileSync8(p, buildLaunchdPlist(d.sledsArgv, deadline));
2228
2996
  const r = d.exec("launchctl", ["load", p]);
2229
2997
  if (r.ok)
2230
2998
  return { kind: "launchd", detail: `launchd agent ${REVERT_LABEL}` };
@@ -2251,9 +3019,9 @@ var scheduleRevert = (d, deadlineMs) => {
2251
3019
  var cancelRevert = (d, kind) => {
2252
3020
  if (kind === "launchd" || d.platform === "darwin") {
2253
3021
  const p = plistPath(d.home);
2254
- if (existsSync7(p)) {
3022
+ if (existsSync9(p)) {
2255
3023
  d.exec("launchctl", ["unload", p]);
2256
- rmSync(p, { force: true });
3024
+ rmSync3(p, { force: true });
2257
3025
  }
2258
3026
  }
2259
3027
  if (kind === "systemd" || d.platform === "linux") {
@@ -2262,6 +3030,7 @@ var cancelRevert = (d, kind) => {
2262
3030
  };
2263
3031
 
2264
3032
  // src/commands/off.ts
3033
+ init_settings();
2265
3034
  var off = (o) => {
2266
3035
  const log = o.log ?? console.log;
2267
3036
  const cfg = readConfig(o.home);
@@ -2289,7 +3058,13 @@ var off = (o) => {
2289
3058
  return 0;
2290
3059
  };
2291
3060
 
3061
+ // src/commands/on.ts
3062
+ init_config();
3063
+ init_settings();
3064
+
2292
3065
  // src/commands/init.ts
3066
+ init_config();
3067
+ init_settings();
2293
3068
  var DEFAULT_PROXY_URL2 = "http://localhost:8787";
2294
3069
 
2295
3070
  // src/commands/on.ts
@@ -2312,6 +3087,10 @@ var on = (o) => {
2312
3087
  error("Saved token is not a sled_ token. Run `sleds init --token <sled_…>`.");
2313
3088
  return 2;
2314
3089
  }
3090
+ if (cfg.org && !cfg.org.capabilities.upstreamKey) {
3091
+ error(`${cfg.org.name} has no platform key, so there is no org key to switch to. Hold until the reset, or hand off with /sled 5. An admin can add a key on the dashboard.`);
3092
+ return 2;
3093
+ }
2315
3094
  const url = (o.url ?? cfg.proxyUrl ?? env.SLEDS_PROXY_URL ?? DEFAULT_PROXY_URL2).replace(/\/+$/, "");
2316
3095
  let untilResetMs;
2317
3096
  if (o.untilReset !== undefined) {
@@ -2365,7 +3144,70 @@ var on = (o) => {
2365
3144
  return 0;
2366
3145
  };
2367
3146
 
3147
+ // src/commands/run.ts
3148
+ init_config();
3149
+ init_meter();
3150
+ import { hostname as hostname3 } from "node:os";
3151
+ var run = async (o) => {
3152
+ const log = o.log ?? console.log;
3153
+ const error = o.error ?? console.error;
3154
+ if (!o.jobId) {
3155
+ error("usage: sleds run <jobId>");
3156
+ return 2;
3157
+ }
3158
+ const client = o.client ?? (() => {
3159
+ const src = meterSource(o.home);
3160
+ return src ? musherClient({ ...src, fetchFn: o.fetchFn }) : null;
3161
+ })();
3162
+ if (!client) {
3163
+ error("No seat on this machine. Run `sleds init` first.");
3164
+ return 1;
3165
+ }
3166
+ const list = await client.list();
3167
+ if (!list) {
3168
+ error("Could not reach the SLEDS proxy.");
3169
+ return 1;
3170
+ }
3171
+ const job = [...list.due, ...list.upcoming].find((j) => j.jobId === o.jobId);
3172
+ if (!job) {
3173
+ error(`Job ${o.jobId} is not a scheduled local job on this seat (sleds musher --status lists them).`);
3174
+ return 1;
3175
+ }
3176
+ const cfg = readConfig(o.home);
3177
+ const claude = findClaude(o.home, cfg.musher?.claudePath, o.which ?? defaultWhich);
3178
+ if (!claude) {
3179
+ error("`claude` not found. Install Claude Code, or `sleds musher --claude /path/to/claude`.");
3180
+ return 1;
3181
+ }
3182
+ const out = await runJob({
3183
+ job,
3184
+ client,
3185
+ fallbackSession: readSeatState(o.home).session,
3186
+ host: o.host ?? hostname3(),
3187
+ claudePath: claude,
3188
+ permissionMode: cfg.musher?.permissionMode ?? DEFAULT_PERMISSION_MODE,
3189
+ timeoutMs: (cfg.musher?.timeoutMinutes ?? DEFAULT_TIMEOUT_MINUTES) * 60000,
3190
+ exec: o.execCapture,
3191
+ log
3192
+ });
3193
+ if (out.kind === "skipped") {
3194
+ error(`Not run: ${out.reason}`);
3195
+ return 1;
3196
+ }
3197
+ log(out.summary);
3198
+ if (out.ok) {
3199
+ const a = await client.attestation(job.jobId);
3200
+ if (a)
3201
+ log(a.attestation.trailer);
3202
+ else
3203
+ log(`(attestation pending — sleds verify ${job.jobId})`);
3204
+ }
3205
+ return out.ok ? 0 : 1;
3206
+ };
3207
+
2368
3208
  // src/commands/seatEvent.ts
3209
+ init_config();
3210
+ init_meter();
2369
3211
  var HOOK_STDIN_TIMEOUT_MS = 1000;
2370
3212
  var NOTIFICATION_TITLE = "sleds";
2371
3213
  var isObject7 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
@@ -2407,25 +3249,26 @@ var seatEvent = async (o) => {
2407
3249
  if (week && week.resetsAt > now)
2408
3250
  writeSeatState(o.home, { ...state, lastWallResetsAt: week.resetsAt });
2409
3251
  } catch {}
2410
- log(SEAT_WALL_LINE);
3252
+ const line = seatWallLine(readConfig(o.home).org?.capabilities.upstreamKey !== false);
3253
+ log(line);
2411
3254
  if ((o.platform ?? process.platform) === "darwin" && o.exec) {
2412
3255
  try {
2413
- o.exec("osascript", osascriptArgs(NOTIFICATION_TITLE, SEAT_WALL_LINE));
3256
+ o.exec("osascript", osascriptArgs(NOTIFICATION_TITLE, line));
2414
3257
  } catch {}
2415
3258
  }
2416
3259
  return 0;
2417
3260
  };
2418
3261
 
2419
3262
  // src/commands/seatSync.ts
2420
- import { execFileSync as execFileSync4 } from "node:child_process";
2421
- import { existsSync as existsSync8, mkdirSync as mkdirSync8, readFileSync as readFileSync6, readdirSync as readdirSync2, writeFileSync as writeFileSync8 } from "node:fs";
3263
+ import { execFileSync as execFileSync2 } from "node:child_process";
3264
+ import { existsSync as existsSync10, mkdirSync as mkdirSync9, readFileSync as readFileSync8, readdirSync as readdirSync2, writeFileSync as writeFileSync9 } from "node:fs";
2422
3265
  import { platform } from "node:os";
2423
- import { join as join10 } from "node:path";
3266
+ import { join as join9 } from "node:path";
2424
3267
 
2425
3268
  // src/cookieDb.ts
2426
- import { copyFileSync, rmSync as rmSync2 } from "node:fs";
3269
+ import { copyFileSync, rmSync as rmSync4 } from "node:fs";
2427
3270
  import { tmpdir } from "node:os";
2428
- import { join as join9 } from "node:path";
3271
+ import { join as join8 } from "node:path";
2429
3272
  var QUERY = "SELECT name, hex(encrypted_value) AS ev FROM cookies WHERE host_key LIKE '%claude.ai%'";
2430
3273
  var isBun = () => typeof globalThis.Bun !== "undefined";
2431
3274
  async function queryRows(dbPath) {
@@ -2454,18 +3297,21 @@ function nodeSqlite() {
2454
3297
  return mod;
2455
3298
  }
2456
3299
  async function readCookieRows(dbPath) {
2457
- const copy = join9(tmpdir(), `sleds-cookies-${process.pid}-${Date.now()}.sqlite`);
3300
+ const copy = join8(tmpdir(), `sleds-cookies-${process.pid}-${Date.now()}.sqlite`);
2458
3301
  copyFileSync(dbPath, copy);
2459
3302
  try {
2460
3303
  const rows = await queryRows(copy);
2461
3304
  return rows.map((r) => ({ name: r.name, encrypted_value: Buffer.from(r.ev, "hex") }));
2462
3305
  } finally {
2463
3306
  try {
2464
- rmSync2(copy, { force: true });
3307
+ rmSync4(copy, { force: true });
2465
3308
  } catch {}
2466
3309
  }
2467
3310
  }
2468
3311
 
3312
+ // src/commands/seatSync.ts
3313
+ init_meter();
3314
+
2469
3315
  // src/seatSync.ts
2470
3316
  import { createDecipheriv, pbkdf2Sync } from "node:crypto";
2471
3317
  var BROWSERS = {
@@ -2611,13 +3457,13 @@ function parseUsageResponse(raw, now = Date.now()) {
2611
3457
  const resetsAt = parseResetsAt(v.resets_at);
2612
3458
  if (usedPct === undefined || usedPct < 0 || resetsAt === undefined)
2613
3459
  continue;
2614
- const bar2 = { usedPct, resetsAt };
3460
+ const bar = { usedPct, resetsAt };
2615
3461
  if (k === "five_hour")
2616
- out.fiveHour = bar2;
3462
+ out.fiveHour = bar;
2617
3463
  else if (k === "seven_day")
2618
- out.sevenDay = bar2;
3464
+ out.sevenDay = bar;
2619
3465
  else
2620
- out.models[k] = bar2;
3466
+ out.models[k] = bar;
2621
3467
  }
2622
3468
  const hasAny = out.fiveHour || out.sevenDay || Object.keys(out.models).length > 0 || out.usedCreditsUsd !== undefined;
2623
3469
  return hasAny ? out : null;
@@ -2727,7 +3573,7 @@ function findFile(root, name) {
2727
3573
  const stack = [root];
2728
3574
  while (stack.length > 0) {
2729
3575
  const dir = stack.pop();
2730
- if (!dir || !existsSync8(dir))
3576
+ if (!dir || !existsSync10(dir))
2731
3577
  continue;
2732
3578
  let entries;
2733
3579
  try {
@@ -2736,7 +3582,7 @@ function findFile(root, name) {
2736
3582
  continue;
2737
3583
  }
2738
3584
  for (const e of entries) {
2739
- const p = join10(dir, e.name);
3585
+ const p = join9(dir, e.name);
2740
3586
  if (e.isDirectory())
2741
3587
  stack.push(p);
2742
3588
  else if (e.name === name)
@@ -2747,8 +3593,8 @@ function findFile(root, name) {
2747
3593
  }
2748
3594
  function findCookieDb(home, source) {
2749
3595
  const b = BROWSERS[source.browser];
2750
- const root = join10(home, APP_SUPPORT, b.appDir);
2751
- if (!existsSync8(root))
3596
+ const root = join9(home, APP_SUPPORT, b.appDir);
3597
+ if (!existsSync10(root))
2752
3598
  throw new Error(`no ${source.browser} data at ${root} (is it installed?)`);
2753
3599
  if (!b.profiled) {
2754
3600
  const db2 = findFile(root, "Cookies");
@@ -2756,15 +3602,15 @@ function findCookieDb(home, source) {
2756
3602
  throw new Error(`no cookie store under ${root}`);
2757
3603
  return db2;
2758
3604
  }
2759
- const localStatePath = join10(root, "Local State");
2760
- const localState = existsSync8(localStatePath) ? readFileSync6(localStatePath, "utf8") : null;
3605
+ const localStatePath = join9(root, "Local State");
3606
+ const localState = existsSync10(localStatePath) ? readFileSync8(localStatePath, "utf8") : null;
2761
3607
  const wanted = source.profile ?? "Default";
2762
3608
  const { dir, ambiguous } = resolveProfileDir(localState, wanted);
2763
3609
  if (ambiguous)
2764
3610
  throw new Error(`"${wanted}" names ${ambiguous.length} ${source.browser} profiles (${ambiguous.join(", ")}) — pass the directory or the account email instead`);
2765
3611
  if (!dir)
2766
3612
  throw new Error(`no ${source.browser} profile named "${wanted}" (check chrome://version)`);
2767
- const db = cookieDbCandidates(join10(root, dir)).find((p) => existsSync8(p));
3613
+ const db = cookieDbCandidates(join9(root, dir)).find((p) => existsSync10(p));
2768
3614
  if (!db)
2769
3615
  throw new Error(`profile "${dir}" has no cookie store yet (open claude.ai in it once)`);
2770
3616
  return db;
@@ -2774,7 +3620,7 @@ async function readCookieRowsBun(home, source) {
2774
3620
  }
2775
3621
  function keychainKey(service) {
2776
3622
  try {
2777
- return execFileSync4("security", ["find-generic-password", "-w", "-s", service], {
3623
+ return execFileSync2("security", ["find-generic-password", "-w", "-s", service], {
2778
3624
  encoding: "utf8"
2779
3625
  }).trim();
2780
3626
  } catch {
@@ -2786,7 +3632,7 @@ function decryptJar(rows, safeStoragePw) {
2786
3632
  }
2787
3633
  var curlUsage = (org, cookie) => {
2788
3634
  try {
2789
- const out = execFileSync4("curl", usageCurlArgs(org, cookie), {
3635
+ const out = execFileSync2("curl", usageCurlArgs(org, cookie), {
2790
3636
  encoding: "utf8",
2791
3637
  maxBuffer: 8000000
2792
3638
  });
@@ -2795,8 +3641,8 @@ var curlUsage = (org, cookie) => {
2795
3641
  return { status: 0, body: "" };
2796
3642
  }
2797
3643
  };
2798
- function fetchSeatUsage(jar, org, now, run) {
2799
- const { status, body } = run(org, cookieHeader(jar, org));
3644
+ function fetchSeatUsage(jar, org, now, run2) {
3645
+ const { status, body } = run2(org, cookieHeader(jar, org));
2800
3646
  if (status !== 200)
2801
3647
  return { usage: null, status };
2802
3648
  try {
@@ -2807,7 +3653,7 @@ function fetchSeatUsage(jar, org, now, run) {
2807
3653
  }
2808
3654
  function launchAgentPlist(bun, script, home, source) {
2809
3655
  const label = launchLabel(source);
2810
- const log = join10(home, ".config", "sleds", `${label.slice("ai.sleds.".length)}.log`);
3656
+ const log = join9(home, ".config", "sleds", `${label.slice("ai.sleds.".length)}.log`);
2811
3657
  const esc = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
2812
3658
  const args = [bun, script, "seat-sync", ...sourceArgs(source)].map((a) => ` <string>${esc(a)}</string>`).join(`
2813
3659
  `);
@@ -2829,32 +3675,32 @@ ${args}
2829
3675
  `;
2830
3676
  }
2831
3677
  function plistPath2(home, source) {
2832
- return join10(home, "Library", "LaunchAgents", `${launchLabel(source)}.plist`);
3678
+ return join9(home, "Library", "LaunchAgents", `${launchLabel(source)}.plist`);
2833
3679
  }
2834
- function install2(home, argv, source, log) {
3680
+ function install(home, argv, source, log) {
2835
3681
  const bun = argv[0] ?? process.execPath;
2836
3682
  const script = argv[1] ?? "";
2837
3683
  if (!script) {
2838
3684
  log("cannot resolve the sleds script path to install the timer");
2839
3685
  return 1;
2840
3686
  }
2841
- const dir = join10(home, "Library", "LaunchAgents");
2842
- mkdirSync8(dir, { recursive: true });
3687
+ const dir = join9(home, "Library", "LaunchAgents");
3688
+ mkdirSync9(dir, { recursive: true });
2843
3689
  const path = plistPath2(home, source);
2844
- writeFileSync8(path, launchAgentPlist(bun, script, home, source), { mode: 384 });
3690
+ writeFileSync9(path, launchAgentPlist(bun, script, home, source), { mode: 384 });
2845
3691
  try {
2846
- execFileSync4("launchctl", ["unload", path], { stdio: "ignore" });
3692
+ execFileSync2("launchctl", ["unload", path], { stdio: "ignore" });
2847
3693
  } catch {}
2848
- execFileSync4("launchctl", ["load", "-w", path]);
3694
+ execFileSync2("launchctl", ["load", "-w", path]);
2849
3695
  log(`seat-sync timer installed (every ${SYNC_INTERVAL_S / 60} min) → ${path}`);
2850
3696
  return 0;
2851
3697
  }
2852
- function uninstall2(home, source, log) {
3698
+ function uninstall(home, source, log) {
2853
3699
  const path = plistPath2(home, source);
2854
3700
  try {
2855
- execFileSync4("launchctl", ["unload", "-w", path], { stdio: "ignore" });
3701
+ execFileSync2("launchctl", ["unload", "-w", path], { stdio: "ignore" });
2856
3702
  } catch {}
2857
- log(existsSync8(path) ? `seat-sync timer removed (${path} can be deleted)` : "no seat-sync timer");
3703
+ log(existsSync10(path) ? `seat-sync timer removed (${path} can be deleted)` : "no seat-sync timer");
2858
3704
  return 0;
2859
3705
  }
2860
3706
  var seatSync = async (o) => {
@@ -2867,9 +3713,9 @@ var seatSync = async (o) => {
2867
3713
  }
2868
3714
  const { source } = parsed;
2869
3715
  if (source.uninstall)
2870
- return uninstall2(o.home, source, log);
3716
+ return uninstall(o.home, source, log);
2871
3717
  if (source.install)
2872
- return install2(o.home, [process.execPath, process.argv[1] ?? ""], source, log);
3718
+ return install(o.home, [process.execPath, process.argv[1] ?? ""], source, log);
2873
3719
  if (platform() !== "darwin" && !o.readCookieRows) {
2874
3720
  log("seat-sync is macOS-only for now.");
2875
3721
  return 2;
@@ -2949,7 +3795,8 @@ async function postSeat(proxyUrl, token, body, fetchFn) {
2949
3795
  }
2950
3796
 
2951
3797
  // src/commands/specEvent.ts
2952
- import { readFileSync as readFileSync7, statSync } from "node:fs";
3798
+ init_meter();
3799
+ import { readFileSync as readFileSync9, statSync } from "node:fs";
2953
3800
  import { basename, isAbsolute, relative } from "node:path";
2954
3801
  var HOOK_STDIN_TIMEOUT_MS2 = 1000;
2955
3802
  var ESTIMATE_TIMEOUT_MS = 4000;
@@ -3005,7 +3852,7 @@ function readFileOrNull(path) {
3005
3852
  try {
3006
3853
  if (statSync(path).size > 2000000)
3007
3854
  return null;
3008
- return readFileSync7(path, "utf8");
3855
+ return readFileSync9(path, "utf8");
3009
3856
  } catch {
3010
3857
  return null;
3011
3858
  }
@@ -3048,7 +3895,9 @@ var specEvent = async (o) => {
3048
3895
  };
3049
3896
 
3050
3897
  // src/commands/status.ts
3051
- import { existsSync as existsSync9 } from "node:fs";
3898
+ init_config();
3899
+ init_settings();
3900
+ import { existsSync as existsSync11 } from "node:fs";
3052
3901
  var checkHealth2 = async (url, fetchFn = fetch, timeoutMs = 1000) => {
3053
3902
  try {
3054
3903
  const res = await fetchFn(`${url}/healthz`, { signal: AbortSignal.timeout(timeoutMs) });
@@ -3107,6 +3956,10 @@ var formatStatus = (s) => {
3107
3956
  }
3108
3957
  if (s.email)
3109
3958
  lines.push(row2("Seat:", s.email));
3959
+ if (s.org)
3960
+ lines.push(row2("Org:", `${s.org.name} · ${s.org.plan} · ${s.org.upstream === "none" ? "no platform key (walls: hold or hand off)" : s.org.upstream === "own" ? "org key" : "shared key"}`));
3961
+ if (s.wiring)
3962
+ lines.push(row2("Wiring:", s.wiring === "seat-first" ? "seat-first — Claude Code on your seat; the proxy only after `sleds on`" : "proxy-always — every request through the proxy"));
3110
3963
  if (s.mode === "off") {
3111
3964
  lines.push(s.pointed ? "Claude Code is pointed at the proxy by settings.json (set by `sleds init`)." : "Claude Code is on your seat. Hit a limit? `sleds on --until-reset +5h`.");
3112
3965
  }
@@ -3116,7 +3969,7 @@ var status = async (o) => {
3116
3969
  const log = o.log ?? console.log;
3117
3970
  const nowMs = (o.now ?? Date.now)();
3118
3971
  const cfg = readConfig(o.home);
3119
- const settings = existsSync9(settingsPath(o.home)) ? readSettings(o.home) : {};
3972
+ const settings = existsSync11(settingsPath(o.home)) ? readSettings(o.home) : {};
3120
3973
  const inSettings = readProxy(settings);
3121
3974
  const proxyUrl = inSettings?.url ?? cfg.proxyUrl;
3122
3975
  const token = inSettings?.token ?? cfg.token;
@@ -3138,6 +3991,14 @@ var status = async (o) => {
3138
3991
  info.tokenMasked = maskToken(token);
3139
3992
  if (cfg.email)
3140
3993
  info.email = cfg.email;
3994
+ if (cfg.wiring)
3995
+ info.wiring = cfg.wiring;
3996
+ if (cfg.org)
3997
+ info.org = {
3998
+ name: cfg.org.name,
3999
+ plan: cfg.org.plan,
4000
+ upstream: cfg.org.capabilities.upstreamSource
4001
+ };
3141
4002
  if (cfg.reason)
3142
4003
  info.reason = cfg.reason;
3143
4004
  if (o.tz)
@@ -3162,15 +4023,19 @@ var status = async (o) => {
3162
4023
  };
3163
4024
 
3164
4025
  // src/commands/statusline.ts
4026
+ init_meter();
3165
4027
  var statusline = async (o) => {
3166
4028
  const log = o.log ?? console.log;
3167
4029
  const now = (o.now ?? Date.now)();
3168
4030
  const input = o.stdin ?? await readStdin(STDIN_TIMEOUT_MS);
3169
4031
  const window = seatWindowFromStdin(input, now);
4032
+ const session = seatSessionFromStdin(input, now);
3170
4033
  let posts = [];
3171
4034
  try {
3172
4035
  if (window)
3173
- posts = rememberSeat(o, window, now);
4036
+ posts = rememberSeat(o, window, session, now);
4037
+ else if (session)
4038
+ writeSeatState(o.home, { ...readSeatState(o.home), session });
3174
4039
  } catch {}
3175
4040
  const seatFragment = formatSeatFragment(window);
3176
4041
  let line;
@@ -3189,9 +4054,9 @@ var statusline = async (o) => {
3189
4054
  await Promise.allSettled(posts);
3190
4055
  return 0;
3191
4056
  };
3192
- var rememberSeat = (o, window, now) => {
4057
+ var rememberSeat = (o, window, session, now) => {
3193
4058
  const prior = readSeatState(o.home);
3194
- let state = { ...prior, window };
4059
+ let state = { ...prior, window, ...session ? { session } : {} };
3195
4060
  const src = meterSource(o.home);
3196
4061
  const posts = [];
3197
4062
  if (src) {
@@ -3214,11 +4079,18 @@ var rememberSeat = (o, window, now) => {
3214
4079
  };
3215
4080
 
3216
4081
  // src/commands/uninstall.ts
3217
- import { existsSync as existsSync10, rmSync as rmSync3 } from "node:fs";
3218
- var uninstall3 = (o) => {
4082
+ init_config();
4083
+ init_meter();
4084
+ import { spawnSync as spawnSync3 } from "node:child_process";
4085
+ import { existsSync as existsSync12, rmSync as rmSync5 } from "node:fs";
4086
+ init_settings();
4087
+ var defaultUnload = (plist) => {
4088
+ spawnSync3("launchctl", ["unload", plist], { stdio: "ignore" });
4089
+ };
4090
+ var uninstall2 = (o) => {
3219
4091
  const log = o.log ?? console.log;
3220
4092
  const removed = [];
3221
- if (existsSync10(settingsPath(o.home))) {
4093
+ if (existsSync12(settingsPath(o.home))) {
3222
4094
  let settings = readSettings(o.home);
3223
4095
  let changed = false;
3224
4096
  if (hasEitherKey(settings)) {
@@ -3250,16 +4122,22 @@ var uninstall3 = (o) => {
3250
4122
  writeSettings(o.home, settings);
3251
4123
  }
3252
4124
  for (const file of [meterCachePath(o.home), seatStatePath(o.home)]) {
3253
- if (existsSync10(file)) {
3254
- rmSync3(file, { force: true });
4125
+ if (existsSync12(file)) {
4126
+ rmSync5(file, { force: true });
3255
4127
  removed.push(file);
3256
4128
  }
3257
4129
  }
3258
4130
  const skill = skillDir(o.home);
3259
- if (existsSync10(skill)) {
3260
- rmSync3(skill, { recursive: true, force: true });
4131
+ if (existsSync12(skill)) {
4132
+ rmSync5(skill, { recursive: true, force: true });
3261
4133
  removed.push(skill);
3262
4134
  }
4135
+ const plist = musherPlistPath(o.home);
4136
+ if (existsSync12(plist)) {
4137
+ (o.unloadAgent ?? defaultUnload)(plist);
4138
+ rmSync5(plist, { force: true });
4139
+ removed.push(`launchd agent ${MUSHER_LABEL}`);
4140
+ }
3263
4141
  if (removed.length === 0) {
3264
4142
  log("Nothing to remove; SLEDS was not installed.");
3265
4143
  } else {
@@ -3277,10 +4155,58 @@ var hasEitherKey = (settings) => {
3277
4155
  return BASE_URL_KEY in env || AUTH_TOKEN_KEY in env;
3278
4156
  };
3279
4157
 
4158
+ // src/commands/verify.ts
4159
+ init_meter();
4160
+ var jobIdFromTarget = (target) => {
4161
+ const t = target.trim();
4162
+ const m = /SLEDS-Attest:.*\bjob=([^\s]+)/.exec(t);
4163
+ if (m?.[1])
4164
+ return m[1];
4165
+ return /^[A-Za-z0-9_-]{3,64}$/.test(t) ? t : null;
4166
+ };
4167
+ var verify = async (o) => {
4168
+ const log = o.log ?? console.log;
4169
+ const error = o.error ?? console.error;
4170
+ const jobId = o.target ? jobIdFromTarget(o.target) : null;
4171
+ if (!jobId) {
4172
+ error("usage: sleds verify <jobId> (or paste the SLEDS-Attest line)");
4173
+ return 2;
4174
+ }
4175
+ const client = o.client ?? (() => {
4176
+ const src = meterSource(o.home);
4177
+ return src ? musherClient({ ...src, fetchFn: o.fetchFn }) : null;
4178
+ })();
4179
+ if (!client) {
4180
+ error("No seat on this machine. Run `sleds init` first.");
4181
+ return 1;
4182
+ }
4183
+ const a = await client.attestation(jobId);
4184
+ if (!a) {
4185
+ error(`No attestation for ${jobId} (not delivered, not signed, not your org, or the proxy is down).`);
4186
+ return 1;
4187
+ }
4188
+ if (!a.publicKey) {
4189
+ error(`Attestation found but its key ${a.attestation.keyId} is not on file — cannot verify.`);
4190
+ return 1;
4191
+ }
4192
+ const ok = verifyAttestation(a.attestation.payload, a.attestation.sig, a.publicKey);
4193
+ const f = parsePayload(a.attestation.payload);
4194
+ log(`${ok ? "VERIFIED" : "INVALID "} job ${jobId}`);
4195
+ log(` model ${f.model ?? a.model ?? "unknown"}`);
4196
+ log(` engine ${f.engine ?? a.engine}${f.seat ? ` · seat ${f.seat}` : ""}`);
4197
+ log(` finished ${f.finished ?? "?"} · signed ${formatLocal(a.attestation.signedAt)} · key ${a.attestation.keyId}`);
4198
+ if (a.outputs.length)
4199
+ log(` outputs ${a.outputs.join(" ")}`);
4200
+ log(` ${a.attestation.trailer}`);
4201
+ if (!ok)
4202
+ log(" The signature does not match the payload under the org's public key.");
4203
+ return ok ? 0 : 1;
4204
+ };
4205
+
3280
4206
  // src/schedule.ts
3281
- import { spawnSync } from "node:child_process";
4207
+ import { spawnSync as spawnSync4 } from "node:child_process";
3282
4208
  var defaultExec = (cmd, args) => {
3283
- const r = spawnSync(cmd, [...args], { stdio: ["ignore", "ignore", "pipe"], encoding: "utf8" });
4209
+ const r = spawnSync4(cmd, [...args], { stdio: ["ignore", "ignore", "pipe"], encoding: "utf8" });
3284
4210
  if (r.error)
3285
4211
  return { ok: false, stderr: r.error.message };
3286
4212
  return { ok: r.status === 0, stderr: r.stderr ?? "" };
@@ -3294,21 +4220,33 @@ commands:
3294
4220
  --token <sled_\u2026> seat token (else SLEDS_TOKEN, ~/.sleds-token, or prompt)
3295
4221
  --url <proxy-url> proxy base URL (else SLEDS_PROXY_URL, default ${DEFAULT_PROXY_URL})
3296
4222
  --no-probe skip the /healthz check of the proxy URL
4223
+ --seat-first keep Claude Code on your seat; the proxy only at a wall (default for seat plans)
4224
+ --proxy-always every request through the proxy on the org key (default for API-plan orgs)
3297
4225
  --non-interactive never prompt; exit 2 if no token is available
3298
- --signup no org? create an individual seat: your email + your own
3299
- Anthropic API key (validated, stored encrypted, the only key it spends)
4226
+ --signup no org? create one: (1) just you \u2014 your email + your own Anthropic
4227
+ API key (validated, stored encrypted, the only key it spends), or
4228
+ (2) your team \u2014 work email + team name, platform key optional
4229
+ --team "<name>" with --signup: create the team org (you become its owner)
4230
+ --email <you@work.com> with --signup: skip the email prompt
3300
4231
  on Hit a limit on your seat? Switch Claude Code to the org key through the proxy.
3301
4232
  --until-reset <when> revert at this time: +5h, +90m, or an ISO timestamp
3302
4233
  --reason "<text>" note shown by \`sleds status\`
3303
4234
  --no-schedule record the deadline but do not install a launchd/systemd revert
4235
+ defer Hit a limit? Resume this session on this Mac at the reset \u2014 runs itself on your
4236
+ seat, no key needed (the musher). Uses the last session the status line saw.
4237
+ --at +2h | <ISO> start then instead of the binding reset
4238
+ --session <id> --cwd <dir> --model <id> override what was remembered
4239
+ musher The agent that runs deferred jobs here: --install / --uninstall / --status,
4240
+ --claude <path>, --mode <permission-mode> (default acceptEdits), --timeout <min>.
4241
+ run <jobId> Run one deferred job on this Mac now (the manual musher).
4242
+ verify <jobId | SLEDS-Attest line> Check a finished job's attestation: which model built it,
4243
+ signed by the org's key, verified locally.
3304
4244
  off Switch Claude Code back to your seat. Restores whatever \`on\` replaced.
3305
4245
  uninstall Remove the proxy settings, skill and status line. Keeps ~/.sleds-token.
3306
4246
  status Show the switch state, deadline, proxy health and wall mode.
3307
4247
  doctor Check the whole install: which seat this shell is, Claude settings, proxy, hooks,
3308
- Node version, stale links, the SwiftBar plugin, the seat-sync timer.
4248
+ Node version, stale links, the seat's last quota report.
3309
4249
  meter Show the pipeline: built today, queued with its band, delivered overnight.
3310
- bar Print the menu-bar meter in SwiftBar format; --install links it into SwiftBar
3311
- (--home/--claude-config pick the seat it tracks; --name <x> adds a second item).
3312
4250
  mcp Run the MCP server on stdio: tools usage, estimate, overnight, jobs.
3313
4251
  Register with \`claude mcp add sleds -- sleds mcp\` (Cowork sees the same server).
3314
4252
  seat-sync Read the seat's subscription usage (weekly/5h limits, per-model, credits) from a
@@ -3359,17 +4297,24 @@ var stringFlag = (flags, name) => {
3359
4297
  const v = flags[name];
3360
4298
  return typeof v === "string" ? v : undefined;
3361
4299
  };
4300
+ var hookStdin = async () => {
4301
+ if (process.stdin.isTTY)
4302
+ return;
4303
+ const { readStdin: readStdin3 } = await Promise.resolve().then(() => (init_seat(), exports_seat));
4304
+ const text = await readStdin3(300);
4305
+ return text.trim() ? text : undefined;
4306
+ };
3362
4307
  var sledsArgv = () => {
3363
4308
  const script = process.argv[1];
3364
4309
  return script ? [process.execPath, script] : [process.execPath];
3365
4310
  };
3366
- var shellQuote2 = (s) => /^[\w./-]+$/.test(s) ? s : `'${s.replace(/'/g, "'\\''")}'`;
3367
- var statusLineCommand = (argv) => [...argv, "statusline"].map(shellQuote2).join(" ");
3368
- var seatEventCommand = (argv) => [...argv, "seat-event"].map(shellQuote2).join(" ");
3369
- var specEventCommand = (argv) => [...argv, "spec-event"].map(shellQuote2).join(" ");
4311
+ var shellQuote = (s) => /^[\w./-]+$/.test(s) ? s : `'${s.replace(/'/g, "'\\''")}'`;
4312
+ var statusLineCommand = (argv) => [...argv, "statusline"].map(shellQuote).join(" ");
4313
+ var seatEventCommand = (argv) => [...argv, "seat-event"].map(shellQuote).join(" ");
4314
+ var specEventCommand = (argv) => [...argv, "spec-event"].map(shellQuote).join(" ");
3370
4315
  var main = async (argv) => {
3371
4316
  const { cmd, flags } = parseArgs(argv);
3372
- const home = homedir3();
4317
+ const home = homedir();
3373
4318
  const scheduler = {
3374
4319
  platform: platform2(),
3375
4320
  home,
@@ -3384,7 +4329,24 @@ var main = async (argv) => {
3384
4329
  url: stringFlag(flags, "url"),
3385
4330
  nonInteractive: flags["non-interactive"] === true,
3386
4331
  signup: flags.signup === true,
4332
+ team: typeof flags.team === "string" ? flags.team : undefined,
4333
+ email: typeof flags.email === "string" ? flags.email : undefined,
3387
4334
  noProbe: flags["no-probe"] === true,
4335
+ proxyAlways: flags["proxy-always"] === true,
4336
+ seatFirst: flags["seat-first"] === true,
4337
+ installMusher: () => {
4338
+ if (platform2() !== "darwin")
4339
+ return null;
4340
+ const lines = [];
4341
+ const code = musherInstall({
4342
+ home,
4343
+ argv: [],
4344
+ sledsArgv: sledsArgv(),
4345
+ log: (l) => lines.push(l),
4346
+ error: (l) => lines.push(l)
4347
+ });
4348
+ return code === 0 ? lines[0] ?? "installed the musher agent" : `musher not installed: ${lines.join(" ")}`;
4349
+ },
3388
4350
  prompt: promptStdin,
3389
4351
  statusLineCommand: statusLineCommand(sledsArgv()),
3390
4352
  seatEventCommand: seatEventCommand(sledsArgv()),
@@ -3411,16 +4373,22 @@ var main = async (argv) => {
3411
4373
  });
3412
4374
  case "off":
3413
4375
  return off({ home, scheduler });
4376
+ case "defer":
4377
+ return defer({ home, argv: process.argv.slice(3), stdin: await hookStdin() });
4378
+ case "musher":
4379
+ return musher({ home, argv: process.argv.slice(3), sledsArgv: sledsArgv() });
4380
+ case "run":
4381
+ return run({ home, jobId: process.argv[3] });
4382
+ case "verify":
4383
+ return verify({ home, target: process.argv.slice(3).join(" ") || undefined });
3414
4384
  case "uninstall":
3415
- return uninstall3({ home });
4385
+ return uninstall2({ home });
3416
4386
  case "doctor":
3417
4387
  return doctor({ home });
3418
4388
  case "status":
3419
4389
  return status({ home });
3420
4390
  case "meter":
3421
4391
  return meter({ home });
3422
- case "bar":
3423
- return bar({ home, argv: process.argv.slice(3) });
3424
4392
  case "mcp":
3425
4393
  return mcp({ home });
3426
4394
  case "seat-sync":
@@ -3435,7 +4403,7 @@ var main = async (argv) => {
3435
4403
  case "version":
3436
4404
  case "--version":
3437
4405
  case "-v":
3438
- console.log(`sleds ${"0.1.7"}`);
4406
+ console.log("sleds 0.1.14");
3439
4407
  return 0;
3440
4408
  default:
3441
4409
  console.error(`unknown command: ${cmd}