modelstat 0.0.21 → 0.0.23
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 +358 -149
- package/dist/cli.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -4341,7 +4341,14 @@ var init_schemas = __esm({
|
|
|
4341
4341
|
files_touched: external_exports.array(external_exports.string().max(512)).max(256).default([]),
|
|
4342
4342
|
// Reference to originating file for reparsing
|
|
4343
4343
|
source_file: external_exports.string().max(1024).nullable(),
|
|
4344
|
-
source_byte_offset: external_exports.number().int().nonnegative().nullable()
|
|
4344
|
+
source_byte_offset: external_exports.number().int().nonnegative().nullable(),
|
|
4345
|
+
// Billing mode. Tools with a flat-fee subscription tier (Claude
|
|
4346
|
+
// Code, Cursor Pro, GitHub Copilot, etc) emit events tagged
|
|
4347
|
+
// `billing: "subscription"` — the server short-circuits cost to $0
|
|
4348
|
+
// for those, since token-level pricing doesn't apply once the user
|
|
4349
|
+
// is paying the subscription. `api` (or absent) means pay-per-token
|
|
4350
|
+
// against whatever rates the org has configured.
|
|
4351
|
+
billing: external_exports.enum(["subscription", "api"]).optional()
|
|
4345
4352
|
});
|
|
4346
4353
|
RedactionReport = external_exports.object({
|
|
4347
4354
|
secrets_found: external_exports.number().int().nonnegative().default(0),
|
|
@@ -4723,7 +4730,12 @@ async function parseClaudeCodeJsonl(ctx) {
|
|
|
4723
4730
|
tool_calls: {},
|
|
4724
4731
|
files_touched: [],
|
|
4725
4732
|
source_file: ctx.sourceFile,
|
|
4726
|
-
source_byte_offset: offsetAtLineStart
|
|
4733
|
+
source_byte_offset: offsetAtLineStart,
|
|
4734
|
+
// Files in ~/.claude/projects/ come from the Claude Code app
|
|
4735
|
+
// used via subscription (not the raw API). Mark them so the
|
|
4736
|
+
// server short-circuits token-level cost to $0 — the user has
|
|
4737
|
+
// already paid the flat monthly fee.
|
|
4738
|
+
billing: "subscription"
|
|
4727
4739
|
});
|
|
4728
4740
|
} else if (obj.type === "user") {
|
|
4729
4741
|
const u = obj;
|
|
@@ -4748,7 +4760,8 @@ async function parseClaudeCodeJsonl(ctx) {
|
|
|
4748
4760
|
tool_calls: {},
|
|
4749
4761
|
files_touched: [],
|
|
4750
4762
|
source_file: ctx.sourceFile,
|
|
4751
|
-
source_byte_offset: offsetAtLineStart
|
|
4763
|
+
source_byte_offset: offsetAtLineStart,
|
|
4764
|
+
billing: "subscription"
|
|
4752
4765
|
});
|
|
4753
4766
|
} else {
|
|
4754
4767
|
skipped += 1;
|
|
@@ -7474,6 +7487,107 @@ var init_src2 = __esm({
|
|
|
7474
7487
|
}
|
|
7475
7488
|
});
|
|
7476
7489
|
|
|
7490
|
+
// src/identity.ts
|
|
7491
|
+
import {
|
|
7492
|
+
chmodSync,
|
|
7493
|
+
mkdirSync,
|
|
7494
|
+
readFileSync as readFileSync2,
|
|
7495
|
+
renameSync,
|
|
7496
|
+
writeFileSync,
|
|
7497
|
+
existsSync as existsSync3
|
|
7498
|
+
} from "fs";
|
|
7499
|
+
import { homedir as homedir2, hostname as osHostname } from "os";
|
|
7500
|
+
import { join as join2 } from "path";
|
|
7501
|
+
function ensureRoot() {
|
|
7502
|
+
mkdirSync(ROOT, { recursive: true, mode: 448 });
|
|
7503
|
+
}
|
|
7504
|
+
function writeAtomic(meta) {
|
|
7505
|
+
ensureRoot();
|
|
7506
|
+
const tmp = `${IDENTITY_FILE}.${process.pid}.tmp`;
|
|
7507
|
+
writeFileSync(tmp, JSON.stringify(meta, null, 2), { mode: 384 });
|
|
7508
|
+
renameSync(tmp, IDENTITY_FILE);
|
|
7509
|
+
try {
|
|
7510
|
+
chmodSync(IDENTITY_FILE, 384);
|
|
7511
|
+
} catch {
|
|
7512
|
+
}
|
|
7513
|
+
}
|
|
7514
|
+
function identityPath() {
|
|
7515
|
+
return IDENTITY_FILE;
|
|
7516
|
+
}
|
|
7517
|
+
function hasIdentityFile() {
|
|
7518
|
+
return existsSync3(IDENTITY_FILE);
|
|
7519
|
+
}
|
|
7520
|
+
function parseFile() {
|
|
7521
|
+
try {
|
|
7522
|
+
const raw = readFileSync2(IDENTITY_FILE, "utf8");
|
|
7523
|
+
const obj = JSON.parse(raw);
|
|
7524
|
+
if (!obj.deviceUuid || !obj.deviceId || !obj.bearerToken) {
|
|
7525
|
+
return null;
|
|
7526
|
+
}
|
|
7527
|
+
return {
|
|
7528
|
+
deviceUuid: obj.deviceUuid,
|
|
7529
|
+
deviceId: obj.deviceId,
|
|
7530
|
+
bearerToken: obj.bearerToken,
|
|
7531
|
+
claimCode: obj.claimCode ?? null,
|
|
7532
|
+
claimUrl: obj.claimUrl ?? null,
|
|
7533
|
+
hostname: obj.hostname ?? osHostname(),
|
|
7534
|
+
createdAt: obj.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
7535
|
+
userEmail: obj.userEmail ?? null,
|
|
7536
|
+
defaultOrgId: obj.defaultOrgId ?? null
|
|
7537
|
+
};
|
|
7538
|
+
} catch {
|
|
7539
|
+
return null;
|
|
7540
|
+
}
|
|
7541
|
+
}
|
|
7542
|
+
function loadIdentity(migrateFromConf2) {
|
|
7543
|
+
const fromFile = parseFile();
|
|
7544
|
+
if (fromFile) return fromFile;
|
|
7545
|
+
if (!migrateFromConf2) return null;
|
|
7546
|
+
const legacy = migrateFromConf2();
|
|
7547
|
+
if (!legacy) return null;
|
|
7548
|
+
if (!legacy.deviceUuid || !legacy.deviceId || !legacy.bearerToken) {
|
|
7549
|
+
return null;
|
|
7550
|
+
}
|
|
7551
|
+
const migrated = {
|
|
7552
|
+
deviceUuid: legacy.deviceUuid,
|
|
7553
|
+
deviceId: legacy.deviceId,
|
|
7554
|
+
bearerToken: legacy.bearerToken,
|
|
7555
|
+
claimCode: legacy.claimCode ?? null,
|
|
7556
|
+
claimUrl: legacy.claimUrl ?? null,
|
|
7557
|
+
hostname: osHostname(),
|
|
7558
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7559
|
+
userEmail: legacy.userEmail ?? null,
|
|
7560
|
+
defaultOrgId: legacy.defaultOrgId ?? null
|
|
7561
|
+
};
|
|
7562
|
+
writeAtomic(migrated);
|
|
7563
|
+
return migrated;
|
|
7564
|
+
}
|
|
7565
|
+
function saveIdentity(meta) {
|
|
7566
|
+
writeAtomic(meta);
|
|
7567
|
+
}
|
|
7568
|
+
function backupIdentity() {
|
|
7569
|
+
if (!existsSync3(IDENTITY_FILE)) return null;
|
|
7570
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
7571
|
+
const dest = `${IDENTITY_FILE}.bak-${stamp}`;
|
|
7572
|
+
renameSync(IDENTITY_FILE, dest);
|
|
7573
|
+
return dest;
|
|
7574
|
+
}
|
|
7575
|
+
function updateIdentity(patch) {
|
|
7576
|
+
const current = parseFile();
|
|
7577
|
+
if (!current) return null;
|
|
7578
|
+
const merged = { ...current, ...patch };
|
|
7579
|
+
writeAtomic(merged);
|
|
7580
|
+
return merged;
|
|
7581
|
+
}
|
|
7582
|
+
var ROOT, IDENTITY_FILE;
|
|
7583
|
+
var init_identity = __esm({
|
|
7584
|
+
"src/identity.ts"() {
|
|
7585
|
+
"use strict";
|
|
7586
|
+
ROOT = join2(homedir2(), ".modelstat");
|
|
7587
|
+
IDENTITY_FILE = join2(ROOT, "identity.json");
|
|
7588
|
+
}
|
|
7589
|
+
});
|
|
7590
|
+
|
|
7477
7591
|
// ../../node_modules/.pnpm/undici@7.25.0/node_modules/undici/lib/core/symbols.js
|
|
7478
7592
|
var require_symbols = __commonJS({
|
|
7479
7593
|
"../../node_modules/.pnpm/undici@7.25.0/node_modules/undici/lib/core/symbols.js"(exports, module) {
|
|
@@ -33048,15 +33162,15 @@ function envPaths(name, { suffix = "nodejs" } = {}) {
|
|
|
33048
33162
|
}
|
|
33049
33163
|
return linux(name);
|
|
33050
33164
|
}
|
|
33051
|
-
var
|
|
33165
|
+
var homedir3, tmpdir, env, macos, windows, linux;
|
|
33052
33166
|
var init_env_paths = __esm({
|
|
33053
33167
|
"../../node_modules/.pnpm/env-paths@3.0.0/node_modules/env-paths/index.js"() {
|
|
33054
33168
|
"use strict";
|
|
33055
|
-
|
|
33169
|
+
homedir3 = os.homedir();
|
|
33056
33170
|
tmpdir = os.tmpdir();
|
|
33057
33171
|
({ env } = process2);
|
|
33058
33172
|
macos = (name) => {
|
|
33059
|
-
const library = path.join(
|
|
33173
|
+
const library = path.join(homedir3, "Library");
|
|
33060
33174
|
return {
|
|
33061
33175
|
data: path.join(library, "Application Support", name),
|
|
33062
33176
|
config: path.join(library, "Preferences", name),
|
|
@@ -33066,8 +33180,8 @@ var init_env_paths = __esm({
|
|
|
33066
33180
|
};
|
|
33067
33181
|
};
|
|
33068
33182
|
windows = (name) => {
|
|
33069
|
-
const appData = env.APPDATA || path.join(
|
|
33070
|
-
const localAppData = env.LOCALAPPDATA || path.join(
|
|
33183
|
+
const appData = env.APPDATA || path.join(homedir3, "AppData", "Roaming");
|
|
33184
|
+
const localAppData = env.LOCALAPPDATA || path.join(homedir3, "AppData", "Local");
|
|
33071
33185
|
return {
|
|
33072
33186
|
// Data/config/cache/log are invented by me as Windows isn't opinionated about this
|
|
33073
33187
|
data: path.join(localAppData, name, "Data"),
|
|
@@ -33078,13 +33192,13 @@ var init_env_paths = __esm({
|
|
|
33078
33192
|
};
|
|
33079
33193
|
};
|
|
33080
33194
|
linux = (name) => {
|
|
33081
|
-
const username = path.basename(
|
|
33195
|
+
const username = path.basename(homedir3);
|
|
33082
33196
|
return {
|
|
33083
|
-
data: path.join(env.XDG_DATA_HOME || path.join(
|
|
33084
|
-
config: path.join(env.XDG_CONFIG_HOME || path.join(
|
|
33085
|
-
cache: path.join(env.XDG_CACHE_HOME || path.join(
|
|
33197
|
+
data: path.join(env.XDG_DATA_HOME || path.join(homedir3, ".local", "share"), name),
|
|
33198
|
+
config: path.join(env.XDG_CONFIG_HOME || path.join(homedir3, ".config"), name),
|
|
33199
|
+
cache: path.join(env.XDG_CACHE_HOME || path.join(homedir3, ".cache"), name),
|
|
33086
33200
|
// https://wiki.debian.org/XDGBaseDirectorySpecification#state
|
|
33087
|
-
log: path.join(env.XDG_STATE_HOME || path.join(
|
|
33201
|
+
log: path.join(env.XDG_STATE_HOME || path.join(homedir3, ".local", "state"), name),
|
|
33088
33202
|
temp: path.join(tmpdir, username, name)
|
|
33089
33203
|
};
|
|
33090
33204
|
};
|
|
@@ -33525,9 +33639,9 @@ import { once } from "events";
|
|
|
33525
33639
|
import { createWriteStream } from "fs";
|
|
33526
33640
|
import path3 from "path";
|
|
33527
33641
|
import { Readable } from "stream";
|
|
33528
|
-
function
|
|
33642
|
+
function writeFileSync2(filePath, data, options = DEFAULT_WRITE_OPTIONS) {
|
|
33529
33643
|
if (isString(options))
|
|
33530
|
-
return
|
|
33644
|
+
return writeFileSync2(filePath, data, { encoding: options });
|
|
33531
33645
|
const timeout = options.timeout ?? DEFAULT_TIMEOUT_SYNC;
|
|
33532
33646
|
const retryOptions = { timeout };
|
|
33533
33647
|
let tempDisposer = null;
|
|
@@ -43650,7 +43764,7 @@ var init_source = __esm({
|
|
|
43650
43764
|
fs2.writeFileSync(this.path, data, { mode: this.#options.configFileMode });
|
|
43651
43765
|
} else {
|
|
43652
43766
|
try {
|
|
43653
|
-
|
|
43767
|
+
writeFileSync2(this.path, data, { mode: this.#options.configFileMode });
|
|
43654
43768
|
} catch (error) {
|
|
43655
43769
|
if (error?.code === "EXDEV") {
|
|
43656
43770
|
fs2.writeFileSync(this.path, data, { mode: this.#options.configFileMode });
|
|
@@ -43752,20 +43866,52 @@ var init_source = __esm({
|
|
|
43752
43866
|
});
|
|
43753
43867
|
|
|
43754
43868
|
// src/config.ts
|
|
43755
|
-
import { existsSync as
|
|
43869
|
+
import { existsSync as existsSync4 } from "fs";
|
|
43756
43870
|
import { hostname } from "os";
|
|
43757
43871
|
import { dirname as dirname2, resolve as resolve3 } from "path";
|
|
43758
43872
|
import { fileURLToPath } from "url";
|
|
43759
|
-
|
|
43873
|
+
function migrateFromConf() {
|
|
43874
|
+
const bearer = store.get("bearerToken");
|
|
43875
|
+
const deviceUuid = store.get("deviceUuid");
|
|
43876
|
+
const deviceId = store.get("deviceId");
|
|
43877
|
+
if (!bearer || !deviceUuid || !deviceId) return null;
|
|
43878
|
+
return {
|
|
43879
|
+
bearerToken: bearer,
|
|
43880
|
+
deviceId,
|
|
43881
|
+
deviceUuid,
|
|
43882
|
+
claimCode: store.get("claimCode"),
|
|
43883
|
+
claimUrl: store.get("claimUrl"),
|
|
43884
|
+
userEmail: store.get("userEmail"),
|
|
43885
|
+
defaultOrgId: store.get("defaultOrgId")
|
|
43886
|
+
};
|
|
43887
|
+
}
|
|
43888
|
+
function clearConfIdentity() {
|
|
43889
|
+
store.set("bearerToken", null);
|
|
43890
|
+
store.set("deviceId", null);
|
|
43891
|
+
store.set("deviceUuid", null);
|
|
43892
|
+
store.set("claimCode", null);
|
|
43893
|
+
store.set("claimUrl", null);
|
|
43894
|
+
}
|
|
43895
|
+
function writeThrough(patch) {
|
|
43896
|
+
if (!cachedIdentity) {
|
|
43897
|
+
throw new Error(
|
|
43898
|
+
"config: no identity yet \u2014 call state.saveFreshIdentity() first"
|
|
43899
|
+
);
|
|
43900
|
+
}
|
|
43901
|
+
cachedIdentity = { ...cachedIdentity, ...patch };
|
|
43902
|
+
updateIdentity(patch);
|
|
43903
|
+
}
|
|
43904
|
+
var import_dotenv, here, DEFAULT_API_URL, LEGACY_LOCALHOST_API, store, cachedIdentity, state;
|
|
43760
43905
|
var init_config2 = __esm({
|
|
43761
43906
|
"src/config.ts"() {
|
|
43762
43907
|
"use strict";
|
|
43763
43908
|
import_dotenv = __toESM(require_main(), 1);
|
|
43764
43909
|
init_source();
|
|
43910
|
+
init_identity();
|
|
43765
43911
|
here = dirname2(fileURLToPath(import.meta.url));
|
|
43766
43912
|
for (let d = here, i = 0; i < 8; i++, d = resolve3(d, "..")) {
|
|
43767
43913
|
const candidate = resolve3(d, ".env");
|
|
43768
|
-
if (
|
|
43914
|
+
if (existsSync4(candidate)) {
|
|
43769
43915
|
(0, import_dotenv.config)({ path: candidate });
|
|
43770
43916
|
break;
|
|
43771
43917
|
}
|
|
@@ -43791,6 +43937,14 @@ var init_config2 = __esm({
|
|
|
43791
43937
|
cursor: {}
|
|
43792
43938
|
}
|
|
43793
43939
|
});
|
|
43940
|
+
cachedIdentity = (() => {
|
|
43941
|
+
const had = store.get("bearerToken") !== null;
|
|
43942
|
+
const id = loadIdentity(migrateFromConf);
|
|
43943
|
+
if (id && had && !store.path.includes("fallback")) {
|
|
43944
|
+
clearConfIdentity();
|
|
43945
|
+
}
|
|
43946
|
+
return id;
|
|
43947
|
+
})();
|
|
43794
43948
|
state = {
|
|
43795
43949
|
/** Resolution order: env var → stored value (if user ran `setApiUrl`
|
|
43796
43950
|
* or paired pre-0.0.8) → production default. The legacy localhost
|
|
@@ -43804,42 +43958,66 @@ var init_config2 = __esm({
|
|
|
43804
43958
|
setApiUrl(v) {
|
|
43805
43959
|
store.set("apiUrl", v);
|
|
43806
43960
|
},
|
|
43961
|
+
// ── Identity: backed by ~/.modelstat/identity.json ─────────────
|
|
43962
|
+
/** Seed a fresh identity after a successful self-register. Writes
|
|
43963
|
+
* the file atomically; use `state.backupAndReset()` first if
|
|
43964
|
+
* overwriting an existing identity. */
|
|
43965
|
+
saveFreshIdentity(meta) {
|
|
43966
|
+
const id = {
|
|
43967
|
+
deviceUuid: meta.deviceUuid,
|
|
43968
|
+
deviceId: meta.deviceId,
|
|
43969
|
+
bearerToken: meta.bearerToken,
|
|
43970
|
+
claimCode: meta.claimCode,
|
|
43971
|
+
claimUrl: meta.claimUrl,
|
|
43972
|
+
hostname: hostname(),
|
|
43973
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
43974
|
+
userEmail: null,
|
|
43975
|
+
defaultOrgId: null
|
|
43976
|
+
};
|
|
43977
|
+
saveIdentity(id);
|
|
43978
|
+
cachedIdentity = id;
|
|
43979
|
+
},
|
|
43980
|
+
get identity() {
|
|
43981
|
+
return cachedIdentity;
|
|
43982
|
+
},
|
|
43807
43983
|
get bearer() {
|
|
43808
|
-
return
|
|
43984
|
+
return cachedIdentity?.bearerToken ?? null;
|
|
43809
43985
|
},
|
|
43810
43986
|
setBearer(v) {
|
|
43811
|
-
|
|
43987
|
+
if (v === null) {
|
|
43988
|
+
cachedIdentity = null;
|
|
43989
|
+
return;
|
|
43990
|
+
}
|
|
43991
|
+
writeThrough({ bearerToken: v });
|
|
43812
43992
|
},
|
|
43813
43993
|
get deviceId() {
|
|
43814
|
-
return
|
|
43815
|
-
},
|
|
43816
|
-
setDeviceId(v) {
|
|
43817
|
-
store.set("deviceId", v);
|
|
43818
|
-
},
|
|
43819
|
-
get userEmail() {
|
|
43820
|
-
return store.get("userEmail");
|
|
43821
|
-
},
|
|
43822
|
-
setUserEmail(v) {
|
|
43823
|
-
store.set("userEmail", v);
|
|
43994
|
+
return cachedIdentity?.deviceId ?? null;
|
|
43824
43995
|
},
|
|
43825
43996
|
get deviceUuid() {
|
|
43826
|
-
return
|
|
43827
|
-
},
|
|
43828
|
-
setDeviceUuid(v) {
|
|
43829
|
-
store.set("deviceUuid", v);
|
|
43997
|
+
return cachedIdentity?.deviceUuid ?? null;
|
|
43830
43998
|
},
|
|
43831
43999
|
get claimCode() {
|
|
43832
|
-
return
|
|
44000
|
+
return cachedIdentity?.claimCode ?? null;
|
|
43833
44001
|
},
|
|
43834
44002
|
setClaimCode(v) {
|
|
43835
|
-
|
|
44003
|
+
if (!cachedIdentity) return;
|
|
44004
|
+
writeThrough({ claimCode: v });
|
|
43836
44005
|
},
|
|
43837
44006
|
get claimUrl() {
|
|
43838
|
-
return
|
|
44007
|
+
return cachedIdentity?.claimUrl ?? null;
|
|
43839
44008
|
},
|
|
43840
44009
|
setClaimUrl(v) {
|
|
43841
|
-
|
|
44010
|
+
if (!cachedIdentity) return;
|
|
44011
|
+
writeThrough({ claimUrl: v });
|
|
44012
|
+
},
|
|
44013
|
+
get userEmail() {
|
|
44014
|
+
return cachedIdentity?.userEmail ?? null;
|
|
43842
44015
|
},
|
|
44016
|
+
setUserEmail(v) {
|
|
44017
|
+
if (!cachedIdentity) return;
|
|
44018
|
+
writeThrough({ userEmail: v });
|
|
44019
|
+
},
|
|
44020
|
+
// ── Runtime state: stays in conf ───────────────────────────────
|
|
43843
44021
|
getCursor(path5) {
|
|
43844
44022
|
return store.get("cursor")[path5];
|
|
43845
44023
|
},
|
|
@@ -44389,23 +44567,23 @@ var init_pipeline2 = __esm({
|
|
|
44389
44567
|
|
|
44390
44568
|
// src/scan.ts
|
|
44391
44569
|
import { readdir, stat as stat2 } from "fs/promises";
|
|
44392
|
-
import { homedir as
|
|
44393
|
-
import { join as
|
|
44570
|
+
import { homedir as homedir4 } from "os";
|
|
44571
|
+
import { join as join3 } from "path";
|
|
44394
44572
|
async function scanAll(cb = {}) {
|
|
44395
44573
|
const deviceId = state.deviceId;
|
|
44396
44574
|
if (!deviceId) throw new Error("agent not enrolled \u2014 run `register` first");
|
|
44397
44575
|
const jobs = [];
|
|
44398
44576
|
try {
|
|
44399
|
-
const base =
|
|
44577
|
+
const base = join3(homedir4(), ".claude/projects");
|
|
44400
44578
|
const projects = await readdir(base).catch(() => []);
|
|
44401
44579
|
for (const p of projects) {
|
|
44402
|
-
const dir =
|
|
44580
|
+
const dir = join3(base, p);
|
|
44403
44581
|
const ds = await stat2(dir).catch(() => null);
|
|
44404
44582
|
if (!ds?.isDirectory()) continue;
|
|
44405
44583
|
const files = await readdir(dir);
|
|
44406
44584
|
for (const f of files) {
|
|
44407
44585
|
if (!f.endsWith(".jsonl")) continue;
|
|
44408
|
-
const full =
|
|
44586
|
+
const full = join3(dir, f);
|
|
44409
44587
|
jobs.push({
|
|
44410
44588
|
path: full,
|
|
44411
44589
|
parse: async () => {
|
|
@@ -44419,17 +44597,17 @@ async function scanAll(cb = {}) {
|
|
|
44419
44597
|
console.warn("claude scan skipped:", e.message);
|
|
44420
44598
|
}
|
|
44421
44599
|
try {
|
|
44422
|
-
const base =
|
|
44600
|
+
const base = join3(homedir4(), ".codex/sessions");
|
|
44423
44601
|
const years = await readdir(base).catch(() => []);
|
|
44424
44602
|
for (const y of years) {
|
|
44425
|
-
const months = await readdir(
|
|
44603
|
+
const months = await readdir(join3(base, y)).catch(() => []);
|
|
44426
44604
|
for (const m of months) {
|
|
44427
|
-
const days = await readdir(
|
|
44605
|
+
const days = await readdir(join3(base, y, m)).catch(() => []);
|
|
44428
44606
|
for (const d of days) {
|
|
44429
|
-
const files = await readdir(
|
|
44607
|
+
const files = await readdir(join3(base, y, m, d)).catch(() => []);
|
|
44430
44608
|
for (const f of files) {
|
|
44431
44609
|
if (!f.startsWith("rollout-") || !f.endsWith(".jsonl")) continue;
|
|
44432
|
-
const full =
|
|
44610
|
+
const full = join3(base, y, m, d, f);
|
|
44433
44611
|
jobs.push({
|
|
44434
44612
|
path: full,
|
|
44435
44613
|
parse: async () => {
|
|
@@ -44503,7 +44681,7 @@ var init_scan = __esm({
|
|
|
44503
44681
|
init_pipeline2();
|
|
44504
44682
|
init_config2();
|
|
44505
44683
|
init_api();
|
|
44506
|
-
AGENT_VERSION = "agent-dev-0.0.
|
|
44684
|
+
AGENT_VERSION = "agent-dev-0.0.23";
|
|
44507
44685
|
BATCH_MAX_EVENTS = 2e3;
|
|
44508
44686
|
}
|
|
44509
44687
|
});
|
|
@@ -44511,17 +44689,17 @@ var init_scan = __esm({
|
|
|
44511
44689
|
// src/lock.ts
|
|
44512
44690
|
import {
|
|
44513
44691
|
closeSync,
|
|
44514
|
-
existsSync as
|
|
44515
|
-
mkdirSync as
|
|
44692
|
+
existsSync as existsSync6,
|
|
44693
|
+
mkdirSync as mkdirSync3,
|
|
44516
44694
|
openSync,
|
|
44517
|
-
readFileSync as
|
|
44518
|
-
renameSync,
|
|
44695
|
+
readFileSync as readFileSync3,
|
|
44696
|
+
renameSync as renameSync2,
|
|
44519
44697
|
unlinkSync as unlinkSync2,
|
|
44520
|
-
writeFileSync as
|
|
44698
|
+
writeFileSync as writeFileSync4,
|
|
44521
44699
|
writeSync
|
|
44522
44700
|
} from "fs";
|
|
44523
|
-
import { homedir as
|
|
44524
|
-
import { join as
|
|
44701
|
+
import { homedir as homedir6 } from "os";
|
|
44702
|
+
import { join as join5 } from "path";
|
|
44525
44703
|
function isProcessAlive(pid) {
|
|
44526
44704
|
if (!pid || pid <= 0) return false;
|
|
44527
44705
|
try {
|
|
@@ -44535,7 +44713,7 @@ function isProcessAlive(pid) {
|
|
|
44535
44713
|
}
|
|
44536
44714
|
function readLock() {
|
|
44537
44715
|
try {
|
|
44538
|
-
const raw =
|
|
44716
|
+
const raw = readFileSync3(LOCK_FILE, "utf8");
|
|
44539
44717
|
const obj = JSON.parse(raw);
|
|
44540
44718
|
if (typeof obj.pid !== "number") return null;
|
|
44541
44719
|
return {
|
|
@@ -44549,7 +44727,7 @@ function readLock() {
|
|
|
44549
44727
|
}
|
|
44550
44728
|
}
|
|
44551
44729
|
function writeLockAtomic(meta) {
|
|
44552
|
-
|
|
44730
|
+
mkdirSync3(LOCK_DIR, { recursive: true });
|
|
44553
44731
|
const tmp = `${LOCK_FILE}.${meta.pid}.${Date.now()}.tmp`;
|
|
44554
44732
|
const fd = openSync(tmp, "wx");
|
|
44555
44733
|
try {
|
|
@@ -44557,7 +44735,7 @@ function writeLockAtomic(meta) {
|
|
|
44557
44735
|
} finally {
|
|
44558
44736
|
closeSync(fd);
|
|
44559
44737
|
}
|
|
44560
|
-
|
|
44738
|
+
renameSync2(tmp, LOCK_FILE);
|
|
44561
44739
|
}
|
|
44562
44740
|
function removeLockIfOwned(ownerPid) {
|
|
44563
44741
|
const lock = readLock();
|
|
@@ -44622,8 +44800,8 @@ var LOCK_DIR, LOCK_FILE;
|
|
|
44622
44800
|
var init_lock = __esm({
|
|
44623
44801
|
"src/lock.ts"() {
|
|
44624
44802
|
"use strict";
|
|
44625
|
-
LOCK_DIR =
|
|
44626
|
-
LOCK_FILE =
|
|
44803
|
+
LOCK_DIR = join5(homedir6(), ".modelstat");
|
|
44804
|
+
LOCK_FILE = join5(LOCK_DIR, "daemon.lock");
|
|
44627
44805
|
}
|
|
44628
44806
|
});
|
|
44629
44807
|
|
|
@@ -46353,7 +46531,7 @@ __export(daemon_exports, {
|
|
|
46353
46531
|
setProgress: () => setProgress,
|
|
46354
46532
|
setQueue: () => setQueue
|
|
46355
46533
|
});
|
|
46356
|
-
import { existsSync as
|
|
46534
|
+
import { existsSync as existsSync7, statSync as statSync2 } from "fs";
|
|
46357
46535
|
function setPhase(phase, message) {
|
|
46358
46536
|
status.phase = phase;
|
|
46359
46537
|
status.message = message ?? null;
|
|
@@ -46475,21 +46653,21 @@ async function runDaemon(opts = {}) {
|
|
|
46475
46653
|
await runDiscovery();
|
|
46476
46654
|
await runScanCycle("startup");
|
|
46477
46655
|
const chokidar = (await Promise.resolve().then(() => (init_esm2(), esm_exports))).default;
|
|
46478
|
-
const { homedir:
|
|
46479
|
-
const { join:
|
|
46480
|
-
const home2 =
|
|
46656
|
+
const { homedir: homedir8, platform: platform5 } = await import("os");
|
|
46657
|
+
const { join: join9 } = await import("path");
|
|
46658
|
+
const home2 = homedir8();
|
|
46481
46659
|
const dirs = [
|
|
46482
|
-
|
|
46483
|
-
|
|
46484
|
-
|
|
46485
|
-
|
|
46660
|
+
join9(home2, ".claude/projects"),
|
|
46661
|
+
join9(home2, ".codex/sessions"),
|
|
46662
|
+
join9(home2, ".cursor/ai-tracking"),
|
|
46663
|
+
join9(home2, ".gemini"),
|
|
46486
46664
|
...platform5() === "darwin" ? [
|
|
46487
|
-
|
|
46488
|
-
|
|
46665
|
+
join9(home2, "Library/Application Support/Cursor/User/workspaceStorage"),
|
|
46666
|
+
join9(home2, "Library/Application Support/Claude")
|
|
46489
46667
|
] : [
|
|
46490
|
-
|
|
46668
|
+
join9(home2, ".config/Cursor/User/workspaceStorage")
|
|
46491
46669
|
]
|
|
46492
|
-
].filter((p) =>
|
|
46670
|
+
].filter((p) => existsSync7(p) && statSync2(p).isDirectory());
|
|
46493
46671
|
setPhase("watching", `Watching ${dirs.length} directories`);
|
|
46494
46672
|
const watcher = chokidar.watch(dirs, {
|
|
46495
46673
|
persistent: true,
|
|
@@ -46536,7 +46714,7 @@ var init_daemon = __esm({
|
|
|
46536
46714
|
init_config2();
|
|
46537
46715
|
init_lock();
|
|
46538
46716
|
init_scan();
|
|
46539
|
-
AGENT_VERSION2 = "agent-dev-0.0.
|
|
46717
|
+
AGENT_VERSION2 = "agent-dev-0.0.23";
|
|
46540
46718
|
HEARTBEAT_INTERVAL_MS = 1e4;
|
|
46541
46719
|
SCAN_INTERVAL_MS = 5 * 60 * 1e3;
|
|
46542
46720
|
status = {
|
|
@@ -46556,37 +46734,37 @@ var watch_exports = {};
|
|
|
46556
46734
|
__export(watch_exports, {
|
|
46557
46735
|
watchForever: () => watchForever
|
|
46558
46736
|
});
|
|
46559
|
-
import { existsSync as
|
|
46560
|
-
import { homedir as
|
|
46561
|
-
import { join as
|
|
46737
|
+
import { existsSync as existsSync8 } from "fs";
|
|
46738
|
+
import { homedir as homedir7, platform as platform3 } from "os";
|
|
46739
|
+
import { join as join8 } from "path";
|
|
46562
46740
|
function resolveWatchDirs() {
|
|
46563
|
-
const home2 =
|
|
46564
|
-
const xdgConfig = process.env.XDG_CONFIG_HOME ??
|
|
46565
|
-
const xdgData = process.env.XDG_DATA_HOME ??
|
|
46741
|
+
const home2 = homedir7();
|
|
46742
|
+
const xdgConfig = process.env.XDG_CONFIG_HOME ?? join8(home2, ".config");
|
|
46743
|
+
const xdgData = process.env.XDG_DATA_HOME ?? join8(home2, ".local/share");
|
|
46566
46744
|
const candidates = [
|
|
46567
46745
|
// universal (default HOME-rooted CLI data dirs)
|
|
46568
|
-
|
|
46569
|
-
|
|
46570
|
-
|
|
46571
|
-
|
|
46572
|
-
|
|
46746
|
+
join8(home2, ".claude/projects"),
|
|
46747
|
+
join8(home2, ".codex/sessions"),
|
|
46748
|
+
join8(home2, ".cursor/ai-tracking"),
|
|
46749
|
+
join8(home2, ".gemini"),
|
|
46750
|
+
join8(home2, ".aider"),
|
|
46573
46751
|
// XDG / Linux
|
|
46574
|
-
|
|
46575
|
-
|
|
46576
|
-
|
|
46577
|
-
|
|
46578
|
-
|
|
46579
|
-
|
|
46752
|
+
join8(xdgConfig, "claude/projects"),
|
|
46753
|
+
join8(xdgConfig, "codex/sessions"),
|
|
46754
|
+
join8(xdgConfig, "Cursor/User/workspaceStorage"),
|
|
46755
|
+
join8(xdgConfig, "Code/User/workspaceStorage"),
|
|
46756
|
+
join8(xdgConfig, "Code - Insiders/User/workspaceStorage"),
|
|
46757
|
+
join8(xdgData, "claude/projects"),
|
|
46580
46758
|
// macOS
|
|
46581
46759
|
...platform3() === "darwin" ? [
|
|
46582
|
-
|
|
46583
|
-
|
|
46584
|
-
|
|
46585
|
-
|
|
46586
|
-
|
|
46760
|
+
join8(home2, "Library/Application Support/Cursor/User/workspaceStorage"),
|
|
46761
|
+
join8(home2, "Library/Application Support/Claude"),
|
|
46762
|
+
join8(home2, "Library/Application Support/Code/User/workspaceStorage"),
|
|
46763
|
+
join8(home2, "Library/Application Support/Windsurf/User/workspaceStorage"),
|
|
46764
|
+
join8(home2, "Library/Application Support/Zed")
|
|
46587
46765
|
] : []
|
|
46588
46766
|
];
|
|
46589
|
-
return Array.from(new Set(candidates)).filter((p) =>
|
|
46767
|
+
return Array.from(new Set(candidates)).filter((p) => existsSync8(p));
|
|
46590
46768
|
}
|
|
46591
46769
|
async function safeScan(reason) {
|
|
46592
46770
|
if (scanning) {
|
|
@@ -46646,51 +46824,53 @@ var init_watch = __esm({
|
|
|
46646
46824
|
|
|
46647
46825
|
// src/cli.ts
|
|
46648
46826
|
init_src2();
|
|
46827
|
+
init_identity();
|
|
46649
46828
|
init_api();
|
|
46650
46829
|
init_config2();
|
|
46651
46830
|
init_scan();
|
|
46652
46831
|
import { spawn } from "child_process";
|
|
46653
46832
|
import { randomBytes } from "crypto";
|
|
46654
46833
|
import { platform as platform4, release, arch as cpuArch, hostname as hostname2 } from "os";
|
|
46834
|
+
import { createInterface as createInterface3 } from "readline";
|
|
46655
46835
|
|
|
46656
46836
|
// src/service.ts
|
|
46657
46837
|
import { spawnSync } from "child_process";
|
|
46658
46838
|
import {
|
|
46659
46839
|
copyFileSync,
|
|
46660
|
-
existsSync as
|
|
46661
|
-
mkdirSync,
|
|
46840
|
+
existsSync as existsSync5,
|
|
46841
|
+
mkdirSync as mkdirSync2,
|
|
46662
46842
|
unlinkSync,
|
|
46663
|
-
writeFileSync as
|
|
46843
|
+
writeFileSync as writeFileSync3
|
|
46664
46844
|
} from "fs";
|
|
46665
|
-
import { homedir as
|
|
46666
|
-
import { dirname as dirname4, join as
|
|
46845
|
+
import { homedir as homedir5, platform as platform2, userInfo } from "os";
|
|
46846
|
+
import { dirname as dirname4, join as join4 } from "path";
|
|
46667
46847
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
46668
46848
|
var SERVICE_LABEL = "ai.modelstat.agent";
|
|
46669
46849
|
var SYSTEMD_UNIT = "modelstat";
|
|
46670
46850
|
function home() {
|
|
46671
|
-
return
|
|
46851
|
+
return homedir5();
|
|
46672
46852
|
}
|
|
46673
46853
|
function stateDir() {
|
|
46674
|
-
return
|
|
46854
|
+
return join4(home(), ".modelstat");
|
|
46675
46855
|
}
|
|
46676
46856
|
function binDir() {
|
|
46677
|
-
return
|
|
46857
|
+
return join4(stateDir(), "bin");
|
|
46678
46858
|
}
|
|
46679
46859
|
function logDir() {
|
|
46680
|
-
return
|
|
46860
|
+
return join4(stateDir(), "logs");
|
|
46681
46861
|
}
|
|
46682
46862
|
function installedCliPath() {
|
|
46683
|
-
return
|
|
46863
|
+
return join4(binDir(), "modelstat.mjs");
|
|
46684
46864
|
}
|
|
46685
46865
|
function runningCliPath() {
|
|
46686
46866
|
return fileURLToPath2(import.meta.url).replace(/service\.(mjs|js|ts)$/, "cli.mjs");
|
|
46687
46867
|
}
|
|
46688
46868
|
function installBundle() {
|
|
46689
|
-
|
|
46690
|
-
|
|
46869
|
+
mkdirSync2(binDir(), { recursive: true });
|
|
46870
|
+
mkdirSync2(logDir(), { recursive: true });
|
|
46691
46871
|
const src = runningCliPath();
|
|
46692
46872
|
const dest = installedCliPath();
|
|
46693
|
-
if (!
|
|
46873
|
+
if (!existsSync5(src)) {
|
|
46694
46874
|
throw new Error(
|
|
46695
46875
|
`Can't find the CLI bundle to install from (${src}). Are you running a local dev build?`
|
|
46696
46876
|
);
|
|
@@ -46702,21 +46882,21 @@ function nodeBinary() {
|
|
|
46702
46882
|
return process.execPath;
|
|
46703
46883
|
}
|
|
46704
46884
|
function plistPath() {
|
|
46705
|
-
return
|
|
46885
|
+
return join4(home(), "Library", "LaunchAgents", `${SERVICE_LABEL}.plist`);
|
|
46706
46886
|
}
|
|
46707
46887
|
function locateTrayExecutable() {
|
|
46708
46888
|
const candidates = [
|
|
46709
|
-
|
|
46889
|
+
join4(home(), "Applications", "ModelstatTray.app", "Contents", "MacOS", "modelstat-tray"),
|
|
46710
46890
|
"/Applications/ModelstatTray.app/Contents/MacOS/modelstat-tray"
|
|
46711
46891
|
];
|
|
46712
46892
|
for (const p of candidates) {
|
|
46713
|
-
if (
|
|
46893
|
+
if (existsSync5(p)) return p;
|
|
46714
46894
|
}
|
|
46715
46895
|
return null;
|
|
46716
46896
|
}
|
|
46717
46897
|
function writePlist(cliPath) {
|
|
46718
46898
|
const p = plistPath();
|
|
46719
|
-
|
|
46899
|
+
mkdirSync2(dirname4(p), { recursive: true });
|
|
46720
46900
|
const tray = locateTrayExecutable();
|
|
46721
46901
|
const programArgs = tray ? ` <string>${tray}</string>` : [
|
|
46722
46902
|
` <string>${nodeBinary()}</string>`,
|
|
@@ -46736,8 +46916,8 @@ ${programArgs}
|
|
|
46736
46916
|
<key>KeepAlive</key>
|
|
46737
46917
|
<dict><key>SuccessfulExit</key><false/></dict>
|
|
46738
46918
|
<key>ThrottleInterval</key><integer>30</integer>
|
|
46739
|
-
<key>StandardOutPath</key><string>${
|
|
46740
|
-
<key>StandardErrorPath</key><string>${
|
|
46919
|
+
<key>StandardOutPath</key><string>${join4(logDir(), "out.log")}</string>
|
|
46920
|
+
<key>StandardErrorPath</key><string>${join4(logDir(), "err.log")}</string>
|
|
46741
46921
|
<key>EnvironmentVariables</key>
|
|
46742
46922
|
<dict>
|
|
46743
46923
|
<key>PATH</key><string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin</string>
|
|
@@ -46746,7 +46926,7 @@ ${programArgs}
|
|
|
46746
46926
|
</dict>
|
|
46747
46927
|
</plist>
|
|
46748
46928
|
`;
|
|
46749
|
-
|
|
46929
|
+
writeFileSync3(p, plist, { mode: 420 });
|
|
46750
46930
|
return p;
|
|
46751
46931
|
}
|
|
46752
46932
|
function launchctl(args) {
|
|
@@ -46777,7 +46957,7 @@ function macUninstall() {
|
|
|
46777
46957
|
const target = `gui/${uid}/${SERVICE_LABEL}`;
|
|
46778
46958
|
launchctl(["bootout", target]);
|
|
46779
46959
|
const plist = plistPath();
|
|
46780
|
-
if (
|
|
46960
|
+
if (existsSync5(plist)) {
|
|
46781
46961
|
try {
|
|
46782
46962
|
unlinkSync(plist);
|
|
46783
46963
|
} catch {
|
|
@@ -46790,12 +46970,12 @@ function macStatus() {
|
|
|
46790
46970
|
return { running: r.ok, hint: r.ok ? "launchd managed" : "not installed" };
|
|
46791
46971
|
}
|
|
46792
46972
|
function systemdUnitPath() {
|
|
46793
|
-
const xdg = process.env.XDG_CONFIG_HOME ??
|
|
46794
|
-
return
|
|
46973
|
+
const xdg = process.env.XDG_CONFIG_HOME ?? join4(home(), ".config");
|
|
46974
|
+
return join4(xdg, "systemd", "user", `${SYSTEMD_UNIT}.service`);
|
|
46795
46975
|
}
|
|
46796
46976
|
function writeSystemdUnit(cliPath) {
|
|
46797
46977
|
const unitPath = systemdUnitPath();
|
|
46798
|
-
|
|
46978
|
+
mkdirSync2(dirname4(unitPath), { recursive: true });
|
|
46799
46979
|
const unit = `[Unit]
|
|
46800
46980
|
Description=modelstat agent
|
|
46801
46981
|
Documentation=https://modelstat.ai
|
|
@@ -46810,13 +46990,13 @@ RestartSec=10
|
|
|
46810
46990
|
# Don't restart-storm if the service is persistently unreachable.
|
|
46811
46991
|
StartLimitIntervalSec=300
|
|
46812
46992
|
StartLimitBurst=10
|
|
46813
|
-
StandardOutput=append:${
|
|
46814
|
-
StandardError=append:${
|
|
46993
|
+
StandardOutput=append:${join4(logDir(), "out.log")}
|
|
46994
|
+
StandardError=append:${join4(logDir(), "err.log")}
|
|
46815
46995
|
|
|
46816
46996
|
[Install]
|
|
46817
46997
|
WantedBy=default.target
|
|
46818
46998
|
`;
|
|
46819
|
-
|
|
46999
|
+
writeFileSync3(unitPath, unit, { mode: 420 });
|
|
46820
47000
|
return unitPath;
|
|
46821
47001
|
}
|
|
46822
47002
|
function systemctl(args) {
|
|
@@ -46836,7 +47016,7 @@ function linuxInstall() {
|
|
|
46836
47016
|
function linuxUninstall() {
|
|
46837
47017
|
systemctl(["disable", "--now", `${SYSTEMD_UNIT}.service`]);
|
|
46838
47018
|
const unit = systemdUnitPath();
|
|
46839
|
-
if (
|
|
47019
|
+
if (existsSync5(unit)) {
|
|
46840
47020
|
try {
|
|
46841
47021
|
unlinkSync(unit);
|
|
46842
47022
|
} catch {
|
|
@@ -46880,9 +47060,9 @@ function logsDir() {
|
|
|
46880
47060
|
}
|
|
46881
47061
|
function installTrayApp(sourceAppPath) {
|
|
46882
47062
|
if (platform2() !== "darwin") return null;
|
|
46883
|
-
if (!
|
|
46884
|
-
const dest =
|
|
46885
|
-
|
|
47063
|
+
if (!existsSync5(sourceAppPath)) return null;
|
|
47064
|
+
const dest = join4(home(), "Applications", "ModelstatTray.app");
|
|
47065
|
+
mkdirSync2(dirname4(dest), { recursive: true });
|
|
46886
47066
|
spawnSync("rm", ["-rf", dest]);
|
|
46887
47067
|
const r = spawnSync("cp", ["-R", sourceAppPath, dest], { encoding: "utf8" });
|
|
46888
47068
|
if (r.status !== 0) {
|
|
@@ -46895,25 +47075,25 @@ function bundledTrayAppPath() {
|
|
|
46895
47075
|
const here2 = dirname4(fileURLToPath2(import.meta.url));
|
|
46896
47076
|
const candidates = [
|
|
46897
47077
|
// Pre-built .app — CI with codesigning drops one here.
|
|
46898
|
-
|
|
47078
|
+
join4(here2, "..", "vendor", "ModelstatTray.app"),
|
|
46899
47079
|
// Local dev layout: apps/agent-dev/src/service.ts → ../../tray-mac/build/ModelstatTray.app
|
|
46900
|
-
|
|
47080
|
+
join4(here2, "..", "..", "tray-mac", "build", "ModelstatTray.app")
|
|
46901
47081
|
];
|
|
46902
47082
|
for (const c of candidates) {
|
|
46903
|
-
if (
|
|
47083
|
+
if (existsSync5(c)) return c;
|
|
46904
47084
|
}
|
|
46905
47085
|
const sourceDirs = [
|
|
46906
|
-
|
|
46907
|
-
|
|
47086
|
+
join4(here2, "..", "vendor", "tray-mac"),
|
|
47087
|
+
join4(here2, "..", "..", "tray-mac")
|
|
46908
47088
|
];
|
|
46909
47089
|
for (const src of sourceDirs) {
|
|
46910
|
-
const build =
|
|
46911
|
-
if (!
|
|
47090
|
+
const build = join4(src, "build-app.sh");
|
|
47091
|
+
if (!existsSync5(build)) continue;
|
|
46912
47092
|
if (!hasSwift()) return null;
|
|
46913
47093
|
const r = spawnSync("bash", [build], { cwd: src, encoding: "utf8" });
|
|
46914
47094
|
if (r.status === 0) {
|
|
46915
|
-
const app =
|
|
46916
|
-
if (
|
|
47095
|
+
const app = join4(src, "build", "ModelstatTray.app");
|
|
47096
|
+
if (existsSync5(app)) return app;
|
|
46917
47097
|
}
|
|
46918
47098
|
}
|
|
46919
47099
|
return null;
|
|
@@ -46929,6 +47109,20 @@ function trayStatus() {
|
|
|
46929
47109
|
}
|
|
46930
47110
|
|
|
46931
47111
|
// src/cli.ts
|
|
47112
|
+
async function confirmPrompt(question, defaultYes) {
|
|
47113
|
+
if (process.stdin.isTTY !== true) return defaultYes;
|
|
47114
|
+
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
47115
|
+
try {
|
|
47116
|
+
const raw = await new Promise((resolve6) => rl.question(question, resolve6));
|
|
47117
|
+
const ans = raw.trim().toLowerCase();
|
|
47118
|
+
if (ans === "") return defaultYes;
|
|
47119
|
+
if (ans === "y" || ans === "yes") return true;
|
|
47120
|
+
if (ans === "n" || ans === "no") return false;
|
|
47121
|
+
return defaultYes;
|
|
47122
|
+
} finally {
|
|
47123
|
+
rl.close();
|
|
47124
|
+
}
|
|
47125
|
+
}
|
|
46932
47126
|
function tryOpenBrowser(url) {
|
|
46933
47127
|
const p = platform4();
|
|
46934
47128
|
const cmd = p === "darwin" ? "open" : p === "win32" ? "cmd" : "xdg-open";
|
|
@@ -46995,11 +47189,13 @@ async function cmdSelfRegister() {
|
|
|
46995
47189
|
device_uuid: deviceUuid,
|
|
46996
47190
|
fingerprint
|
|
46997
47191
|
});
|
|
46998
|
-
state.
|
|
46999
|
-
|
|
47000
|
-
|
|
47001
|
-
|
|
47002
|
-
|
|
47192
|
+
state.saveFreshIdentity({
|
|
47193
|
+
deviceUuid: res.device_uuid,
|
|
47194
|
+
deviceId: res.device_id,
|
|
47195
|
+
bearerToken: res.device_secret,
|
|
47196
|
+
claimCode: res.claim_code,
|
|
47197
|
+
claimUrl: res.claim_url
|
|
47198
|
+
});
|
|
47003
47199
|
process.stdout.write(` \x1B[32m\u2713\x1B[0m registered device_id=${res.device_id}
|
|
47004
47200
|
`);
|
|
47005
47201
|
process.stdout.write(` \x1B[32m\u2713\x1B[0m secret ${res.secret_prefix}\u2026 (hashed on server, never re-sent)
|
|
@@ -47059,19 +47255,21 @@ async function cmdConnect(opts) {
|
|
|
47059
47255
|
};
|
|
47060
47256
|
const wipeAndSelfRegister = async (reason) => {
|
|
47061
47257
|
warn(`${reason} \u2014 re-registering this device`);
|
|
47258
|
+
const bak = backupIdentity();
|
|
47259
|
+
if (bak) warn(`old identity moved to ${bak}`);
|
|
47062
47260
|
state.setBearer(null);
|
|
47063
|
-
state.setDeviceId(null);
|
|
47064
|
-
state.setDeviceUuid(null);
|
|
47065
|
-
state.setClaimCode(null);
|
|
47066
|
-
state.setClaimUrl(null);
|
|
47067
47261
|
await cmdSelfRegister();
|
|
47068
47262
|
};
|
|
47069
|
-
if (
|
|
47263
|
+
if (opts.fresh && hasIdentityFile()) {
|
|
47264
|
+
step("`--fresh` passed \u2014 minting a new device identity");
|
|
47265
|
+
await wipeAndSelfRegister("forced fresh start");
|
|
47266
|
+
} else if (!state.deviceUuid || !state.bearer || !state.deviceId) {
|
|
47070
47267
|
step("Registering this device with modelstat.ai");
|
|
47071
47268
|
await cmdSelfRegister();
|
|
47072
47269
|
} else {
|
|
47073
47270
|
step("Re-using existing device identity");
|
|
47074
47271
|
ok(`device ${state.deviceId}`);
|
|
47272
|
+
ok(`identity file ${identityPath()}`);
|
|
47075
47273
|
try {
|
|
47076
47274
|
const me = await fetchDeviceMe(state.bearer);
|
|
47077
47275
|
if (me.claim_code && me.claim_code !== state.claimCode) {
|
|
@@ -47083,6 +47281,15 @@ async function cmdConnect(opts) {
|
|
|
47083
47281
|
}
|
|
47084
47282
|
} catch (e) {
|
|
47085
47283
|
if (e instanceof DeviceMeUnauthorized) {
|
|
47284
|
+
const interactive = !opts.yes && process.stdin.isTTY === true;
|
|
47285
|
+
if (interactive) {
|
|
47286
|
+
const prompt = "cached credentials no longer accepted by the server. Re-register this device? [Y/n] ";
|
|
47287
|
+
const answer = await confirmPrompt(prompt, true);
|
|
47288
|
+
if (!answer) {
|
|
47289
|
+
warn("keeping existing identity; connect aborted");
|
|
47290
|
+
return;
|
|
47291
|
+
}
|
|
47292
|
+
}
|
|
47086
47293
|
await wipeAndSelfRegister("cached credentials no longer valid");
|
|
47087
47294
|
} else {
|
|
47088
47295
|
warn(`couldn't refresh device state: ${e.message}`);
|
|
@@ -47362,7 +47569,9 @@ function cmdPaths(args) {
|
|
|
47362
47569
|
function parseConnectOpts(argv) {
|
|
47363
47570
|
return {
|
|
47364
47571
|
json: argv.includes("--json"),
|
|
47365
|
-
noBrowser: argv.includes("--no-browser")
|
|
47572
|
+
noBrowser: argv.includes("--no-browser"),
|
|
47573
|
+
fresh: argv.includes("--fresh"),
|
|
47574
|
+
yes: argv.includes("--yes") || argv.includes("-y")
|
|
47366
47575
|
};
|
|
47367
47576
|
}
|
|
47368
47577
|
async function main() {
|