modelstat 0.0.6 → 0.0.7

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.
package/dist/cli.mjs CHANGED
@@ -4424,6 +4424,17 @@ var init_redact = __esm({
4424
4424
  }
4425
4425
  });
4426
4426
 
4427
+ // ../../packages/core/src/billing.ts
4428
+ var MILLION, FREE_INCLUDED_TOKENS, TEAM_INCLUDED_PER_SEAT;
4429
+ var init_billing = __esm({
4430
+ "../../packages/core/src/billing.ts"() {
4431
+ "use strict";
4432
+ MILLION = 1000000n;
4433
+ FREE_INCLUDED_TOKENS = 100n * MILLION;
4434
+ TEAM_INCLUDED_PER_SEAT = 250n * MILLION;
4435
+ }
4436
+ });
4437
+
4427
4438
  // ../../packages/core/src/index.ts
4428
4439
  var init_src = __esm({
4429
4440
  "../../packages/core/src/index.ts"() {
@@ -4432,6 +4443,7 @@ var init_src = __esm({
4432
4443
  init_schemas();
4433
4444
  init_ids();
4434
4445
  init_redact();
4446
+ init_billing();
4435
4447
  }
4436
4448
  });
4437
4449
 
@@ -5512,7 +5524,7 @@ __export(daemon_exports, {
5512
5524
  setProgress: () => setProgress,
5513
5525
  setQueue: () => setQueue
5514
5526
  });
5515
- import { existsSync as existsSync4, statSync as statSync2 } from "fs";
5527
+ import { existsSync as existsSync5, statSync as statSync2 } from "fs";
5516
5528
  import { request as request2 } from "undici";
5517
5529
  function setPhase(phase, message) {
5518
5530
  status.phase = phase;
@@ -5616,21 +5628,21 @@ async function runDaemon() {
5616
5628
  await runDiscovery();
5617
5629
  await runScanCycle("startup");
5618
5630
  const chokidar2 = (await import("chokidar")).default;
5619
- const { homedir: homedir4, platform: platform4 } = await import("os");
5620
- const { join: join4 } = await import("path");
5621
- const home = homedir4();
5631
+ const { homedir: homedir5, platform: platform5 } = await import("os");
5632
+ const { join: join5 } = await import("path");
5633
+ const home2 = homedir5();
5622
5634
  const dirs = [
5623
- join4(home, ".claude/projects"),
5624
- join4(home, ".codex/sessions"),
5625
- join4(home, ".cursor/ai-tracking"),
5626
- join4(home, ".gemini"),
5627
- ...platform4() === "darwin" ? [
5628
- join4(home, "Library/Application Support/Cursor/User/workspaceStorage"),
5629
- join4(home, "Library/Application Support/Claude")
5635
+ join5(home2, ".claude/projects"),
5636
+ join5(home2, ".codex/sessions"),
5637
+ join5(home2, ".cursor/ai-tracking"),
5638
+ join5(home2, ".gemini"),
5639
+ ...platform5() === "darwin" ? [
5640
+ join5(home2, "Library/Application Support/Cursor/User/workspaceStorage"),
5641
+ join5(home2, "Library/Application Support/Claude")
5630
5642
  ] : [
5631
- join4(home, ".config/Cursor/User/workspaceStorage")
5643
+ join5(home2, ".config/Cursor/User/workspaceStorage")
5632
5644
  ]
5633
- ].filter((p) => existsSync4(p) && statSync2(p).isDirectory());
5645
+ ].filter((p) => existsSync5(p) && statSync2(p).isDirectory());
5634
5646
  setPhase("watching", `Watching ${dirs.length} directories`);
5635
5647
  const watcher = chokidar2.watch(dirs, {
5636
5648
  persistent: true,
@@ -5695,37 +5707,37 @@ __export(watch_exports, {
5695
5707
  watchForever: () => watchForever
5696
5708
  });
5697
5709
  import chokidar from "chokidar";
5698
- import { existsSync as existsSync5 } from "fs";
5699
- import { homedir as homedir3, platform as platform2 } from "os";
5700
- import { join as join3 } from "path";
5710
+ import { existsSync as existsSync6 } from "fs";
5711
+ import { homedir as homedir4, platform as platform3 } from "os";
5712
+ import { join as join4 } from "path";
5701
5713
  function resolveWatchDirs() {
5702
- const home = homedir3();
5703
- const xdgConfig = process.env.XDG_CONFIG_HOME ?? join3(home, ".config");
5704
- const xdgData = process.env.XDG_DATA_HOME ?? join3(home, ".local/share");
5714
+ const home2 = homedir4();
5715
+ const xdgConfig = process.env.XDG_CONFIG_HOME ?? join4(home2, ".config");
5716
+ const xdgData = process.env.XDG_DATA_HOME ?? join4(home2, ".local/share");
5705
5717
  const candidates = [
5706
5718
  // universal (default HOME-rooted CLI data dirs)
5707
- join3(home, ".claude/projects"),
5708
- join3(home, ".codex/sessions"),
5709
- join3(home, ".cursor/ai-tracking"),
5710
- join3(home, ".gemini"),
5711
- join3(home, ".aider"),
5719
+ join4(home2, ".claude/projects"),
5720
+ join4(home2, ".codex/sessions"),
5721
+ join4(home2, ".cursor/ai-tracking"),
5722
+ join4(home2, ".gemini"),
5723
+ join4(home2, ".aider"),
5712
5724
  // XDG / Linux
5713
- join3(xdgConfig, "claude/projects"),
5714
- join3(xdgConfig, "codex/sessions"),
5715
- join3(xdgConfig, "Cursor/User/workspaceStorage"),
5716
- join3(xdgConfig, "Code/User/workspaceStorage"),
5717
- join3(xdgConfig, "Code - Insiders/User/workspaceStorage"),
5718
- join3(xdgData, "claude/projects"),
5725
+ join4(xdgConfig, "claude/projects"),
5726
+ join4(xdgConfig, "codex/sessions"),
5727
+ join4(xdgConfig, "Cursor/User/workspaceStorage"),
5728
+ join4(xdgConfig, "Code/User/workspaceStorage"),
5729
+ join4(xdgConfig, "Code - Insiders/User/workspaceStorage"),
5730
+ join4(xdgData, "claude/projects"),
5719
5731
  // macOS
5720
- ...platform2() === "darwin" ? [
5721
- join3(home, "Library/Application Support/Cursor/User/workspaceStorage"),
5722
- join3(home, "Library/Application Support/Claude"),
5723
- join3(home, "Library/Application Support/Code/User/workspaceStorage"),
5724
- join3(home, "Library/Application Support/Windsurf/User/workspaceStorage"),
5725
- join3(home, "Library/Application Support/Zed")
5732
+ ...platform3() === "darwin" ? [
5733
+ join4(home2, "Library/Application Support/Cursor/User/workspaceStorage"),
5734
+ join4(home2, "Library/Application Support/Claude"),
5735
+ join4(home2, "Library/Application Support/Code/User/workspaceStorage"),
5736
+ join4(home2, "Library/Application Support/Windsurf/User/workspaceStorage"),
5737
+ join4(home2, "Library/Application Support/Zed")
5726
5738
  ] : []
5727
5739
  ];
5728
- return Array.from(new Set(candidates)).filter((p) => existsSync5(p));
5740
+ return Array.from(new Set(candidates)).filter((p) => existsSync6(p));
5729
5741
  }
5730
5742
  async function safeScan(reason) {
5731
5743
  if (scanning) {
@@ -5788,10 +5800,224 @@ init_api();
5788
5800
  init_config();
5789
5801
  init_scan();
5790
5802
  import { spawn } from "child_process";
5791
- import { platform as platform3, release, arch as cpuArch, hostname as hostname2 } from "os";
5803
+ import { platform as platform4, release, arch as cpuArch, hostname as hostname2 } from "os";
5792
5804
  import { setTimeout as delay } from "timers/promises";
5805
+
5806
+ // src/service.ts
5807
+ import { spawnSync } from "child_process";
5808
+ import {
5809
+ copyFileSync,
5810
+ existsSync as existsSync4,
5811
+ mkdirSync,
5812
+ unlinkSync,
5813
+ writeFileSync
5814
+ } from "fs";
5815
+ import { homedir as homedir3, platform as platform2, userInfo } from "os";
5816
+ import { dirname as dirname3, join as join3 } from "path";
5817
+ import { fileURLToPath as fileURLToPath2 } from "url";
5818
+ var SERVICE_LABEL = "ai.modelstat.agent";
5819
+ var SYSTEMD_UNIT = "modelstat";
5820
+ function home() {
5821
+ return homedir3();
5822
+ }
5823
+ function stateDir() {
5824
+ return join3(home(), ".modelstat");
5825
+ }
5826
+ function binDir() {
5827
+ return join3(stateDir(), "bin");
5828
+ }
5829
+ function logDir() {
5830
+ return join3(stateDir(), "logs");
5831
+ }
5832
+ function installedCliPath() {
5833
+ return join3(binDir(), "modelstat.mjs");
5834
+ }
5835
+ function runningCliPath() {
5836
+ return fileURLToPath2(import.meta.url).replace(/service\.(mjs|js|ts)$/, "cli.mjs");
5837
+ }
5838
+ function installBundle() {
5839
+ mkdirSync(binDir(), { recursive: true });
5840
+ mkdirSync(logDir(), { recursive: true });
5841
+ const src = runningCliPath();
5842
+ const dest = installedCliPath();
5843
+ if (!existsSync4(src)) {
5844
+ throw new Error(
5845
+ `Can't find the CLI bundle to install from (${src}). Are you running a local dev build?`
5846
+ );
5847
+ }
5848
+ copyFileSync(src, dest);
5849
+ return dest;
5850
+ }
5851
+ function nodeBinary() {
5852
+ return process.execPath;
5853
+ }
5854
+ function plistPath() {
5855
+ return join3(home(), "Library", "LaunchAgents", `${SERVICE_LABEL}.plist`);
5856
+ }
5857
+ function writePlist(cliPath) {
5858
+ const p = plistPath();
5859
+ mkdirSync(dirname3(p), { recursive: true });
5860
+ const plist = `<?xml version="1.0" encoding="UTF-8"?>
5861
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
5862
+ <plist version="1.0">
5863
+ <dict>
5864
+ <key>Label</key><string>${SERVICE_LABEL}</string>
5865
+ <key>ProgramArguments</key>
5866
+ <array>
5867
+ <string>${nodeBinary()}</string>
5868
+ <string>${cliPath}</string>
5869
+ <string>start</string>
5870
+ </array>
5871
+ <key>RunAtLoad</key><true/>
5872
+ <key>KeepAlive</key>
5873
+ <dict><key>SuccessfulExit</key><false/></dict>
5874
+ <key>ThrottleInterval</key><integer>30</integer>
5875
+ <key>StandardOutPath</key><string>${join3(logDir(), "out.log")}</string>
5876
+ <key>StandardErrorPath</key><string>${join3(logDir(), "err.log")}</string>
5877
+ <key>EnvironmentVariables</key>
5878
+ <dict>
5879
+ <key>PATH</key><string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin</string>
5880
+ </dict>
5881
+ <key>WorkingDirectory</key><string>${home()}</string>
5882
+ </dict>
5883
+ </plist>
5884
+ `;
5885
+ writeFileSync(p, plist, { mode: 420 });
5886
+ return p;
5887
+ }
5888
+ function launchctl(args) {
5889
+ const r = spawnSync("launchctl", args, { encoding: "utf8" });
5890
+ return { ok: r.status === 0, out: r.stdout ?? "", err: r.stderr ?? "" };
5891
+ }
5892
+ function macInstall() {
5893
+ const cliPath = installBundle();
5894
+ const plist = writePlist(cliPath);
5895
+ const uid = userInfo().uid;
5896
+ const target = `gui/${uid}/${SERVICE_LABEL}`;
5897
+ launchctl(["bootout", target]);
5898
+ const boot = launchctl(["bootstrap", `gui/${uid}`, plist]);
5899
+ if (!boot.ok && !/already loaded|service already bootstrapped/i.test(boot.err)) {
5900
+ const load = launchctl(["load", "-w", plist]);
5901
+ if (!load.ok) {
5902
+ throw new Error(
5903
+ `launchctl load failed:
5904
+ bootstrap: ${boot.err.trim()}
5905
+ load: ${load.err.trim()}`
5906
+ );
5907
+ }
5908
+ }
5909
+ launchctl(["kickstart", "-k", target]);
5910
+ }
5911
+ function macUninstall() {
5912
+ const uid = userInfo().uid;
5913
+ const target = `gui/${uid}/${SERVICE_LABEL}`;
5914
+ launchctl(["bootout", target]);
5915
+ const plist = plistPath();
5916
+ if (existsSync4(plist)) {
5917
+ try {
5918
+ unlinkSync(plist);
5919
+ } catch {
5920
+ }
5921
+ }
5922
+ }
5923
+ function macStatus() {
5924
+ const uid = userInfo().uid;
5925
+ const r = launchctl(["print", `gui/${uid}/${SERVICE_LABEL}`]);
5926
+ return { running: r.ok, hint: r.ok ? "launchd managed" : "not installed" };
5927
+ }
5928
+ function systemdUnitPath() {
5929
+ const xdg = process.env.XDG_CONFIG_HOME ?? join3(home(), ".config");
5930
+ return join3(xdg, "systemd", "user", `${SYSTEMD_UNIT}.service`);
5931
+ }
5932
+ function writeSystemdUnit(cliPath) {
5933
+ const unitPath = systemdUnitPath();
5934
+ mkdirSync(dirname3(unitPath), { recursive: true });
5935
+ const unit = `[Unit]
5936
+ Description=modelstat agent
5937
+ Documentation=https://modelstat.ai
5938
+ After=network-online.target
5939
+ Wants=network-online.target
5940
+
5941
+ [Service]
5942
+ Type=simple
5943
+ ExecStart=${nodeBinary()} ${cliPath} start
5944
+ Restart=always
5945
+ RestartSec=10
5946
+ # Don't restart-storm if the backend is persistently unreachable.
5947
+ StartLimitIntervalSec=300
5948
+ StartLimitBurst=10
5949
+ StandardOutput=append:${join3(logDir(), "out.log")}
5950
+ StandardError=append:${join3(logDir(), "err.log")}
5951
+
5952
+ [Install]
5953
+ WantedBy=default.target
5954
+ `;
5955
+ writeFileSync(unitPath, unit, { mode: 420 });
5956
+ return unitPath;
5957
+ }
5958
+ function systemctl(args) {
5959
+ const r = spawnSync("systemctl", ["--user", ...args], { encoding: "utf8" });
5960
+ return { ok: r.status === 0, out: r.stdout ?? "", err: r.stderr ?? "" };
5961
+ }
5962
+ function linuxInstall() {
5963
+ const cliPath = installBundle();
5964
+ writeSystemdUnit(cliPath);
5965
+ systemctl(["daemon-reload"]);
5966
+ const en = systemctl(["enable", "--now", `${SYSTEMD_UNIT}.service`]);
5967
+ if (!en.ok) {
5968
+ throw new Error(`systemctl enable failed: ${en.err.trim()}`);
5969
+ }
5970
+ systemctl(["restart", `${SYSTEMD_UNIT}.service`]);
5971
+ }
5972
+ function linuxUninstall() {
5973
+ systemctl(["disable", "--now", `${SYSTEMD_UNIT}.service`]);
5974
+ const unit = systemdUnitPath();
5975
+ if (existsSync4(unit)) {
5976
+ try {
5977
+ unlinkSync(unit);
5978
+ } catch {
5979
+ }
5980
+ }
5981
+ systemctl(["daemon-reload"]);
5982
+ }
5983
+ function linuxStatus() {
5984
+ const r = systemctl(["is-active", `${SYSTEMD_UNIT}.service`]);
5985
+ const active = r.out.trim() === "active";
5986
+ return { running: active, hint: active ? "systemd managed" : "not running" };
5987
+ }
5988
+ function installService() {
5989
+ const p = platform2();
5990
+ if (p === "darwin") {
5991
+ macInstall();
5992
+ return { path: plistPath(), logs: logDir() };
5993
+ }
5994
+ if (p === "linux") {
5995
+ linuxInstall();
5996
+ return { path: systemdUnitPath(), logs: logDir() };
5997
+ }
5998
+ throw new Error(
5999
+ `Service installation isn't supported on ${p}. Run 'modelstat start' manually to keep the agent running.`
6000
+ );
6001
+ }
6002
+ function uninstallService() {
6003
+ const p = platform2();
6004
+ if (p === "darwin") return macUninstall();
6005
+ if (p === "linux") return linuxUninstall();
6006
+ throw new Error(`Service uninstall isn't supported on ${p}.`);
6007
+ }
6008
+ function serviceStatus() {
6009
+ const p = platform2();
6010
+ if (p === "darwin") return macStatus();
6011
+ if (p === "linux") return linuxStatus();
6012
+ return { running: false, hint: `unsupported platform (${p})` };
6013
+ }
6014
+ function logsDir() {
6015
+ return logDir();
6016
+ }
6017
+
6018
+ // src/cli.ts
5793
6019
  function tryOpenBrowser(url) {
5794
- const p = platform3();
6020
+ const p = platform4();
5795
6021
  const cmd = p === "darwin" ? "open" : p === "win32" ? "cmd" : "xdg-open";
5796
6022
  const args = p === "win32" ? ["/c", "start", "", url] : [url];
5797
6023
  try {
@@ -5807,7 +6033,7 @@ function tryOpenBrowser(url) {
5807
6033
  }
5808
6034
  var AGENT_VERSION3 = "agent-dev-0.0.1";
5809
6035
  function osFamily() {
5810
- const p = platform3();
6036
+ const p = platform4();
5811
6037
  if (p === "darwin") return "macos";
5812
6038
  if (p === "linux") return "linux";
5813
6039
  return "other";
@@ -5897,13 +6123,33 @@ async function cmdConnect() {
5897
6123
  }
5898
6124
  state.setDeviceId(enroll.device_id);
5899
6125
  console.log(`\u2713 device registered (${enroll.device_id.slice(0, 8)}\u2026)`);
5900
- console.log();
5901
- console.log("Starting daemon \u2014 the dashboard takes it from here.");
5902
- console.log("Press Ctrl-C to stop.");
5903
- console.log();
5904
- const { runDaemon: runDaemon2 } = await Promise.resolve().then(() => (init_daemon(), daemon_exports));
5905
- await runDaemon2();
5906
- return;
6126
+ try {
6127
+ const svc = installService();
6128
+ console.log(`\u2713 service installed (${svc.path})`);
6129
+ console.log(` logs: ${svc.logs}`);
6130
+ console.log();
6131
+ const banner = "\u2501".repeat(60);
6132
+ console.log(banner);
6133
+ console.log(" You're connected. The agent is now running in the");
6134
+ console.log(" background and will start on login.");
6135
+ console.log();
6136
+ console.log(" Manage it from the dashboard:");
6137
+ console.log(" \x1B[1;36mhttps://modelstat.ai/dashboard\x1B[0m");
6138
+ console.log();
6139
+ console.log(" Stop it any time: \x1B[2mmodelstat stop\x1B[0m");
6140
+ console.log(" Uninstall: \x1B[2mmodelstat uninstall\x1B[0m");
6141
+ console.log(banner);
6142
+ return;
6143
+ } catch (err) {
6144
+ console.warn();
6145
+ console.warn(`\u26A0 couldn't install as a background service: ${err.message}`);
6146
+ console.warn(" Running in the foreground instead \u2014 press Ctrl-C to stop.");
6147
+ console.warn(" (Install globally with `npm i -g modelstat` then re-run `modelstat connect`.)");
6148
+ console.warn();
6149
+ const { runDaemon: runDaemon2 } = await Promise.resolve().then(() => (init_daemon(), daemon_exports));
6150
+ await runDaemon2();
6151
+ return;
6152
+ }
5907
6153
  }
5908
6154
  } catch (e) {
5909
6155
  if (dots % 15 === 0) console.warn(`
@@ -5947,6 +6193,29 @@ async function cmdStart() {
5947
6193
  const { runDaemon: runDaemon2 } = await Promise.resolve().then(() => (init_daemon(), daemon_exports));
5948
6194
  await runDaemon2();
5949
6195
  }
6196
+ async function cmdStop() {
6197
+ try {
6198
+ uninstallService();
6199
+ console.log("\u2713 service stopped and uninstalled");
6200
+ console.log(` Your device pairing is still in ${state.storePath}`);
6201
+ console.log(" Run `modelstat connect` again to re-enable.");
6202
+ } catch (err) {
6203
+ console.error(`\u2717 ${err.message}`);
6204
+ process.exit(1);
6205
+ }
6206
+ }
6207
+ async function cmdStatus() {
6208
+ const s = serviceStatus();
6209
+ const paired = !!state.bearer && !!state.deviceId;
6210
+ console.log(`paired: ${paired ? "yes" : "no"}`);
6211
+ if (paired) {
6212
+ console.log(` user: ${state.userEmail ?? "(unknown)"}`);
6213
+ console.log(` device: ${state.deviceId}`);
6214
+ }
6215
+ console.log(`service: ${s.running ? "running" : "stopped"} (${s.hint})`);
6216
+ console.log(`logs: ${logsDir()}`);
6217
+ console.log(`state: ${state.storePath}`);
6218
+ }
5950
6219
  async function main() {
5951
6220
  const cmd = process.argv[2];
5952
6221
  switch (cmd) {
@@ -5964,16 +6233,25 @@ async function main() {
5964
6233
  return cmdScan();
5965
6234
  case "watch":
5966
6235
  return cmdWatch();
6236
+ case "stop":
6237
+ case "uninstall":
6238
+ return cmdStop();
6239
+ case "status":
6240
+ return cmdStatus();
5967
6241
  default:
5968
- console.log("usage: modelstat [connect|start|discover|scan|watch|register]");
6242
+ console.log(
6243
+ "usage: modelstat [connect|status|stop|start|discover|scan|watch|register]"
6244
+ );
5969
6245
  console.log();
5970
- console.log(" (no args) \u2014 pair if needed, then run the daemon (default)");
5971
- console.log(" connect \u2014 pair + start daemon (recommended first run)");
5972
- console.log(" start \u2014 run the daemon (requires prior pairing)");
5973
- console.log(" discover \u2014 one-shot report of installs/identities");
5974
- console.log(" scan \u2014 one-shot parse + upload of local JSONL");
5975
- console.log(" watch \u2014 continuous (chokidar) with periodic backstop");
5976
- console.log(" register \u2014 DEV shortcut (email-only, no OAuth)");
6246
+ console.log(" (no args) \u2014 pair if needed, then run the daemon in the foreground");
6247
+ console.log(" connect \u2014 pair + install as a background service, then exit");
6248
+ console.log(" status \u2014 show pairing + service state");
6249
+ console.log(" stop \u2014 stop and uninstall the background service");
6250
+ console.log(" start \u2014 run the daemon (used by the installed service)");
6251
+ console.log(" discover \u2014 one-shot report of installs/identities");
6252
+ console.log(" scan \u2014 one-shot parse + upload of local JSONL");
6253
+ console.log(" watch \u2014 continuous (chokidar) with periodic backstop");
6254
+ console.log(" register \u2014 DEV shortcut (email-only, no OAuth)");
5977
6255
  process.exit(1);
5978
6256
  }
5979
6257
  }