modelstat 0.0.42 → 0.0.44
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 +335 -129
- package/dist/cli.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -4421,7 +4421,15 @@ var init_schemas = __esm({
|
|
|
4421
4421
|
installation_id: external_exports.string(),
|
|
4422
4422
|
identity_id: external_exports.string().nullable()
|
|
4423
4423
|
})
|
|
4424
|
-
).optional()
|
|
4424
|
+
).optional(),
|
|
4425
|
+
/** Optional per-session titles — session_id → short redacted title
|
|
4426
|
+
* (≤120 chars) produced by the companion's local titler from the
|
|
4427
|
+
* session's segment abstracts. Server-side this is last-write-wins
|
|
4428
|
+
* per session; companions recompute it from the full session view on
|
|
4429
|
+
* every upload, so the latest batch always carries the freshest
|
|
4430
|
+
* title. Absent for runtimes without a titler (older agents, no-op
|
|
4431
|
+
* browser summariser) — the server keeps whatever it has. */
|
|
4432
|
+
session_titles: external_exports.record(external_exports.string(), external_exports.string().max(120)).optional()
|
|
4425
4433
|
});
|
|
4426
4434
|
HeartbeatPayload = external_exports.object({
|
|
4427
4435
|
device_id: external_exports.string(),
|
|
@@ -4542,6 +4550,8 @@ function sourceEventId(deviceId, sourceOrFilePath, byteOffsetMaybe) {
|
|
|
4542
4550
|
key = `fs::${sourceOrFilePath}::${byteOffset}`;
|
|
4543
4551
|
} else if ("file" in sourceOrFilePath) {
|
|
4544
4552
|
key = `fs::${sourceOrFilePath.file}::${sourceOrFilePath.byteOffset}`;
|
|
4553
|
+
} else if ("lineUuid" in sourceOrFilePath) {
|
|
4554
|
+
key = `uuid::${sourceOrFilePath.lineUuid}`;
|
|
4545
4555
|
} else {
|
|
4546
4556
|
key = `web::${sourceOrFilePath.host}::${sourceOrFilePath.conversationId}::${sourceOrFilePath.messageId}`;
|
|
4547
4557
|
}
|
|
@@ -4674,8 +4684,9 @@ var init_src = __esm({
|
|
|
4674
4684
|
|
|
4675
4685
|
// ../../packages/parsers/src/claude-code/index.ts
|
|
4676
4686
|
import { createHash } from "crypto";
|
|
4677
|
-
import { createReadStream } from "fs";
|
|
4687
|
+
import { createReadStream, existsSync as existsSync2, readdirSync } from "fs";
|
|
4678
4688
|
import { stat } from "fs/promises";
|
|
4689
|
+
import { dirname as dirname2, join } from "path";
|
|
4679
4690
|
import { createInterface } from "readline";
|
|
4680
4691
|
function extractExcerpt(content) {
|
|
4681
4692
|
if (!content) return void 0;
|
|
@@ -4714,6 +4725,37 @@ async function parseClaudeCodeJsonl(ctx) {
|
|
|
4714
4725
|
let cwd = null;
|
|
4715
4726
|
let gitBranch = null;
|
|
4716
4727
|
let lastModel = null;
|
|
4728
|
+
const filenameSessionId = deriveSessionIdFromFilename(ctx.sourceFile);
|
|
4729
|
+
const ancestorExistsCache = /* @__PURE__ */ new Map();
|
|
4730
|
+
function ancestorFileExists(sid) {
|
|
4731
|
+
const cached2 = ancestorExistsCache.get(sid);
|
|
4732
|
+
if (cached2 !== void 0) return cached2;
|
|
4733
|
+
let found = false;
|
|
4734
|
+
const dir = dirname2(ctx.sourceFile);
|
|
4735
|
+
try {
|
|
4736
|
+
if (existsSync2(join(dir, `${sid}.jsonl`))) {
|
|
4737
|
+
found = true;
|
|
4738
|
+
} else {
|
|
4739
|
+
const root = dirname2(dir);
|
|
4740
|
+
for (const entry of readdirSync(root, { withFileTypes: true })) {
|
|
4741
|
+
if (!entry.isDirectory()) continue;
|
|
4742
|
+
if (existsSync2(join(root, entry.name, `${sid}.jsonl`))) {
|
|
4743
|
+
found = true;
|
|
4744
|
+
break;
|
|
4745
|
+
}
|
|
4746
|
+
}
|
|
4747
|
+
}
|
|
4748
|
+
} catch {
|
|
4749
|
+
}
|
|
4750
|
+
ancestorExistsCache.set(sid, found);
|
|
4751
|
+
return found;
|
|
4752
|
+
}
|
|
4753
|
+
function dedupeIdFor(lineUuid, byteOffset) {
|
|
4754
|
+
const isResumeCopy = filenameSessionId !== null && sessionId !== filenameSessionId;
|
|
4755
|
+
if (!isResumeCopy) return sourceEventId(ctx.deviceId, ctx.sourceFile, byteOffset);
|
|
4756
|
+
if (ancestorFileExists(sessionId)) return null;
|
|
4757
|
+
return sourceEventId(ctx.deviceId, { lineUuid });
|
|
4758
|
+
}
|
|
4717
4759
|
for await (const line of rl) {
|
|
4718
4760
|
const byteLen = Buffer.byteLength(line, "utf8") + 1;
|
|
4719
4761
|
const offsetAtLineStart = startOffset + bytePos;
|
|
@@ -4743,15 +4785,22 @@ async function parseClaudeCodeJsonl(ctx) {
|
|
|
4743
4785
|
if (obj.type === "assistant") {
|
|
4744
4786
|
const a = obj;
|
|
4745
4787
|
const usage = a.message?.usage ?? {};
|
|
4746
|
-
|
|
4788
|
+
if (a.message?.model && a.message.model !== "<synthetic>") {
|
|
4789
|
+
lastModel = a.message.model;
|
|
4790
|
+
}
|
|
4747
4791
|
if (!a.uuid || !sessionId) {
|
|
4748
4792
|
skipped += 1;
|
|
4749
4793
|
continue;
|
|
4750
4794
|
}
|
|
4795
|
+
const eventId = dedupeIdFor(a.uuid, offsetAtLineStart);
|
|
4796
|
+
if (eventId === null) {
|
|
4797
|
+
skipped += 1;
|
|
4798
|
+
continue;
|
|
4799
|
+
}
|
|
4751
4800
|
const slug = guessRepoSlugFromPath(cwd);
|
|
4752
4801
|
const excerpt = extractExcerpt(a.message?.content);
|
|
4753
4802
|
events.push({
|
|
4754
|
-
source_event_id:
|
|
4803
|
+
source_event_id: eventId,
|
|
4755
4804
|
ts: a.timestamp,
|
|
4756
4805
|
kind: "assistant_message",
|
|
4757
4806
|
tool: "claude_code",
|
|
@@ -4793,9 +4842,14 @@ async function parseClaudeCodeJsonl(ctx) {
|
|
|
4793
4842
|
skipped += 1;
|
|
4794
4843
|
continue;
|
|
4795
4844
|
}
|
|
4845
|
+
const eventId = dedupeIdFor(u.uuid, offsetAtLineStart);
|
|
4846
|
+
if (eventId === null) {
|
|
4847
|
+
skipped += 1;
|
|
4848
|
+
continue;
|
|
4849
|
+
}
|
|
4796
4850
|
const excerpt = extractExcerpt(u.message?.content);
|
|
4797
4851
|
events.push({
|
|
4798
|
-
source_event_id:
|
|
4852
|
+
source_event_id: eventId,
|
|
4799
4853
|
ts: u.timestamp,
|
|
4800
4854
|
kind: "user_message",
|
|
4801
4855
|
tool: "claude_code",
|
|
@@ -4825,6 +4879,10 @@ async function parseClaudeCodeJsonl(ctx) {
|
|
|
4825
4879
|
sourceFile: ctx.sourceFile
|
|
4826
4880
|
};
|
|
4827
4881
|
}
|
|
4882
|
+
function deriveSessionIdFromFilename(path5) {
|
|
4883
|
+
const m = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/.exec(path5);
|
|
4884
|
+
return m ? m[1] ?? null : null;
|
|
4885
|
+
}
|
|
4828
4886
|
async function quickChecksum(path5) {
|
|
4829
4887
|
const st = await stat(path5);
|
|
4830
4888
|
const stream = createReadStream(path5, {
|
|
@@ -7145,9 +7203,9 @@ var init_cursor = __esm({
|
|
|
7145
7203
|
|
|
7146
7204
|
// ../../packages/parsers/src/discovery/index.ts
|
|
7147
7205
|
import { execFile as execFile2, execSync } from "child_process";
|
|
7148
|
-
import { existsSync as
|
|
7206
|
+
import { existsSync as existsSync3, statSync } from "fs";
|
|
7149
7207
|
import { homedir, platform } from "os";
|
|
7150
|
-
import { join, resolve as resolve2 } from "path";
|
|
7208
|
+
import { join as join2, resolve as resolve2 } from "path";
|
|
7151
7209
|
import { promisify as promisify2 } from "util";
|
|
7152
7210
|
async function discover(options = {}) {
|
|
7153
7211
|
const os2 = platform() === "darwin" ? "macos" : "linux";
|
|
@@ -7163,7 +7221,7 @@ async function discover(options = {}) {
|
|
|
7163
7221
|
}
|
|
7164
7222
|
for (const extra of options.extraDataDirs?.[spec.tool] ?? []) candidates.add(expandPath(extra));
|
|
7165
7223
|
for (const p of candidates) {
|
|
7166
|
-
if (
|
|
7224
|
+
if (existsSync3(p) && statSync(p).isDirectory()) {
|
|
7167
7225
|
installations.push({
|
|
7168
7226
|
tool: spec.tool,
|
|
7169
7227
|
install_method: "manual",
|
|
@@ -7180,8 +7238,8 @@ async function discover(options = {}) {
|
|
|
7180
7238
|
for (const spec of SOURCES) {
|
|
7181
7239
|
for (const bin of spec.binaries ?? []) {
|
|
7182
7240
|
for (const dir of binDirs) {
|
|
7183
|
-
const p =
|
|
7184
|
-
if (
|
|
7241
|
+
const p = join2(dir, bin);
|
|
7242
|
+
if (existsSync3(p)) {
|
|
7185
7243
|
const version = await safeVersionProbe(p);
|
|
7186
7244
|
installations.push({
|
|
7187
7245
|
tool: spec.tool,
|
|
@@ -7331,7 +7389,7 @@ async function probeIdentities(os2) {
|
|
|
7331
7389
|
`${homedir()}/.codex/auth.json`,
|
|
7332
7390
|
`${homedir()}/.config/codex/auth.json`
|
|
7333
7391
|
]) {
|
|
7334
|
-
if (!
|
|
7392
|
+
if (!existsSync3(candidate)) continue;
|
|
7335
7393
|
try {
|
|
7336
7394
|
const data = await fs4.promises.readFile(candidate, "utf8");
|
|
7337
7395
|
const obj = JSON.parse(data);
|
|
@@ -7379,7 +7437,7 @@ async function probeIdentities(os2) {
|
|
|
7379
7437
|
`${homedir()}/.gemini/oauth_creds.json`,
|
|
7380
7438
|
`${homedir()}/.config/gemini/oauth_creds.json`
|
|
7381
7439
|
]) {
|
|
7382
|
-
if (!
|
|
7440
|
+
if (!existsSync3(candidate)) continue;
|
|
7383
7441
|
try {
|
|
7384
7442
|
const data = await fs4.promises.readFile(candidate, "utf8");
|
|
7385
7443
|
const obj = JSON.parse(data);
|
|
@@ -7401,7 +7459,7 @@ async function probeIdentities(os2) {
|
|
|
7401
7459
|
`${homedir()}/Library/Application Support/Cursor/User/globalStorage/storage.json`,
|
|
7402
7460
|
`${homedir()}/.config/Cursor/User/globalStorage/storage.json`
|
|
7403
7461
|
]) {
|
|
7404
|
-
if (!
|
|
7462
|
+
if (!existsSync3(candidate)) continue;
|
|
7405
7463
|
try {
|
|
7406
7464
|
const data = await fs4.promises.readFile(candidate, "utf8");
|
|
7407
7465
|
const obj = JSON.parse(data);
|
|
@@ -7561,10 +7619,10 @@ import {
|
|
|
7561
7619
|
readFileSync as readFileSync2,
|
|
7562
7620
|
renameSync,
|
|
7563
7621
|
writeFileSync,
|
|
7564
|
-
existsSync as
|
|
7622
|
+
existsSync as existsSync4
|
|
7565
7623
|
} from "fs";
|
|
7566
7624
|
import { homedir as homedir2, hostname as osHostname } from "os";
|
|
7567
|
-
import { join as
|
|
7625
|
+
import { join as join3 } from "path";
|
|
7568
7626
|
function ensureRoot() {
|
|
7569
7627
|
mkdirSync(ROOT, { recursive: true, mode: 448 });
|
|
7570
7628
|
}
|
|
@@ -7582,7 +7640,7 @@ function identityPath() {
|
|
|
7582
7640
|
return IDENTITY_FILE;
|
|
7583
7641
|
}
|
|
7584
7642
|
function hasIdentityFile() {
|
|
7585
|
-
return
|
|
7643
|
+
return existsSync4(IDENTITY_FILE);
|
|
7586
7644
|
}
|
|
7587
7645
|
function parseFile() {
|
|
7588
7646
|
try {
|
|
@@ -7633,7 +7691,7 @@ function saveIdentity(meta) {
|
|
|
7633
7691
|
writeAtomic(meta);
|
|
7634
7692
|
}
|
|
7635
7693
|
function backupIdentity() {
|
|
7636
|
-
if (!
|
|
7694
|
+
if (!existsSync4(IDENTITY_FILE)) return null;
|
|
7637
7695
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
7638
7696
|
const dest = `${IDENTITY_FILE}.bak-${stamp}`;
|
|
7639
7697
|
renameSync(IDENTITY_FILE, dest);
|
|
@@ -7650,8 +7708,8 @@ var ROOT, IDENTITY_FILE;
|
|
|
7650
7708
|
var init_identity = __esm({
|
|
7651
7709
|
"src/identity.ts"() {
|
|
7652
7710
|
"use strict";
|
|
7653
|
-
ROOT =
|
|
7654
|
-
IDENTITY_FILE =
|
|
7711
|
+
ROOT = join3(homedir2(), ".modelstat");
|
|
7712
|
+
IDENTITY_FILE = join3(ROOT, "identity.json");
|
|
7655
7713
|
}
|
|
7656
7714
|
});
|
|
7657
7715
|
|
|
@@ -21152,7 +21210,7 @@ var require_snapshot_recorder = __commonJS({
|
|
|
21152
21210
|
"../../node_modules/.pnpm/undici@7.25.0/node_modules/undici/lib/mock/snapshot-recorder.js"(exports, module) {
|
|
21153
21211
|
"use strict";
|
|
21154
21212
|
var { writeFile, readFile, mkdir: mkdir2 } = __require("fs/promises");
|
|
21155
|
-
var { dirname:
|
|
21213
|
+
var { dirname: dirname9, resolve: resolve6 } = __require("path");
|
|
21156
21214
|
var { setTimeout: setTimeout2, clearTimeout: clearTimeout2 } = __require("timers");
|
|
21157
21215
|
var { InvalidArgumentError, UndiciError } = require_errors();
|
|
21158
21216
|
var { hashId, isUrlExcludedFactory, normalizeHeaders, createHeaderFilters } = require_snapshot_utils();
|
|
@@ -21383,7 +21441,7 @@ var require_snapshot_recorder = __commonJS({
|
|
|
21383
21441
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
21384
21442
|
}
|
|
21385
21443
|
const resolvedPath = resolve6(path5);
|
|
21386
|
-
await mkdir2(
|
|
21444
|
+
await mkdir2(dirname9(resolvedPath), { recursive: true });
|
|
21387
21445
|
const data = Array.from(this.#snapshots.entries()).map(([hash, snapshot]) => ({
|
|
21388
21446
|
hash,
|
|
21389
21447
|
snapshot
|
|
@@ -43937,9 +43995,9 @@ var init_source = __esm({
|
|
|
43937
43995
|
});
|
|
43938
43996
|
|
|
43939
43997
|
// src/config.ts
|
|
43940
|
-
import { existsSync as
|
|
43998
|
+
import { existsSync as existsSync5 } from "fs";
|
|
43941
43999
|
import { hostname } from "os";
|
|
43942
|
-
import { dirname as
|
|
44000
|
+
import { dirname as dirname3, resolve as resolve3 } from "path";
|
|
43943
44001
|
import { fileURLToPath } from "url";
|
|
43944
44002
|
function migrateFromConf() {
|
|
43945
44003
|
const bearer = store.get("bearerToken");
|
|
@@ -43979,10 +44037,10 @@ var init_config2 = __esm({
|
|
|
43979
44037
|
import_dotenv = __toESM(require_main(), 1);
|
|
43980
44038
|
init_source();
|
|
43981
44039
|
init_identity();
|
|
43982
|
-
here =
|
|
44040
|
+
here = dirname3(fileURLToPath(import.meta.url));
|
|
43983
44041
|
for (let d = here, i = 0; i < 8; i++, d = resolve3(d, "..")) {
|
|
43984
44042
|
const candidate = resolve3(d, ".env");
|
|
43985
|
-
if (
|
|
44043
|
+
if (existsSync5(candidate)) {
|
|
43986
44044
|
(0, import_dotenv.config)({ path: candidate });
|
|
43987
44045
|
break;
|
|
43988
44046
|
}
|
|
@@ -44387,6 +44445,89 @@ var init_cognition = __esm({
|
|
|
44387
44445
|
}
|
|
44388
44446
|
});
|
|
44389
44447
|
|
|
44448
|
+
// ../../packages/companion-core/src/pipeline/title.ts
|
|
44449
|
+
function buildTitleUserPrompt(input) {
|
|
44450
|
+
const lines = input.abstracts.map(
|
|
44451
|
+
(a, i) => ` [part ${i + 1}] ${a.replace(/\s+/g, " ").trim().slice(0, TITLER_ABSTRACT_SLICE_CHARS)}`
|
|
44452
|
+
).join("\n");
|
|
44453
|
+
const facts = input.facts?.trim();
|
|
44454
|
+
return `${facts ? `Session context: ${facts}.
|
|
44455
|
+
|
|
44456
|
+
` : ""}Summaries of the session's parts (chronological):
|
|
44457
|
+
${lines}
|
|
44458
|
+
|
|
44459
|
+
Write the title.`;
|
|
44460
|
+
}
|
|
44461
|
+
function stripCognitionSuffix(abstract) {
|
|
44462
|
+
return abstract.replace(/\s*\[(?:Mood|Mind):[^\]]*\]/g, "").trim();
|
|
44463
|
+
}
|
|
44464
|
+
function sanitiseTitle(raw) {
|
|
44465
|
+
if (!raw) return "";
|
|
44466
|
+
const firstLine = raw.replace(/```[a-z]*\n?/gi, "").split(/[\n\r]/).map((l) => l.trim()).find((l) => l.length > 0) ?? "";
|
|
44467
|
+
let t = firstLine.replace(/\s+/g, " ").replace(/^["'`“”]+/, "").replace(/["'`“”]+$/, "").replace(/[.!]+$/, "").trim();
|
|
44468
|
+
if (!t) return "";
|
|
44469
|
+
t = redact(t).text;
|
|
44470
|
+
return t.slice(0, TITLE_MAX_CHARS).trim();
|
|
44471
|
+
}
|
|
44472
|
+
function fallbackTitle(abstracts) {
|
|
44473
|
+
const first = abstracts.find((a) => a.trim().length > 0);
|
|
44474
|
+
if (!first) return "";
|
|
44475
|
+
const sentence = first.split(/(?<=[.!?])\s/, 1)[0] ?? first;
|
|
44476
|
+
return sanitiseTitle(sentence);
|
|
44477
|
+
}
|
|
44478
|
+
function sampleAbstracts(abstracts, max = TITLER_MAX_ABSTRACTS) {
|
|
44479
|
+
if (abstracts.length <= max) return abstracts;
|
|
44480
|
+
const picks = /* @__PURE__ */ new Set([0, abstracts.length - 1]);
|
|
44481
|
+
for (let i = 1; picks.size < max; i++) {
|
|
44482
|
+
picks.add(Math.round(i * (abstracts.length - 1) / (max - 1)));
|
|
44483
|
+
}
|
|
44484
|
+
return [...picks].sort((a, b) => a - b).map((i) => abstracts[i]);
|
|
44485
|
+
}
|
|
44486
|
+
async function buildSessionTitles(segments, entitle) {
|
|
44487
|
+
const bySession = /* @__PURE__ */ new Map();
|
|
44488
|
+
for (const s of segments) {
|
|
44489
|
+
const arr = bySession.get(s.session_id) ?? [];
|
|
44490
|
+
arr.push(s);
|
|
44491
|
+
bySession.set(s.session_id, arr);
|
|
44492
|
+
}
|
|
44493
|
+
const out = {};
|
|
44494
|
+
for (const [sessionId, segs] of bySession) {
|
|
44495
|
+
const sorted = [...segs].sort((a, b) => a.started_at.localeCompare(b.started_at));
|
|
44496
|
+
const abstracts = sorted.map((s) => stripCognitionSuffix(s.abstract)).filter((a) => a.length > 0);
|
|
44497
|
+
if (abstracts.length === 0) continue;
|
|
44498
|
+
let title = "";
|
|
44499
|
+
if (entitle) {
|
|
44500
|
+
const first = sorted[0];
|
|
44501
|
+
const project = first.tags.find((t) => t.root_key === "projects")?.name;
|
|
44502
|
+
const facts = [
|
|
44503
|
+
project ? `repo ${project}` : null,
|
|
44504
|
+
`${sorted.length} part${sorted.length === 1 ? "" : "s"} on ${first.tool}`
|
|
44505
|
+
].filter(Boolean).join("; ");
|
|
44506
|
+
try {
|
|
44507
|
+
title = sanitiseTitle(await entitle({ abstracts: sampleAbstracts(abstracts), facts }));
|
|
44508
|
+
} catch {
|
|
44509
|
+
title = "";
|
|
44510
|
+
}
|
|
44511
|
+
}
|
|
44512
|
+
if (!title) title = fallbackTitle(abstracts);
|
|
44513
|
+
if (title) out[sessionId] = title;
|
|
44514
|
+
}
|
|
44515
|
+
return out;
|
|
44516
|
+
}
|
|
44517
|
+
var TITLER_SYSTEM_PROMPT, TITLE_MAX_CHARS, TITLER_MAX_TOKENS, TITLER_TEMPERATURE, TITLER_MAX_ABSTRACTS, TITLER_ABSTRACT_SLICE_CHARS;
|
|
44518
|
+
var init_title = __esm({
|
|
44519
|
+
"../../packages/companion-core/src/pipeline/title.ts"() {
|
|
44520
|
+
"use strict";
|
|
44521
|
+
init_redact();
|
|
44522
|
+
TITLER_SYSTEM_PROMPT = "You write a short TITLE for an AI coding session, given one-sentence summaries of its parts in chronological order. The title names what the session was about at a high level, in 3-8 words. If the session clearly spans more than one theme, name the top themes (at most 3) separated by ' \xB7 '. Use concrete domain keywords (features, components, subsystems). No narration, no filler words like 'session' or 'work on', no quotes, no trailing period, no PII, no code literals, no file paths. Reply with only the title.";
|
|
44523
|
+
TITLE_MAX_CHARS = 80;
|
|
44524
|
+
TITLER_MAX_TOKENS = 60;
|
|
44525
|
+
TITLER_TEMPERATURE = 0.2;
|
|
44526
|
+
TITLER_MAX_ABSTRACTS = 10;
|
|
44527
|
+
TITLER_ABSTRACT_SLICE_CHARS = 240;
|
|
44528
|
+
}
|
|
44529
|
+
});
|
|
44530
|
+
|
|
44390
44531
|
// ../../packages/companion-core/src/pipeline/index.ts
|
|
44391
44532
|
async function buildSegmentsForSession(events, adapters2, onProgress) {
|
|
44392
44533
|
if (events.length === 0) return [];
|
|
@@ -44682,6 +44823,7 @@ var init_pipeline = __esm({
|
|
|
44682
44823
|
init_redact();
|
|
44683
44824
|
init_prompts();
|
|
44684
44825
|
init_cognition();
|
|
44826
|
+
init_title();
|
|
44685
44827
|
SEGMENT_TIME_GAP_MS = 15 * 6e4;
|
|
44686
44828
|
SEGMENT_TOPIC_THRESHOLD = 0.35;
|
|
44687
44829
|
SEGMENT_MAX_TURNS = 100;
|
|
@@ -44707,7 +44849,7 @@ var init_src3 = __esm({
|
|
|
44707
44849
|
|
|
44708
44850
|
// ../../packages/companion-core/src/node/file-queue-store.ts
|
|
44709
44851
|
import { promises as fs3 } from "fs";
|
|
44710
|
-
import { dirname as
|
|
44852
|
+
import { dirname as dirname4 } from "path";
|
|
44711
44853
|
var SENT_TTL_MS, FileQueueStore;
|
|
44712
44854
|
var init_file_queue_store = __esm({
|
|
44713
44855
|
"../../packages/companion-core/src/node/file-queue-store.ts"() {
|
|
@@ -44763,7 +44905,7 @@ var init_file_queue_store = __esm({
|
|
|
44763
44905
|
items: Object.fromEntries(this.items.entries())
|
|
44764
44906
|
};
|
|
44765
44907
|
const tmp = `${this.filePath}.tmp`;
|
|
44766
|
-
await fs3.mkdir(
|
|
44908
|
+
await fs3.mkdir(dirname4(this.filePath), { recursive: true });
|
|
44767
44909
|
await fs3.writeFile(tmp, JSON.stringify(snap), "utf8");
|
|
44768
44910
|
try {
|
|
44769
44911
|
await fs3.rename(this.filePath, `${this.filePath}.bak`);
|
|
@@ -44940,14 +45082,14 @@ var init_ollama = __esm({
|
|
|
44940
45082
|
|
|
44941
45083
|
// ../../packages/companion-core/src/node/llama.ts
|
|
44942
45084
|
import { mkdir } from "fs/promises";
|
|
44943
|
-
import { existsSync as
|
|
45085
|
+
import { existsSync as existsSync6 } from "fs";
|
|
44944
45086
|
import { homedir as homedir4 } from "os";
|
|
44945
|
-
import { dirname as
|
|
45087
|
+
import { dirname as dirname5, join as join4 } from "path";
|
|
44946
45088
|
function defaultLlamaConfig() {
|
|
44947
45089
|
const env2 = globalThis.process?.env ?? {};
|
|
44948
|
-
const modelsDir = env2.MODELSTAT_MODELS_DIR ??
|
|
45090
|
+
const modelsDir = env2.MODELSTAT_MODELS_DIR ?? join4(homedir4(), ".modelstat", "models");
|
|
44949
45091
|
const modelUrl = env2.MODELSTAT_LLAMA_MODEL_URL ?? DEFAULT_LLAMA_MODEL_URL;
|
|
44950
|
-
const modelPath = env2.MODELSTAT_LLAMA_MODEL_PATH ??
|
|
45092
|
+
const modelPath = env2.MODELSTAT_LLAMA_MODEL_PATH ?? join4(modelsDir, basenameFromUrl(modelUrl));
|
|
44951
45093
|
return {
|
|
44952
45094
|
modelPath,
|
|
44953
45095
|
modelUrl,
|
|
@@ -44968,8 +45110,8 @@ function basenameFromUrl(url) {
|
|
|
44968
45110
|
return parts[parts.length - 1] || "model.gguf";
|
|
44969
45111
|
}
|
|
44970
45112
|
async function ensureLlamaModel(cfg = defaultLlamaConfig()) {
|
|
44971
|
-
if (
|
|
44972
|
-
await mkdir(
|
|
45113
|
+
if (existsSync6(cfg.modelPath)) return cfg.modelPath;
|
|
45114
|
+
await mkdir(dirname5(cfg.modelPath), { recursive: true });
|
|
44973
45115
|
const res = await fetch(cfg.modelUrl);
|
|
44974
45116
|
if (!res.ok || !res.body) {
|
|
44975
45117
|
throw new Error(
|
|
@@ -45050,6 +45192,9 @@ async function loadOnce(cfg) {
|
|
|
45050
45192
|
const cognizerContext = await model.createContext({
|
|
45051
45193
|
contextSize: Math.min(cfg.contextSize, 2048)
|
|
45052
45194
|
});
|
|
45195
|
+
const entitlerContext = await model.createContext({
|
|
45196
|
+
contextSize: cfg.contextSize
|
|
45197
|
+
});
|
|
45053
45198
|
const summarizer = new llamaMod.LlamaChatSession({
|
|
45054
45199
|
contextSequence: summariserContext.getSequence(),
|
|
45055
45200
|
systemPrompt: SUMMARISER_SYSTEM_PROMPT
|
|
@@ -45058,7 +45203,11 @@ async function loadOnce(cfg) {
|
|
|
45058
45203
|
contextSequence: cognizerContext.getSequence(),
|
|
45059
45204
|
systemPrompt: COGNITION_SYSTEM_PROMPT
|
|
45060
45205
|
});
|
|
45061
|
-
|
|
45206
|
+
const entitler = new llamaMod.LlamaChatSession({
|
|
45207
|
+
contextSequence: entitlerContext.getSequence(),
|
|
45208
|
+
systemPrompt: TITLER_SYSTEM_PROMPT
|
|
45209
|
+
});
|
|
45210
|
+
loaded = { summarizer, cognizer, entitler };
|
|
45062
45211
|
return loaded;
|
|
45063
45212
|
})();
|
|
45064
45213
|
try {
|
|
@@ -45120,12 +45269,41 @@ function llamaCognize(cfg = defaultLlamaConfig()) {
|
|
|
45120
45269
|
}
|
|
45121
45270
|
};
|
|
45122
45271
|
}
|
|
45272
|
+
function llamaEntitle(cfg = defaultLlamaConfig()) {
|
|
45273
|
+
return async (input) => {
|
|
45274
|
+
if (input.abstracts.length === 0) return null;
|
|
45275
|
+
let loadedSessions;
|
|
45276
|
+
try {
|
|
45277
|
+
loadedSessions = await loadOnce(cfg);
|
|
45278
|
+
} catch {
|
|
45279
|
+
return null;
|
|
45280
|
+
}
|
|
45281
|
+
const { entitler } = loadedSessions;
|
|
45282
|
+
const run = inflight.then(async () => {
|
|
45283
|
+
entitler.resetChatHistory();
|
|
45284
|
+
const raw = await entitler.prompt(buildTitleUserPrompt(input), {
|
|
45285
|
+
temperature: TITLER_TEMPERATURE,
|
|
45286
|
+
// Same thinking-budget rationale as the cognition pass: the
|
|
45287
|
+
// answer is tiny but Qwen3.5 reasons first.
|
|
45288
|
+
maxTokens: TITLER_MAX_TOKENS + 400
|
|
45289
|
+
});
|
|
45290
|
+
return stripThinking(raw ?? "") || null;
|
|
45291
|
+
});
|
|
45292
|
+
inflight = run.catch(() => void 0);
|
|
45293
|
+
try {
|
|
45294
|
+
return await run;
|
|
45295
|
+
} catch {
|
|
45296
|
+
return null;
|
|
45297
|
+
}
|
|
45298
|
+
};
|
|
45299
|
+
}
|
|
45123
45300
|
var DEFAULT_LLAMA_MODEL_URL, LLAMA_MAX_TOKENS, loaded, loadPromise, inflight;
|
|
45124
45301
|
var init_llama = __esm({
|
|
45125
45302
|
"../../packages/companion-core/src/node/llama.ts"() {
|
|
45126
45303
|
"use strict";
|
|
45127
45304
|
init_prompts();
|
|
45128
45305
|
init_cognition();
|
|
45306
|
+
init_title();
|
|
45129
45307
|
DEFAULT_LLAMA_MODEL_URL = "https://huggingface.co/lmstudio-community/Qwen3.5-4B-GGUF/resolve/main/Qwen3.5-4B-Q4_K_M.gguf";
|
|
45130
45308
|
LLAMA_MAX_TOKENS = 1024;
|
|
45131
45309
|
loaded = null;
|
|
@@ -45205,6 +45383,7 @@ __export(node_exports, {
|
|
|
45205
45383
|
defaultOllamaConfig: () => defaultOllamaConfig,
|
|
45206
45384
|
ensureLlamaModel: () => ensureLlamaModel,
|
|
45207
45385
|
llamaCognize: () => llamaCognize,
|
|
45386
|
+
llamaEntitle: () => llamaEntitle,
|
|
45208
45387
|
llamaSummarize: () => llamaSummarize,
|
|
45209
45388
|
ollamaCognize: () => ollamaCognize,
|
|
45210
45389
|
ollamaEmbed: () => ollamaEmbed,
|
|
@@ -45322,6 +45501,7 @@ var init_privacy_filter = __esm({
|
|
|
45322
45501
|
var pipeline_exports = {};
|
|
45323
45502
|
__export(pipeline_exports, {
|
|
45324
45503
|
buildSegments: () => buildSegments,
|
|
45504
|
+
buildSessionTitles: () => buildSessionTitles2,
|
|
45325
45505
|
preflightSummariser: () => preflightSummariser
|
|
45326
45506
|
});
|
|
45327
45507
|
async function bundledAdapters() {
|
|
@@ -45337,6 +45517,11 @@ async function bundledAdapters() {
|
|
|
45337
45517
|
summarize: llamaSummarize(llamaCfg),
|
|
45338
45518
|
tokenize: (text) => Math.max(1, Math.ceil(text.length / 4)),
|
|
45339
45519
|
cognize: llamaCognize(llamaCfg),
|
|
45520
|
+
// Session-title pass — same bundled model, third chat session with
|
|
45521
|
+
// TITLER_SYSTEM_PROMPT. One short call per session per upload (the
|
|
45522
|
+
// sessions-list title in the dashboard). Best-effort like cognize:
|
|
45523
|
+
// failures fall back to a deterministic title in buildSessionTitles.
|
|
45524
|
+
entitle: llamaEntitle(llamaCfg),
|
|
45340
45525
|
// Model-based PII redactor (OpenAI Privacy Filter via
|
|
45341
45526
|
// transformers.js / ONNX). Runs locally on CPU after the regex
|
|
45342
45527
|
// pass in packages/core/redact.ts. ~1 GB model downloaded on
|
|
@@ -45366,6 +45551,10 @@ async function getAdapters() {
|
|
|
45366
45551
|
async function buildSegments(events, onProgress) {
|
|
45367
45552
|
return buildSegmentsForSession(events, await getAdapters(), onProgress);
|
|
45368
45553
|
}
|
|
45554
|
+
async function buildSessionTitles2(segments) {
|
|
45555
|
+
const a = await getAdapters();
|
|
45556
|
+
return buildSessionTitles(segments, a.entitle);
|
|
45557
|
+
}
|
|
45369
45558
|
async function preflightSummariser() {
|
|
45370
45559
|
const a = await getAdapters();
|
|
45371
45560
|
const out = await a.summarize({
|
|
@@ -45393,7 +45582,7 @@ var init_pipeline2 = __esm({
|
|
|
45393
45582
|
// src/scan.ts
|
|
45394
45583
|
import { readdir, stat as stat2 } from "fs/promises";
|
|
45395
45584
|
import { homedir as homedir5 } from "os";
|
|
45396
|
-
import { join as
|
|
45585
|
+
import { join as join5 } from "path";
|
|
45397
45586
|
function withNonNullTokens(e) {
|
|
45398
45587
|
return e.tokens ? e : { ...e, tokens: { ...ZERO_TOKENS } };
|
|
45399
45588
|
}
|
|
@@ -45402,16 +45591,16 @@ async function scanAll(cb = {}) {
|
|
|
45402
45591
|
if (!deviceId) throw new Error("agent not enrolled \u2014 run `register` first");
|
|
45403
45592
|
const jobs = [];
|
|
45404
45593
|
try {
|
|
45405
|
-
const base =
|
|
45594
|
+
const base = join5(homedir5(), ".claude/projects");
|
|
45406
45595
|
const projects = await readdir(base).catch(() => []);
|
|
45407
45596
|
for (const p of projects) {
|
|
45408
|
-
const dir =
|
|
45597
|
+
const dir = join5(base, p);
|
|
45409
45598
|
const ds = await stat2(dir).catch(() => null);
|
|
45410
45599
|
if (!ds?.isDirectory()) continue;
|
|
45411
45600
|
const files = await readdir(dir);
|
|
45412
45601
|
for (const f of files) {
|
|
45413
45602
|
if (!f.endsWith(".jsonl")) continue;
|
|
45414
|
-
const full =
|
|
45603
|
+
const full = join5(dir, f);
|
|
45415
45604
|
jobs.push({
|
|
45416
45605
|
path: full,
|
|
45417
45606
|
parse: async () => {
|
|
@@ -45425,17 +45614,17 @@ async function scanAll(cb = {}) {
|
|
|
45425
45614
|
console.warn("claude scan skipped:", e.message);
|
|
45426
45615
|
}
|
|
45427
45616
|
try {
|
|
45428
|
-
const base =
|
|
45617
|
+
const base = join5(homedir5(), ".codex/sessions");
|
|
45429
45618
|
const years = await readdir(base).catch(() => []);
|
|
45430
45619
|
for (const y of years) {
|
|
45431
|
-
const months = await readdir(
|
|
45620
|
+
const months = await readdir(join5(base, y)).catch(() => []);
|
|
45432
45621
|
for (const m of months) {
|
|
45433
|
-
const days = await readdir(
|
|
45622
|
+
const days = await readdir(join5(base, y, m)).catch(() => []);
|
|
45434
45623
|
for (const d of days) {
|
|
45435
|
-
const files = await readdir(
|
|
45624
|
+
const files = await readdir(join5(base, y, m, d)).catch(() => []);
|
|
45436
45625
|
for (const f of files) {
|
|
45437
45626
|
if (!f.startsWith("rollout-") || !f.endsWith(".jsonl")) continue;
|
|
45438
|
-
const full =
|
|
45627
|
+
const full = join5(base, y, m, d, f);
|
|
45439
45628
|
jobs.push({
|
|
45440
45629
|
path: full,
|
|
45441
45630
|
parse: async () => {
|
|
@@ -45457,16 +45646,33 @@ async function scanAll(cb = {}) {
|
|
|
45457
45646
|
let segmentsUploaded = 0;
|
|
45458
45647
|
let buffer = [];
|
|
45459
45648
|
let pendingCursors = [];
|
|
45649
|
+
const runSegmentsBySession = /* @__PURE__ */ new Map();
|
|
45460
45650
|
async function flushBatch() {
|
|
45461
45651
|
if (!buffer.length) return;
|
|
45462
45652
|
const events = buffer.map(withNonNullTokens);
|
|
45463
45653
|
const segments = await buildSegments(events, cb.onProgress);
|
|
45654
|
+
for (const seg of segments) {
|
|
45655
|
+
const arr = runSegmentsBySession.get(seg.session_id) ?? [];
|
|
45656
|
+
arr.push(seg);
|
|
45657
|
+
runSegmentsBySession.set(seg.session_id, arr);
|
|
45658
|
+
}
|
|
45659
|
+
const titleInput = [];
|
|
45660
|
+
for (const sessionId of new Set(segments.map((s) => s.session_id))) {
|
|
45661
|
+
titleInput.push(...runSegmentsBySession.get(sessionId) ?? []);
|
|
45662
|
+
}
|
|
45663
|
+
let sessionTitles = {};
|
|
45664
|
+
try {
|
|
45665
|
+
sessionTitles = await buildSessionTitles2(titleInput);
|
|
45666
|
+
} catch (e) {
|
|
45667
|
+
console.warn("session titling failed \u2014 shipping batch untitled:", e.message);
|
|
45668
|
+
}
|
|
45464
45669
|
const batch = {
|
|
45465
45670
|
batch_id: batchId(),
|
|
45466
45671
|
device_id: deviceId,
|
|
45467
45672
|
agent_version: AGENT_VERSION,
|
|
45468
45673
|
events,
|
|
45469
|
-
segments
|
|
45674
|
+
segments,
|
|
45675
|
+
...Object.keys(sessionTitles).length ? { session_titles: sessionTitles } : {}
|
|
45470
45676
|
};
|
|
45471
45677
|
cb.onUpload?.({ events: events.length, segments: segments.length });
|
|
45472
45678
|
const res = await uploadBatch(batch);
|
|
@@ -45513,7 +45719,7 @@ var init_scan = __esm({
|
|
|
45513
45719
|
init_pipeline2();
|
|
45514
45720
|
init_config2();
|
|
45515
45721
|
init_api();
|
|
45516
|
-
AGENT_VERSION = true ? "agent-0.0.
|
|
45722
|
+
AGENT_VERSION = true ? "agent-0.0.44" : "agent-dev";
|
|
45517
45723
|
BATCH_MAX_EVENTS = 2e3;
|
|
45518
45724
|
ZERO_TOKENS = {
|
|
45519
45725
|
input: 0,
|
|
@@ -45528,7 +45734,7 @@ var init_scan = __esm({
|
|
|
45528
45734
|
// src/lock.ts
|
|
45529
45735
|
import {
|
|
45530
45736
|
closeSync,
|
|
45531
|
-
existsSync as
|
|
45737
|
+
existsSync as existsSync8,
|
|
45532
45738
|
mkdirSync as mkdirSync3,
|
|
45533
45739
|
openSync,
|
|
45534
45740
|
readFileSync as readFileSync4,
|
|
@@ -45538,7 +45744,7 @@ import {
|
|
|
45538
45744
|
writeSync
|
|
45539
45745
|
} from "fs";
|
|
45540
45746
|
import { homedir as homedir7 } from "os";
|
|
45541
|
-
import { join as
|
|
45747
|
+
import { join as join7 } from "path";
|
|
45542
45748
|
function isProcessAlive(pid) {
|
|
45543
45749
|
if (!pid || pid <= 0) return false;
|
|
45544
45750
|
try {
|
|
@@ -45639,8 +45845,8 @@ var LOCK_DIR, LOCK_FILE;
|
|
|
45639
45845
|
var init_lock = __esm({
|
|
45640
45846
|
"src/lock.ts"() {
|
|
45641
45847
|
"use strict";
|
|
45642
|
-
LOCK_DIR =
|
|
45643
|
-
LOCK_FILE =
|
|
45848
|
+
LOCK_DIR = join7(homedir7(), ".modelstat");
|
|
45849
|
+
LOCK_FILE = join7(LOCK_DIR, "daemon.lock");
|
|
45644
45850
|
}
|
|
45645
45851
|
});
|
|
45646
45852
|
|
|
@@ -45704,7 +45910,7 @@ var PROCESSING_VERSION;
|
|
|
45704
45910
|
var init_processing_version = __esm({
|
|
45705
45911
|
"src/processing-version.ts"() {
|
|
45706
45912
|
"use strict";
|
|
45707
|
-
PROCESSING_VERSION =
|
|
45913
|
+
PROCESSING_VERSION = 4;
|
|
45708
45914
|
}
|
|
45709
45915
|
});
|
|
45710
45916
|
|
|
@@ -46441,9 +46647,9 @@ var init_handler = __esm({
|
|
|
46441
46647
|
if (this.fsw.closed) {
|
|
46442
46648
|
return;
|
|
46443
46649
|
}
|
|
46444
|
-
const
|
|
46650
|
+
const dirname9 = sysPath.dirname(file);
|
|
46445
46651
|
const basename4 = sysPath.basename(file);
|
|
46446
|
-
const parent = this.fsw._getWatchedDir(
|
|
46652
|
+
const parent = this.fsw._getWatchedDir(dirname9);
|
|
46447
46653
|
let prevStats = stats;
|
|
46448
46654
|
if (parent.has(basename4))
|
|
46449
46655
|
return;
|
|
@@ -46470,7 +46676,7 @@ var init_handler = __esm({
|
|
|
46470
46676
|
prevStats = newStats2;
|
|
46471
46677
|
}
|
|
46472
46678
|
} catch (error) {
|
|
46473
|
-
this.fsw._remove(
|
|
46679
|
+
this.fsw._remove(dirname9, basename4);
|
|
46474
46680
|
}
|
|
46475
46681
|
} else if (parent.has(basename4)) {
|
|
46476
46682
|
const at = newStats.atimeMs;
|
|
@@ -47436,7 +47642,7 @@ __export(daemon_exports, {
|
|
|
47436
47642
|
setQueue: () => setQueue,
|
|
47437
47643
|
setStat: () => setStat
|
|
47438
47644
|
});
|
|
47439
|
-
import { existsSync as
|
|
47645
|
+
import { existsSync as existsSync9, statSync as statSync2 } from "fs";
|
|
47440
47646
|
function setPhase(phase, message) {
|
|
47441
47647
|
status.phase = phase;
|
|
47442
47648
|
status.message = message ?? null;
|
|
@@ -47516,15 +47722,15 @@ async function sendHeartbeat() {
|
|
|
47516
47722
|
}
|
|
47517
47723
|
async function writeLocalStatus(snapshot) {
|
|
47518
47724
|
const { homedir: homedir9 } = await import("os");
|
|
47519
|
-
const { join:
|
|
47725
|
+
const { join: join11 } = await import("path");
|
|
47520
47726
|
const { writeFile, mkdir: mkdir2, rename } = await import("fs/promises");
|
|
47521
47727
|
if (!lastStatusPath) {
|
|
47522
|
-
const dir =
|
|
47728
|
+
const dir = join11(homedir9(), ".modelstat");
|
|
47523
47729
|
try {
|
|
47524
47730
|
await mkdir2(dir, { recursive: true });
|
|
47525
47731
|
} catch {
|
|
47526
47732
|
}
|
|
47527
|
-
lastStatusPath =
|
|
47733
|
+
lastStatusPath = join11(dir, "last-status.json");
|
|
47528
47734
|
}
|
|
47529
47735
|
const tmp = `${lastStatusPath}.tmp`;
|
|
47530
47736
|
try {
|
|
@@ -47647,20 +47853,20 @@ async function runDaemon(opts = {}) {
|
|
|
47647
47853
|
await requestScan("startup");
|
|
47648
47854
|
const chokidar = (await Promise.resolve().then(() => (init_esm2(), esm_exports))).default;
|
|
47649
47855
|
const { homedir: homedir9, platform: platform5 } = await import("os");
|
|
47650
|
-
const { join:
|
|
47856
|
+
const { join: join11 } = await import("path");
|
|
47651
47857
|
const home2 = homedir9();
|
|
47652
47858
|
const dirs = [
|
|
47653
|
-
|
|
47654
|
-
|
|
47655
|
-
|
|
47656
|
-
|
|
47859
|
+
join11(home2, ".claude/projects"),
|
|
47860
|
+
join11(home2, ".codex/sessions"),
|
|
47861
|
+
join11(home2, ".cursor/ai-tracking"),
|
|
47862
|
+
join11(home2, ".gemini"),
|
|
47657
47863
|
...platform5() === "darwin" ? [
|
|
47658
|
-
|
|
47659
|
-
|
|
47864
|
+
join11(home2, "Library/Application Support/Cursor/User/workspaceStorage"),
|
|
47865
|
+
join11(home2, "Library/Application Support/Claude")
|
|
47660
47866
|
] : [
|
|
47661
|
-
|
|
47867
|
+
join11(home2, ".config/Cursor/User/workspaceStorage")
|
|
47662
47868
|
]
|
|
47663
|
-
].filter((p) =>
|
|
47869
|
+
].filter((p) => existsSync9(p) && statSync2(p).isDirectory());
|
|
47664
47870
|
setPhase("watching", `Watching ${dirs.length} directories`);
|
|
47665
47871
|
const watcher = chokidar.watch(dirs, {
|
|
47666
47872
|
persistent: true,
|
|
@@ -47713,7 +47919,7 @@ var init_daemon = __esm({
|
|
|
47713
47919
|
init_lock();
|
|
47714
47920
|
init_scan();
|
|
47715
47921
|
init_single_flight();
|
|
47716
|
-
AGENT_VERSION2 = true ? "agent-0.0.
|
|
47922
|
+
AGENT_VERSION2 = true ? "agent-0.0.44" : "agent-dev";
|
|
47717
47923
|
HEARTBEAT_INTERVAL_MS = 1e4;
|
|
47718
47924
|
SCAN_INTERVAL_MS = 5 * 60 * 1e3;
|
|
47719
47925
|
DISCOVERY_INTERVAL_MS = 6e4;
|
|
@@ -47739,37 +47945,37 @@ var watch_exports = {};
|
|
|
47739
47945
|
__export(watch_exports, {
|
|
47740
47946
|
watchForever: () => watchForever
|
|
47741
47947
|
});
|
|
47742
|
-
import { existsSync as
|
|
47948
|
+
import { existsSync as existsSync10 } from "fs";
|
|
47743
47949
|
import { homedir as homedir8, platform as platform3 } from "os";
|
|
47744
|
-
import { join as
|
|
47950
|
+
import { join as join10 } from "path";
|
|
47745
47951
|
function resolveWatchDirs() {
|
|
47746
47952
|
const home2 = homedir8();
|
|
47747
|
-
const xdgConfig = process.env.XDG_CONFIG_HOME ??
|
|
47748
|
-
const xdgData = process.env.XDG_DATA_HOME ??
|
|
47953
|
+
const xdgConfig = process.env.XDG_CONFIG_HOME ?? join10(home2, ".config");
|
|
47954
|
+
const xdgData = process.env.XDG_DATA_HOME ?? join10(home2, ".local/share");
|
|
47749
47955
|
const candidates = [
|
|
47750
47956
|
// universal (default HOME-rooted CLI data dirs)
|
|
47751
|
-
|
|
47752
|
-
|
|
47753
|
-
|
|
47754
|
-
|
|
47755
|
-
|
|
47957
|
+
join10(home2, ".claude/projects"),
|
|
47958
|
+
join10(home2, ".codex/sessions"),
|
|
47959
|
+
join10(home2, ".cursor/ai-tracking"),
|
|
47960
|
+
join10(home2, ".gemini"),
|
|
47961
|
+
join10(home2, ".aider"),
|
|
47756
47962
|
// XDG / Linux
|
|
47757
|
-
|
|
47758
|
-
|
|
47759
|
-
|
|
47760
|
-
|
|
47761
|
-
|
|
47762
|
-
|
|
47963
|
+
join10(xdgConfig, "claude/projects"),
|
|
47964
|
+
join10(xdgConfig, "codex/sessions"),
|
|
47965
|
+
join10(xdgConfig, "Cursor/User/workspaceStorage"),
|
|
47966
|
+
join10(xdgConfig, "Code/User/workspaceStorage"),
|
|
47967
|
+
join10(xdgConfig, "Code - Insiders/User/workspaceStorage"),
|
|
47968
|
+
join10(xdgData, "claude/projects"),
|
|
47763
47969
|
// macOS
|
|
47764
47970
|
...platform3() === "darwin" ? [
|
|
47765
|
-
|
|
47766
|
-
|
|
47767
|
-
|
|
47768
|
-
|
|
47769
|
-
|
|
47971
|
+
join10(home2, "Library/Application Support/Cursor/User/workspaceStorage"),
|
|
47972
|
+
join10(home2, "Library/Application Support/Claude"),
|
|
47973
|
+
join10(home2, "Library/Application Support/Code/User/workspaceStorage"),
|
|
47974
|
+
join10(home2, "Library/Application Support/Windsurf/User/workspaceStorage"),
|
|
47975
|
+
join10(home2, "Library/Application Support/Zed")
|
|
47770
47976
|
] : []
|
|
47771
47977
|
];
|
|
47772
|
-
return Array.from(new Set(candidates)).filter((p) =>
|
|
47978
|
+
return Array.from(new Set(candidates)).filter((p) => existsSync10(p));
|
|
47773
47979
|
}
|
|
47774
47980
|
async function safeScan(reason) {
|
|
47775
47981
|
if (scanning) {
|
|
@@ -47844,7 +48050,7 @@ import { createInterface as createInterface3 } from "readline";
|
|
|
47844
48050
|
import { spawnSync } from "child_process";
|
|
47845
48051
|
import {
|
|
47846
48052
|
copyFileSync,
|
|
47847
|
-
existsSync as
|
|
48053
|
+
existsSync as existsSync7,
|
|
47848
48054
|
mkdirSync as mkdirSync2,
|
|
47849
48055
|
readFileSync as readFileSync3,
|
|
47850
48056
|
realpathSync,
|
|
@@ -47853,7 +48059,7 @@ import {
|
|
|
47853
48059
|
} from "fs";
|
|
47854
48060
|
import { createRequire } from "module";
|
|
47855
48061
|
import { homedir as homedir6, platform as platform2, userInfo } from "os";
|
|
47856
|
-
import { dirname as
|
|
48062
|
+
import { dirname as dirname6, join as join6 } from "path";
|
|
47857
48063
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
47858
48064
|
var SERVICE_LABEL = "ai.modelstat.agent";
|
|
47859
48065
|
var SYSTEMD_UNIT = "modelstat";
|
|
@@ -47861,16 +48067,16 @@ function home() {
|
|
|
47861
48067
|
return homedir6();
|
|
47862
48068
|
}
|
|
47863
48069
|
function stateDir() {
|
|
47864
|
-
return
|
|
48070
|
+
return join6(home(), ".modelstat");
|
|
47865
48071
|
}
|
|
47866
48072
|
function binDir() {
|
|
47867
|
-
return
|
|
48073
|
+
return join6(stateDir(), "bin");
|
|
47868
48074
|
}
|
|
47869
48075
|
function logDir() {
|
|
47870
|
-
return
|
|
48076
|
+
return join6(stateDir(), "logs");
|
|
47871
48077
|
}
|
|
47872
48078
|
function installedCliPath() {
|
|
47873
|
-
return
|
|
48079
|
+
return join6(binDir(), "modelstat.mjs");
|
|
47874
48080
|
}
|
|
47875
48081
|
function runningCliPath() {
|
|
47876
48082
|
return fileURLToPath2(import.meta.url).replace(/service\.(mjs|js|ts)$/, "cli.mjs");
|
|
@@ -47880,7 +48086,7 @@ function installBundle() {
|
|
|
47880
48086
|
mkdirSync2(logDir(), { recursive: true });
|
|
47881
48087
|
const src = runningCliPath();
|
|
47882
48088
|
const dest = installedCliPath();
|
|
47883
|
-
if (!
|
|
48089
|
+
if (!existsSync7(src)) {
|
|
47884
48090
|
throw new Error(
|
|
47885
48091
|
`Can't find the CLI bundle to install from (${src}). Are you running a local dev build?`
|
|
47886
48092
|
);
|
|
@@ -47896,14 +48102,14 @@ var NODE_LLAMA_CPP_FALLBACK_VERSION = "3.18.1";
|
|
|
47896
48102
|
function sourceLlamaVersion(sourceCli) {
|
|
47897
48103
|
try {
|
|
47898
48104
|
const req = createRequire(sourceCli);
|
|
47899
|
-
let d =
|
|
48105
|
+
let d = dirname6(realpathSync(req.resolve("node-llama-cpp")));
|
|
47900
48106
|
for (let i = 0; i < 10; i++) {
|
|
47901
|
-
const pj =
|
|
47902
|
-
if (
|
|
48107
|
+
const pj = join6(d, "package.json");
|
|
48108
|
+
if (existsSync7(pj)) {
|
|
47903
48109
|
const p = JSON.parse(readFileSync3(pj, "utf8"));
|
|
47904
48110
|
if (p.name === "node-llama-cpp" && p.version) return p.version;
|
|
47905
48111
|
}
|
|
47906
|
-
const up =
|
|
48112
|
+
const up = dirname6(d);
|
|
47907
48113
|
if (up === d) break;
|
|
47908
48114
|
d = up;
|
|
47909
48115
|
}
|
|
@@ -47917,7 +48123,7 @@ function installNativeRuntime(sourceCli) {
|
|
|
47917
48123
|
try {
|
|
47918
48124
|
const have = JSON.parse(
|
|
47919
48125
|
readFileSync3(
|
|
47920
|
-
|
|
48126
|
+
join6(dest, "node_modules", "node-llama-cpp", "package.json"),
|
|
47921
48127
|
"utf8"
|
|
47922
48128
|
)
|
|
47923
48129
|
);
|
|
@@ -47958,21 +48164,21 @@ function nodeBinary() {
|
|
|
47958
48164
|
return process.execPath;
|
|
47959
48165
|
}
|
|
47960
48166
|
function plistPath() {
|
|
47961
|
-
return
|
|
48167
|
+
return join6(home(), "Library", "LaunchAgents", `${SERVICE_LABEL}.plist`);
|
|
47962
48168
|
}
|
|
47963
48169
|
function locateTrayExecutable() {
|
|
47964
48170
|
const candidates = [
|
|
47965
|
-
|
|
48171
|
+
join6(home(), "Applications", "ModelstatTray.app", "Contents", "MacOS", "modelstat-tray"),
|
|
47966
48172
|
"/Applications/ModelstatTray.app/Contents/MacOS/modelstat-tray"
|
|
47967
48173
|
];
|
|
47968
48174
|
for (const p of candidates) {
|
|
47969
|
-
if (
|
|
48175
|
+
if (existsSync7(p)) return p;
|
|
47970
48176
|
}
|
|
47971
48177
|
return null;
|
|
47972
48178
|
}
|
|
47973
48179
|
function writePlist(cliPath) {
|
|
47974
48180
|
const p = plistPath();
|
|
47975
|
-
mkdirSync2(
|
|
48181
|
+
mkdirSync2(dirname6(p), { recursive: true });
|
|
47976
48182
|
const tray = locateTrayExecutable();
|
|
47977
48183
|
const programArgs = tray ? ` <string>${tray}</string>` : [
|
|
47978
48184
|
` <string>${nodeBinary()}</string>`,
|
|
@@ -47992,8 +48198,8 @@ ${programArgs}
|
|
|
47992
48198
|
<key>KeepAlive</key>
|
|
47993
48199
|
<dict><key>SuccessfulExit</key><false/></dict>
|
|
47994
48200
|
<key>ThrottleInterval</key><integer>30</integer>
|
|
47995
|
-
<key>StandardOutPath</key><string>${
|
|
47996
|
-
<key>StandardErrorPath</key><string>${
|
|
48201
|
+
<key>StandardOutPath</key><string>${join6(logDir(), "out.log")}</string>
|
|
48202
|
+
<key>StandardErrorPath</key><string>${join6(logDir(), "err.log")}</string>
|
|
47997
48203
|
<key>EnvironmentVariables</key>
|
|
47998
48204
|
<dict>
|
|
47999
48205
|
<key>PATH</key><string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin</string>
|
|
@@ -48038,7 +48244,7 @@ function macUninstall() {
|
|
|
48038
48244
|
const target = `gui/${uid}/${SERVICE_LABEL}`;
|
|
48039
48245
|
launchctl(["bootout", target]);
|
|
48040
48246
|
const plist = plistPath();
|
|
48041
|
-
if (
|
|
48247
|
+
if (existsSync7(plist)) {
|
|
48042
48248
|
try {
|
|
48043
48249
|
unlinkSync(plist);
|
|
48044
48250
|
} catch {
|
|
@@ -48051,12 +48257,12 @@ function macStatus() {
|
|
|
48051
48257
|
return { running: r.ok, hint: r.ok ? "launchd managed" : "not installed" };
|
|
48052
48258
|
}
|
|
48053
48259
|
function systemdUnitPath() {
|
|
48054
|
-
const xdg = process.env.XDG_CONFIG_HOME ??
|
|
48055
|
-
return
|
|
48260
|
+
const xdg = process.env.XDG_CONFIG_HOME ?? join6(home(), ".config");
|
|
48261
|
+
return join6(xdg, "systemd", "user", `${SYSTEMD_UNIT}.service`);
|
|
48056
48262
|
}
|
|
48057
48263
|
function writeSystemdUnit(cliPath) {
|
|
48058
48264
|
const unitPath = systemdUnitPath();
|
|
48059
|
-
mkdirSync2(
|
|
48265
|
+
mkdirSync2(dirname6(unitPath), { recursive: true });
|
|
48060
48266
|
const unit = `[Unit]
|
|
48061
48267
|
Description=modelstat agent
|
|
48062
48268
|
Documentation=https://modelstat.ai
|
|
@@ -48075,8 +48281,8 @@ RestartSec=10
|
|
|
48075
48281
|
# Don't restart-storm if the service is persistently unreachable.
|
|
48076
48282
|
StartLimitIntervalSec=300
|
|
48077
48283
|
StartLimitBurst=10
|
|
48078
|
-
StandardOutput=append:${
|
|
48079
|
-
StandardError=append:${
|
|
48284
|
+
StandardOutput=append:${join6(logDir(), "out.log")}
|
|
48285
|
+
StandardError=append:${join6(logDir(), "err.log")}
|
|
48080
48286
|
|
|
48081
48287
|
[Install]
|
|
48082
48288
|
WantedBy=default.target
|
|
@@ -48101,7 +48307,7 @@ function linuxInstall() {
|
|
|
48101
48307
|
function linuxUninstall() {
|
|
48102
48308
|
systemctl(["disable", "--now", `${SYSTEMD_UNIT}.service`]);
|
|
48103
48309
|
const unit = systemdUnitPath();
|
|
48104
|
-
if (
|
|
48310
|
+
if (existsSync7(unit)) {
|
|
48105
48311
|
try {
|
|
48106
48312
|
unlinkSync(unit);
|
|
48107
48313
|
} catch {
|
|
@@ -48145,9 +48351,9 @@ function logsDir() {
|
|
|
48145
48351
|
}
|
|
48146
48352
|
function installTrayApp(sourceAppPath) {
|
|
48147
48353
|
if (platform2() !== "darwin") return null;
|
|
48148
|
-
if (!
|
|
48149
|
-
const dest =
|
|
48150
|
-
mkdirSync2(
|
|
48354
|
+
if (!existsSync7(sourceAppPath)) return null;
|
|
48355
|
+
const dest = join6(home(), "Applications", "ModelstatTray.app");
|
|
48356
|
+
mkdirSync2(dirname6(dest), { recursive: true });
|
|
48151
48357
|
spawnSync("rm", ["-rf", dest]);
|
|
48152
48358
|
const r = spawnSync("cp", ["-R", sourceAppPath, dest], { encoding: "utf8" });
|
|
48153
48359
|
if (r.status !== 0) {
|
|
@@ -48157,28 +48363,28 @@ function installTrayApp(sourceAppPath) {
|
|
|
48157
48363
|
}
|
|
48158
48364
|
function bundledTrayAppPath() {
|
|
48159
48365
|
if (platform2() !== "darwin") return null;
|
|
48160
|
-
const here2 =
|
|
48366
|
+
const here2 = dirname6(fileURLToPath2(import.meta.url));
|
|
48161
48367
|
const candidates = [
|
|
48162
48368
|
// Pre-built .app — CI with codesigning drops one here.
|
|
48163
|
-
|
|
48369
|
+
join6(here2, "..", "vendor", "ModelstatTray.app"),
|
|
48164
48370
|
// Local dev layout: apps/agent-dev/src/service.ts → ../../tray-mac/build/ModelstatTray.app
|
|
48165
|
-
|
|
48371
|
+
join6(here2, "..", "..", "tray-mac", "build", "ModelstatTray.app")
|
|
48166
48372
|
];
|
|
48167
48373
|
for (const c of candidates) {
|
|
48168
|
-
if (
|
|
48374
|
+
if (existsSync7(c)) return c;
|
|
48169
48375
|
}
|
|
48170
48376
|
const sourceDirs = [
|
|
48171
|
-
|
|
48172
|
-
|
|
48377
|
+
join6(here2, "..", "vendor", "tray-mac"),
|
|
48378
|
+
join6(here2, "..", "..", "tray-mac")
|
|
48173
48379
|
];
|
|
48174
48380
|
for (const src of sourceDirs) {
|
|
48175
|
-
const build =
|
|
48176
|
-
if (!
|
|
48381
|
+
const build = join6(src, "build-app.sh");
|
|
48382
|
+
if (!existsSync7(build)) continue;
|
|
48177
48383
|
if (!hasSwift()) return null;
|
|
48178
48384
|
const r = spawnSync("bash", [build], { cwd: src, encoding: "utf8" });
|
|
48179
48385
|
if (r.status === 0) {
|
|
48180
|
-
const app =
|
|
48181
|
-
if (
|
|
48386
|
+
const app = join6(src, "build", "ModelstatTray.app");
|
|
48387
|
+
if (existsSync7(app)) return app;
|
|
48182
48388
|
}
|
|
48183
48389
|
}
|
|
48184
48390
|
return null;
|
|
@@ -48223,7 +48429,7 @@ function tryOpenBrowser(url) {
|
|
|
48223
48429
|
return false;
|
|
48224
48430
|
}
|
|
48225
48431
|
}
|
|
48226
|
-
var AGENT_VERSION3 = true ? "agent-0.0.
|
|
48432
|
+
var AGENT_VERSION3 = true ? "agent-0.0.44" : "agent-dev";
|
|
48227
48433
|
function osFamily() {
|
|
48228
48434
|
const p = platform4();
|
|
48229
48435
|
if (p === "darwin") return "macos";
|
|
@@ -48618,9 +48824,9 @@ function fmtTokens(v) {
|
|
|
48618
48824
|
async function readLocalStatus() {
|
|
48619
48825
|
try {
|
|
48620
48826
|
const { homedir: homedir9 } = await import("os");
|
|
48621
|
-
const { join:
|
|
48827
|
+
const { join: join11 } = await import("path");
|
|
48622
48828
|
const { readFile } = await import("fs/promises");
|
|
48623
|
-
const p =
|
|
48829
|
+
const p = join11(homedir9(), ".modelstat", "last-status.json");
|
|
48624
48830
|
const txt = await readFile(p, "utf8");
|
|
48625
48831
|
return JSON.parse(txt);
|
|
48626
48832
|
} catch {
|