@sleds/cli 0.1.24 → 0.1.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/sleds.mjs +154 -26
  2. package/package.json +1 -1
package/dist/sleds.mjs CHANGED
@@ -833,7 +833,7 @@ var GUIDES = [
833
833
  {
834
834
  do: "Add the custom connector",
835
835
  where: "claude.ai › Settings › Connectors › `Add custom connector`",
836
- note: "URL `https://agent.sleds.ai/mcp`. It signs you in with OAuth — the same email your workspace invited."
836
+ note: "URL `https://mcp.sleds.ai/mcp`. It signs you in with OAuth — the same email your workspace invited."
837
837
  },
838
838
  {
839
839
  do: "Say `/sled usage` in any chat",
@@ -1221,7 +1221,7 @@ var VERBS = [
1221
1221
  id: "connector",
1222
1222
  group: "trust",
1223
1223
  want: "Use SLEDS from chat, Cowork or Claude Design",
1224
- mcp: "add https://agent.sleds.ai/mcp as a connector (OAuth) — then every verb in this column",
1224
+ mcp: "add https://mcp.sleds.ai/mcp as a connector (OAuth) — then every verb in this column",
1225
1225
  how: "The conversation is your cockpit: the same tools, no terminal. Your seat is the account you signed in with."
1226
1226
  },
1227
1227
  {
@@ -2076,8 +2076,8 @@ var SERVER_INFO = {
2076
2076
  description: "The cost and limits of AI agent work — estimate, hand off, and track what a task takes.",
2077
2077
  websiteUrl: "https://sleds.ai",
2078
2078
  icons: [
2079
- { src: "https://agent.sleds.ai/icon.png", mimeType: "image/png", sizes: ["192x192"] },
2080
- { src: "https://agent.sleds.ai/icon.svg", mimeType: "image/svg+xml", sizes: ["any"] }
2079
+ { src: "https://mcp.sleds.ai/icon.png", mimeType: "image/png", sizes: ["192x192"] },
2080
+ { src: "https://mcp.sleds.ai/icon.svg", mimeType: "image/svg+xml", sizes: ["any"] }
2081
2081
  ]
2082
2082
  };
2083
2083
  var SERVER_INSTRUCTIONS = [
@@ -3318,7 +3318,7 @@ async function actualTool(ctx, args) {
3318
3318
  ...num3(args.tokensIn) !== undefined ? { tokensIn: num3(args.tokensIn) } : {},
3319
3319
  ...num3(args.tokensOut) !== undefined ? { tokensOut: num3(args.tokensOut) } : {},
3320
3320
  ...str4(args.by) ? { by: str4(args.by) } : {},
3321
- ...sessionIdOf(args.sessionId) ? { sessionId: sessionIdOf(args.sessionId) } : {},
3321
+ ...sessionIdOf(args.sessionId) ?? ctx.sessionId?.() ? { sessionId: sessionIdOf(args.sessionId) ?? ctx.sessionId?.() } : {},
3322
3322
  ...str4(args.ref) ? { ref: str4(args.ref) } : {},
3323
3323
  ...phases && Object.keys(phases).length > 0 ? { phases } : {},
3324
3324
  ...num3(args.seatCreditsUsd) !== undefined ? { seatCreditsUsd: num3(args.seatCreditsUsd) } : {}
@@ -5214,7 +5214,12 @@ function contextFor(deps) {
5214
5214
  const src = meterSource(deps.home);
5215
5215
  const now = deps.now ?? Date.now;
5216
5216
  const client = src ? trackingClient(fetchClient({ ...src, fetchFn: deps.fetchFn, timeoutMs: deps.timeoutMs }), deps.home, now) : null;
5217
- return { client, now: deps.now, usage: () => usageTool2(deps) };
5217
+ return {
5218
+ client,
5219
+ now: deps.now,
5220
+ usage: () => usageTool2(deps),
5221
+ sessionId: () => readSession(deps.home)?.sessionId
5222
+ };
5218
5223
  }
5219
5224
  var callTool2 = (name, args, deps) => callTool(name, args, contextFor(deps));
5220
5225
  var handleLine2 = (line, deps) => handleLine(line, contextFor(deps));
@@ -7474,6 +7479,128 @@ var announce = (o, events) => {
7474
7479
  };
7475
7480
 
7476
7481
  // src/commands/stopEvent.ts
7482
+ init_meter();
7483
+ import { existsSync as existsSync14, readFileSync as readFileSync12 } from "node:fs";
7484
+
7485
+ // src/transcript.ts
7486
+ var isObject12 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
7487
+ var n = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
7488
+ function sumTranscript(text) {
7489
+ const seen = new Set;
7490
+ const turn = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
7491
+ let sub = 0;
7492
+ let messages = 0;
7493
+ const byModel = new Map;
7494
+ const agents = new Set;
7495
+ let anySidechain = false;
7496
+ for (const line of text.split(`
7497
+ `)) {
7498
+ const t = line.trim();
7499
+ if (!t)
7500
+ continue;
7501
+ let j;
7502
+ try {
7503
+ j = JSON.parse(t);
7504
+ } catch {
7505
+ continue;
7506
+ }
7507
+ if (!isObject12(j) || j.type !== "assistant" || !isObject12(j.message))
7508
+ continue;
7509
+ const m = j.message;
7510
+ const id = typeof m.id === "string" ? m.id : typeof j.uuid === "string" ? j.uuid : undefined;
7511
+ if (id) {
7512
+ if (seen.has(id))
7513
+ continue;
7514
+ seen.add(id);
7515
+ }
7516
+ const u = isObject12(m.usage) ? m.usage : undefined;
7517
+ if (!u)
7518
+ continue;
7519
+ const input = n(u.input_tokens);
7520
+ const output = n(u.output_tokens);
7521
+ const cacheRead = n(u.cache_read_input_tokens);
7522
+ const cacheWrite = n(u.cache_creation_input_tokens);
7523
+ messages++;
7524
+ const model = typeof m.model === "string" ? m.model : undefined;
7525
+ if (model)
7526
+ byModel.set(model, (byModel.get(model) ?? 0) + output);
7527
+ if (j.isSidechain === true) {
7528
+ anySidechain = true;
7529
+ sub += input + output + cacheRead + cacheWrite;
7530
+ if (typeof j.agentId === "string")
7531
+ agents.add(j.agentId);
7532
+ } else {
7533
+ turn.input += input;
7534
+ turn.output += output;
7535
+ turn.cacheRead += cacheRead;
7536
+ turn.cacheWrite += cacheWrite;
7537
+ }
7538
+ }
7539
+ let model;
7540
+ let best = -1;
7541
+ for (const [k, v] of byModel)
7542
+ if (v > best)
7543
+ [model, best] = [k, v];
7544
+ return {
7545
+ turnTokens: turn,
7546
+ subagentTokens: sub,
7547
+ messages,
7548
+ ...model ? { model } : {},
7549
+ subagentRuns: agents.size > 0 ? agents.size : anySidechain ? 1 : 0
7550
+ };
7551
+ }
7552
+ function sessionBody(sessionId, sum, a) {
7553
+ return {
7554
+ capturedAt: a.capturedAt,
7555
+ sessions: [
7556
+ {
7557
+ sessionId,
7558
+ ...a.title ? { title: a.title.slice(0, 200) } : {},
7559
+ updatedAt: a.capturedAt,
7560
+ subagentTokens: sum.subagentTokens,
7561
+ taskCount: sum.subagentRuns,
7562
+ turnTokens: sum.turnTokens,
7563
+ tasks: []
7564
+ }
7565
+ ]
7566
+ };
7567
+ }
7568
+
7569
+ // src/commands/stopEvent.ts
7570
+ var SESSION_POST_TIMEOUT_MS = 2500;
7571
+ async function postTranscript(o, payload, now) {
7572
+ const sessionId = payload.session_id?.trim();
7573
+ const path = payload.transcript_path?.trim();
7574
+ if (!sessionId || !path)
7575
+ return false;
7576
+ const src = meterSource(o.home);
7577
+ if (!src)
7578
+ return false;
7579
+ const read = o.readFile ?? ((p) => existsSync14(p) ? readFileSync12(p, "utf8") : null);
7580
+ let text;
7581
+ try {
7582
+ text = read(path);
7583
+ } catch {
7584
+ return false;
7585
+ }
7586
+ if (!text)
7587
+ return false;
7588
+ const sum = sumTranscript(text);
7589
+ if (sum.messages === 0)
7590
+ return false;
7591
+ const fetchFn = o.fetchFn ?? fetch;
7592
+ try {
7593
+ const res = await fetchFn(`${src.proxyUrl.replace(/\/+$/, "")}/proxy/sessions`, {
7594
+ method: "POST",
7595
+ headers: { authorization: `Bearer ${src.token}`, "content-type": "application/json" },
7596
+ body: JSON.stringify(sessionBody(sessionId, sum, { capturedAt: now })),
7597
+ signal: AbortSignal.timeout(SESSION_POST_TIMEOUT_MS)
7598
+ });
7599
+ return res.ok;
7600
+ } catch {
7601
+ return false;
7602
+ }
7603
+ }
7477
7604
  var parseStopPayload = (raw) => {
7478
7605
  try {
7479
7606
  const j = JSON.parse(raw);
@@ -7503,6 +7630,7 @@ var stopEvent = async (o) => {
7503
7630
  const now = (o.now ?? Date.now)();
7504
7631
  const raw = o.stdin ?? await readStdin(HOOK_STDIN_TIMEOUT_MS);
7505
7632
  const payload = parseStopPayload(raw);
7633
+ await postTranscript(o, payload, now);
7506
7634
  let rows;
7507
7635
  try {
7508
7636
  rows = readOwed(o.home, now);
@@ -7526,11 +7654,11 @@ var stopEvent = async (o) => {
7526
7654
 
7527
7655
  // src/commands/uninstall.ts
7528
7656
  import { spawnSync as spawnSync5 } from "node:child_process";
7529
- import { existsSync as existsSync15, rmSync as rmSync5 } from "node:fs";
7657
+ import { existsSync as existsSync16, rmSync as rmSync5 } from "node:fs";
7530
7658
 
7531
7659
  // src/codex.ts
7532
7660
  init_config();
7533
- import { existsSync as existsSync14, mkdirSync as mkdirSync12, readFileSync as readFileSync12, writeFileSync as writeFileSync12 } from "node:fs";
7661
+ import { existsSync as existsSync15, mkdirSync as mkdirSync12, readFileSync as readFileSync13, writeFileSync as writeFileSync12 } from "node:fs";
7534
7662
  import { dirname as dirname6, join as join12 } from "node:path";
7535
7663
  var PROVIDER_ID2 = "sleds";
7536
7664
  var codexDir2 = (home) => join12(home, ".codex");
@@ -7563,9 +7691,9 @@ function removeCodexProvider2(toml, o = {}) {
7563
7691
  }
7564
7692
  function uninstallCodex(home) {
7565
7693
  const path = codexConfigPath2(home);
7566
- if (!existsSync14(path))
7694
+ if (!existsSync15(path))
7567
7695
  return null;
7568
- const prior = readFileSync12(path, "utf8");
7696
+ const prior = readFileSync13(path, "utf8");
7569
7697
  const next = removeCodexProvider2(prior);
7570
7698
  if (next === prior)
7571
7699
  return null;
@@ -7586,7 +7714,7 @@ var uninstall2 = (o) => {
7586
7714
  (o.log ?? console.log)(` ${codexLine}`);
7587
7715
  const log = o.log ?? console.log;
7588
7716
  const removed = [];
7589
- if (existsSync15(settingsPath(o.home))) {
7717
+ if (existsSync16(settingsPath(o.home))) {
7590
7718
  let settings = readSettings(o.home);
7591
7719
  let changed = false;
7592
7720
  if (hasEitherKey(settings)) {
@@ -7633,18 +7761,18 @@ var uninstall2 = (o) => {
7633
7761
  writeSettings(o.home, settings);
7634
7762
  }
7635
7763
  for (const file of [meterCachePath(o.home), seatStatePath(o.home)]) {
7636
- if (existsSync15(file)) {
7764
+ if (existsSync16(file)) {
7637
7765
  rmSync5(file, { force: true });
7638
7766
  removed.push(file);
7639
7767
  }
7640
7768
  }
7641
7769
  const skill = skillDir(o.home);
7642
- if (existsSync15(skill)) {
7770
+ if (existsSync16(skill)) {
7643
7771
  rmSync5(skill, { recursive: true, force: true });
7644
7772
  removed.push(skill);
7645
7773
  }
7646
7774
  const plist = musherPlistPath(o.home);
7647
- if (existsSync15(plist)) {
7775
+ if (existsSync16(plist)) {
7648
7776
  (o.unloadAgent ?? defaultUnload)(plist);
7649
7777
  rmSync5(plist, { force: true });
7650
7778
  removed.push(`launchd agent ${musherLabel()}`);
@@ -7716,17 +7844,17 @@ var verify = async (o) => {
7716
7844
 
7717
7845
  // src/config.ts
7718
7846
  init_settings();
7719
- import { chmodSync as chmodSync2, existsSync as existsSync16, mkdirSync as mkdirSync13, readFileSync as readFileSync13, renameSync as renameSync6, writeFileSync as writeFileSync13 } from "node:fs";
7847
+ import { chmodSync as chmodSync2, existsSync as existsSync17, mkdirSync as mkdirSync13, readFileSync as readFileSync14, renameSync as renameSync6, writeFileSync as writeFileSync13 } from "node:fs";
7720
7848
  import { join as join13, resolve as resolve4 } from "node:path";
7721
7849
  var configDir2 = (home, env = process.env) => {
7722
7850
  const o = env.SLEDS_HOME?.trim();
7723
7851
  return o ? resolve4(home, o) : join13(home, ".config", "sleds");
7724
7852
  };
7725
7853
  var configPath2 = (home) => join13(configDir2(home), "config.json");
7726
- var isObject12 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
7854
+ var isObject13 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
7727
7855
  var optString2 = (v) => typeof v === "string" ? v : undefined;
7728
7856
  var parsePriorEnv2 = (v) => {
7729
- if (!isObject12(v))
7857
+ if (!isObject13(v))
7730
7858
  return;
7731
7859
  const out = {};
7732
7860
  const url = optString2(v[BASE_URL_KEY]);
@@ -7741,7 +7869,7 @@ var parsePriorEnv2 = (v) => {
7741
7869
  };
7742
7870
  var parseSchedule2 = (v) => v === "launchd" || v === "systemd" || v === "manual" ? v : undefined;
7743
7871
  var parseConfig2 = (raw) => {
7744
- if (!isObject12(raw))
7872
+ if (!isObject13(raw))
7745
7873
  return {};
7746
7874
  const cfg = {};
7747
7875
  const token = optString2(raw.token);
@@ -7785,7 +7913,7 @@ var parseConfig2 = (raw) => {
7785
7913
  return cfg;
7786
7914
  };
7787
7915
  var parseMusher2 = (raw) => {
7788
- if (!isObject12(raw))
7916
+ if (!isObject13(raw))
7789
7917
  return;
7790
7918
  const out = {};
7791
7919
  const pm = optString2(raw.permissionMode);
@@ -7801,7 +7929,7 @@ var parseMusher2 = (raw) => {
7801
7929
  return out;
7802
7930
  };
7803
7931
  var parseOrgInfo2 = (raw) => {
7804
- if (!isObject12(raw) || !isObject12(raw.capabilities))
7932
+ if (!isObject13(raw) || !isObject13(raw.capabilities))
7805
7933
  return;
7806
7934
  const name = optString2(raw.name);
7807
7935
  const slug = optString2(raw.slug);
@@ -7825,9 +7953,9 @@ var parseOrgInfo2 = (raw) => {
7825
7953
  };
7826
7954
  var readConfig2 = (home) => {
7827
7955
  const p = configPath2(home);
7828
- if (!existsSync16(p))
7956
+ if (!existsSync17(p))
7829
7957
  return {};
7830
- return parseConfig2(JSON.parse(readFileSync13(p, "utf8")));
7958
+ return parseConfig2(JSON.parse(readFileSync14(p, "utf8")));
7831
7959
  };
7832
7960
 
7833
7961
  // src/schedule.ts
@@ -7853,12 +7981,12 @@ var withSeatEnv2 = (command, home, env = process.env) => {
7853
7981
  return parts.join(" ");
7854
7982
  };
7855
7983
  var shellWord2 = (v) => /^[\w./~-]+$/.test(v) ? v : `'${v.replace(/'/g, "'\\''")}'`;
7856
- var isObject13 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
7984
+ var isObject14 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
7857
7985
  var isSledsHookFor2 = (sub) => (entry) => {
7858
- if (!isObject13(entry) || !Array.isArray(entry.hooks))
7986
+ if (!isObject14(entry) || !Array.isArray(entry.hooks))
7859
7987
  return false;
7860
7988
  const re = new RegExp(`\\b${sub}\\b`);
7861
- return entry.hooks.some((h) => isObject13(h) && h.type === "command" && typeof h.command === "string" && re.test(h.command));
7989
+ return entry.hooks.some((h) => isObject14(h) && h.type === "command" && typeof h.command === "string" && re.test(h.command));
7862
7990
  };
7863
7991
  var isSledsSessionHook2 = isSledsHookFor2("session-event");
7864
7992
  var isSledsStopHook2 = isSledsHookFor2("stop-event");
@@ -8118,7 +8246,7 @@ ${renderHelpText(argv[1])}`);
8118
8246
  case "version":
8119
8247
  case "--version":
8120
8248
  case "-v":
8121
- console.log("sleds 0.1.24");
8249
+ console.log("sleds 0.1.25");
8122
8250
  return 0;
8123
8251
  default:
8124
8252
  console.error(`unknown command: ${cmd}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sleds/cli",
3
- "version": "0.1.24",
3
+ "version": "0.1.25",
4
4
  "description": "SLEDS CLI — the cost and limits of AI agent work, decided at the wall. Point Claude Code at a SLEDS proxy; estimate before you run; hold, switch model, or run overnight when you hit a limit.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",