modelstat 0.0.12 → 0.0.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.
package/README.md CHANGED
@@ -22,9 +22,9 @@ modelstat connect
22
22
  Or via npm / pnpm / bun:
23
23
 
24
24
  ```bash
25
- npm install -g modelstat && modelstat connect
26
- pnpm add -g modelstat && modelstat connect
27
- bun add -g modelstat && modelstat connect
25
+ npm install -g @modelstat/agent && modelstat connect
26
+ pnpm add -g @modelstat/agent && modelstat connect
27
+ bun add -g @modelstat/agent && modelstat connect
28
28
  ```
29
29
 
30
30
  `modelstat connect` installs a **launchd user agent** on macOS (at `~/Library/LaunchAgents/ai.modelstat.agent.plist`) or a **systemd user unit** on Linux (at `~/.config/systemd/user/modelstat.service`). The daemon starts automatically on login.
package/dist/cli.mjs CHANGED
@@ -4484,7 +4484,22 @@ var init_schemas = __esm({
4484
4484
  });
4485
4485
 
4486
4486
  // ../../packages/core/src/ids.ts
4487
- import { ulid } from "ulid";
4487
+ function ulid(seedTime) {
4488
+ const t = seedTime ?? Date.now();
4489
+ let timeStr = "";
4490
+ let ts = t;
4491
+ for (let i = 9; i >= 0; i--) {
4492
+ timeStr = ULID_ALPHABET[ts % 32] + timeStr;
4493
+ ts = Math.floor(ts / 32);
4494
+ }
4495
+ const bytes = new Uint8Array(16);
4496
+ globalThis.crypto.getRandomValues(bytes);
4497
+ let randStr = "";
4498
+ for (let i = 0; i < 16; i++) {
4499
+ randStr += ULID_ALPHABET[bytes[i] % 32];
4500
+ }
4501
+ return timeStr + randStr;
4502
+ }
4488
4503
  function sourceEventId(deviceId, sourceOrFilePath, byteOffsetMaybe) {
4489
4504
  let key;
4490
4505
  if (typeof sourceOrFilePath === "string") {
@@ -4513,10 +4528,11 @@ function segmentId(sessionId, startedAtMs, endedAtMs, sourceEventIds) {
4513
4528
  }
4514
4529
  return `seg_${h.toString(36)}`;
4515
4530
  }
4516
- var batchId;
4531
+ var ULID_ALPHABET, batchId;
4517
4532
  var init_ids = __esm({
4518
4533
  "../../packages/core/src/ids.ts"() {
4519
4534
  "use strict";
4535
+ ULID_ALPHABET = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
4520
4536
  batchId = () => ulid();
4521
4537
  }
4522
4538
  });
@@ -7748,7 +7764,7 @@ async function reportDiscovery(report) {
7748
7764
  }
7749
7765
  }
7750
7766
  async function fetchDeviceViewByClaim(claimCode) {
7751
- const res = await request(`${state.apiUrl}/v1/d/${encodeURIComponent(claimCode)}`, {
7767
+ const res = await request(`${state.apiUrl}/v1/device/${encodeURIComponent(claimCode)}`, {
7752
7768
  method: "GET"
7753
7769
  });
7754
7770
  if (res.statusCode === 404) return null;
@@ -7759,7 +7775,7 @@ async function fetchDeviceViewByClaim(claimCode) {
7759
7775
  }
7760
7776
  async function fetchDeviceViewJobsByClaim(claimCode) {
7761
7777
  const res = await request(
7762
- `${state.apiUrl}/v1/d/${encodeURIComponent(claimCode)}/jobs`,
7778
+ `${state.apiUrl}/v1/device/${encodeURIComponent(claimCode)}/jobs`,
7763
7779
  { method: "GET" }
7764
7780
  );
7765
7781
  if (res.statusCode === 404) return null;
@@ -7770,7 +7786,7 @@ async function fetchDeviceViewJobsByClaim(claimCode) {
7770
7786
  }
7771
7787
  async function fetchDeviceViewLedgerByClaim(claimCode) {
7772
7788
  const res = await request(
7773
- `${state.apiUrl}/v1/d/${encodeURIComponent(claimCode)}/ledger`,
7789
+ `${state.apiUrl}/v1/device/${encodeURIComponent(claimCode)}/ledger`,
7774
7790
  { method: "GET" }
7775
7791
  );
7776
7792
  if (res.statusCode === 404) return null;
@@ -8908,6 +8924,7 @@ function generateUuidV7() {
8908
8924
  }
8909
8925
  async function cmdSelfRegister() {
8910
8926
  const deviceUuid = state.deviceUuid ?? generateUuidV7();
8927
+ const fresh = !state.deviceUuid;
8911
8928
  const fingerprint = {
8912
8929
  hostname: hostname2(),
8913
8930
  os_family: osFamily(),
@@ -8916,6 +8933,14 @@ async function cmdSelfRegister() {
8916
8933
  agent: "modelstat-agent-dev",
8917
8934
  agent_version: AGENT_VERSION3
8918
8935
  };
8936
+ if (fresh) {
8937
+ process.stdout.write(` \x1B[2mgenerated UUIDv7 ${deviceUuid.slice(0, 8)}\u2026\x1B[0m
8938
+ `);
8939
+ }
8940
+ process.stdout.write(
8941
+ ` \x1B[2m\u2192 POST ${state.apiUrl}/v1/devices/self-register\x1B[0m
8942
+ `
8943
+ );
8919
8944
  const res = await selfRegister({
8920
8945
  device_uuid: deviceUuid,
8921
8946
  fingerprint
@@ -8925,16 +8950,12 @@ async function cmdSelfRegister() {
8925
8950
  state.setBearer(res.device_secret);
8926
8951
  state.setClaimCode(res.claim_code);
8927
8952
  state.setClaimUrl(res.claim_url);
8928
- console.log(`\u2713 self-registered`);
8929
- console.log(` device_uuid: ${res.device_uuid}`);
8930
- console.log(` device_id: ${res.device_id}`);
8931
- console.log(` secret_prefix: ${res.secret_prefix}\u2026`);
8932
- console.log();
8933
- console.log(` Claim this device to attach it to your account:`);
8934
- console.log(` ${res.claim_url}`);
8935
- console.log(` code: ${res.claim_code}`);
8936
- console.log();
8937
- console.log(` state: ${state.storePath}`);
8953
+ process.stdout.write(` \x1B[32m\u2713\x1B[0m registered device_id=${res.device_id}
8954
+ `);
8955
+ process.stdout.write(` \x1B[32m\u2713\x1B[0m secret ${res.secret_prefix}\u2026 (hashed on server, never re-sent)
8956
+ `);
8957
+ process.stdout.write(` \x1B[32m\u2713\x1B[0m claim code ${res.claim_code}
8958
+ `);
8938
8959
  }
8939
8960
  async function cmdAwaitClaim() {
8940
8961
  const secret = state.bearer;
@@ -8971,12 +8992,43 @@ function emitEvent(opts, event, fields = {}) {
8971
8992
  );
8972
8993
  }
8973
8994
  async function cmdConnect(opts) {
8995
+ const step = (msg) => {
8996
+ if (opts.json) return;
8997
+ process.stdout.write(`\x1B[1;36m\u25B8\x1B[0m ${msg}
8998
+ `);
8999
+ };
9000
+ const ok = (msg) => {
9001
+ if (opts.json) return;
9002
+ process.stdout.write(` \x1B[32m\u2713\x1B[0m ${msg}
9003
+ `);
9004
+ };
9005
+ const warn = (msg) => {
9006
+ if (opts.json) return;
9007
+ process.stdout.write(` \x1B[33m\u26A0\x1B[0m ${msg}
9008
+ `);
9009
+ };
9010
+ const hasLegacyBearer = !!state.bearer && !state.bearer.startsWith("ds_live_");
9011
+ const hasLegacyClaim = !!state.claimUrl && (state.claimUrl.includes("/c/") || /\/d\/[a-z]/.test(state.claimUrl) || !state.claimUrl.includes("/device/"));
9012
+ const hasLegacyCode = !!state.claimCode && !/^[0-9a-hjkmnp-tv-z]{32}$/.test(state.claimCode);
9013
+ if (hasLegacyBearer || hasLegacyClaim || hasLegacyCode) {
9014
+ step("Legacy state detected from an older version \u2014 wiping");
9015
+ state.setBearer(null);
9016
+ state.setDeviceId(null);
9017
+ state.setDeviceUuid(null);
9018
+ state.setClaimCode(null);
9019
+ state.setClaimUrl(null);
9020
+ ok("clean slate");
9021
+ }
8974
9022
  if (!state.deviceUuid || !state.bearer || !state.deviceId) {
9023
+ step("Registering this device with modelstat.ai");
8975
9024
  await cmdSelfRegister();
9025
+ } else {
9026
+ step("Re-using existing device identity");
9027
+ ok(`device ${state.deviceId}`);
8976
9028
  }
8977
9029
  const claimCode = state.claimCode ?? "(unknown)";
8978
- const claimUrl = state.claimUrl ?? `https://modelstat.ai/d/${claimCode}`;
8979
- const agentUrl = `https://modelstat.ai/da/${claimCode}`;
9030
+ const claimUrl = state.claimUrl ?? `https://modelstat.ai/device/${claimCode}`;
9031
+ const agentUrl = `https://modelstat.ai/device-agent/${claimCode}`;
8980
9032
  emitEvent(opts, "registered", {
8981
9033
  device_uuid: state.deviceUuid,
8982
9034
  device_id: state.deviceId,
@@ -8985,36 +9037,45 @@ async function cmdConnect(opts) {
8985
9037
  agent_url: agentUrl
8986
9038
  });
8987
9039
  if (platform4() === "darwin") {
9040
+ step("Installing menu-bar tray (macOS)");
8988
9041
  try {
8989
9042
  const src = bundledTrayAppPath();
8990
9043
  if (src) {
8991
9044
  const out = installTrayApp(src);
8992
- if (out) emitEvent(opts, "tray_installed", { path: out.installedAt });
9045
+ if (out) {
9046
+ emitEvent(opts, "tray_installed", { path: out.installedAt });
9047
+ ok(`tray at ${out.installedAt}`);
9048
+ }
8993
9049
  } else {
8994
9050
  emitEvent(opts, "tray_not_bundled", {});
9051
+ warn("no bundled tray \u2014 skipping (install Xcode CLI tools and re-run to get the icon)");
8995
9052
  }
8996
9053
  } catch (e) {
8997
9054
  emitEvent(opts, "tray_install_failed", { error: e.message });
9055
+ warn(`tray install skipped: ${e.message}`);
8998
9056
  }
8999
9057
  }
9058
+ step("Installing background service so the agent survives reboots");
9000
9059
  let serviceOk = false;
9001
9060
  try {
9002
9061
  const svc = installService();
9003
9062
  serviceOk = true;
9004
9063
  emitEvent(opts, "service_installed", { path: svc.path, logs: svc.logs });
9064
+ ok(`${platform4() === "darwin" ? "launchd" : "systemd --user"}: ${svc.path}`);
9005
9065
  } catch (e) {
9006
9066
  emitEvent(opts, "service_install_failed", { error: e.message });
9067
+ warn(`couldn't install service: ${e.message}`);
9068
+ warn("will run in the foreground instead \u2014 don't close this terminal");
9007
9069
  }
9008
9070
  if (!opts.json) {
9009
9071
  const tray = trayStatus();
9010
- const svcOk = serviceOk;
9011
9072
  const line = "\u2501".repeat(60);
9012
9073
  console.log();
9013
9074
  console.log(line);
9014
9075
  console.log(` \u2713 Device registered \u2014 streaming your AI usage to modelstat.`);
9015
9076
  console.log();
9016
9077
  console.log(
9017
- ` service : \x1B[${svcOk ? "32" : "33"}m${svcOk ? "installed" : "foreground"}\x1B[0m`
9078
+ ` service : \x1B[${serviceOk ? "32" : "33"}m${serviceOk ? "installed" : "foreground"}\x1B[0m`
9018
9079
  );
9019
9080
  if (platform4() === "darwin") {
9020
9081
  console.log(