modelstat 0.0.33 → 0.0.35
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/LICENSE +87 -0
- package/dist/cli.mjs +145 -6
- package/dist/cli.mjs.map +1 -1
- package/package.json +18 -19
- package/scripts/postinstall.mjs +63 -5
- package/vendor/tray-mac/build-app.sh +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "modelstat",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.35",
|
|
4
4
|
"description": "modelstat companion — reads local AI-tool usage and ships tokenised events to modelstat.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -15,19 +15,6 @@
|
|
|
15
15
|
"README.md",
|
|
16
16
|
"LICENSE"
|
|
17
17
|
],
|
|
18
|
-
"scripts": {
|
|
19
|
-
"dev:connect": "tsx ./src/cli.ts connect",
|
|
20
|
-
"dev:scan": "tsx ./src/cli.ts scan",
|
|
21
|
-
"dev:watch": "tsx ./src/cli.ts watch",
|
|
22
|
-
"dev:discover": "tsx ./src/cli.ts discover",
|
|
23
|
-
"build": "tsup",
|
|
24
|
-
"build:tray": "bash ./scripts/build-tray.sh",
|
|
25
|
-
"prepack": "pnpm run build && pnpm run build:tray",
|
|
26
|
-
"pack:tarball": "pnpm run build && npm pack --pack-destination ../..",
|
|
27
|
-
"install:local": "bash ./scripts/install-local.sh",
|
|
28
|
-
"postinstall": "node ./scripts/postinstall.mjs",
|
|
29
|
-
"typecheck": "tsc --noEmit"
|
|
30
|
-
},
|
|
31
18
|
"dependencies": {
|
|
32
19
|
"chokidar": "^4.0.3",
|
|
33
20
|
"conf": "^13.1.0",
|
|
@@ -37,13 +24,13 @@
|
|
|
37
24
|
"undici": "^7.1.0"
|
|
38
25
|
},
|
|
39
26
|
"devDependencies": {
|
|
40
|
-
"@modelstat/companion-core": "workspace:*",
|
|
41
|
-
"@modelstat/core": "workspace:*",
|
|
42
|
-
"@modelstat/parsers": "workspace:*",
|
|
43
27
|
"@types/node": "^22.10.5",
|
|
44
28
|
"tsup": "^8.3.5",
|
|
45
29
|
"tsx": "^4.19.2",
|
|
46
|
-
"typescript": "^5.7.3"
|
|
30
|
+
"typescript": "^5.7.3",
|
|
31
|
+
"@modelstat/companion-core": "0.0.0",
|
|
32
|
+
"@modelstat/core": "0.0.0",
|
|
33
|
+
"@modelstat/parsers": "0.0.0"
|
|
47
34
|
},
|
|
48
35
|
"engines": {
|
|
49
36
|
"node": ">=20.18.0"
|
|
@@ -71,5 +58,17 @@
|
|
|
71
58
|
"type": "git",
|
|
72
59
|
"url": "git+https://github.com/modelstat/modelstat.git",
|
|
73
60
|
"directory": "apps/agent-dev"
|
|
61
|
+
},
|
|
62
|
+
"scripts": {
|
|
63
|
+
"dev:connect": "tsx ./src/cli.ts connect",
|
|
64
|
+
"dev:scan": "tsx ./src/cli.ts scan",
|
|
65
|
+
"dev:watch": "tsx ./src/cli.ts watch",
|
|
66
|
+
"dev:discover": "tsx ./src/cli.ts discover",
|
|
67
|
+
"build": "tsup",
|
|
68
|
+
"build:tray": "bash ./scripts/build-tray.sh",
|
|
69
|
+
"pack:tarball": "pnpm run build && npm pack --pack-destination ../..",
|
|
70
|
+
"install:local": "bash ./scripts/install-local.sh",
|
|
71
|
+
"postinstall": "node ./scripts/postinstall.mjs",
|
|
72
|
+
"typecheck": "tsc --noEmit"
|
|
74
73
|
}
|
|
75
|
-
}
|
|
74
|
+
}
|
package/scripts/postinstall.mjs
CHANGED
|
@@ -317,13 +317,71 @@ async function setupNativeNodeModules(installedBundle) {
|
|
|
317
317
|
}
|
|
318
318
|
|
|
319
319
|
/**
|
|
320
|
-
* Kill any
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
* lock
|
|
324
|
-
*
|
|
320
|
+
* Kill any modelstat-related process the service supervisor didn't
|
|
321
|
+
* reap. Two passes:
|
|
322
|
+
* (1) PID from ~/.modelstat/daemon.lock — the most reliable hit
|
|
323
|
+
* when the lock is fresh and our own daemon wrote it.
|
|
324
|
+
* (2) Process scan via `pgrep -f` on macOS/Linux — catches stray
|
|
325
|
+
* daemons launched by an OLDER bundle (different command
|
|
326
|
+
* line, different lock format), zombies that survived a
|
|
327
|
+
* launchd KeepAlive bounce, and the case where the user has
|
|
328
|
+
* BOTH the launchd-managed daemon AND a hand-spawned one
|
|
329
|
+
* running. The pattern is intentionally narrow
|
|
330
|
+
* (`modelstat\\.mjs`) so we don't kill `modelstatd` or any
|
|
331
|
+
* other process that happens to share a substring.
|
|
332
|
+
*
|
|
333
|
+
* SIGTERM first, escalate to SIGKILL after 2 s. All failures
|
|
334
|
+
* tolerated — we just want the new bundle to be the only modelstat
|
|
335
|
+
* process holding the lock when we restart.
|
|
325
336
|
*/
|
|
326
337
|
async function killStaleDaemon(stateDir) {
|
|
338
|
+
await killByLockfile(stateDir);
|
|
339
|
+
await killByProcessScan();
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
async function killByProcessScan() {
|
|
343
|
+
const { spawnSync } = await import("node:child_process");
|
|
344
|
+
// pgrep is on macOS by default, Linux via procps.
|
|
345
|
+
const r = spawnSync("pgrep", ["-f", "modelstat\\.mjs"], {
|
|
346
|
+
encoding: "utf8",
|
|
347
|
+
});
|
|
348
|
+
if (r.status !== 0 || !r.stdout) return;
|
|
349
|
+
const pids = r.stdout
|
|
350
|
+
.split(/\s+/)
|
|
351
|
+
.map((s) => Number(s))
|
|
352
|
+
.filter((n) => Number.isInteger(n) && n > 0 && n !== process.pid);
|
|
353
|
+
if (pids.length === 0) return;
|
|
354
|
+
for (const pid of pids) {
|
|
355
|
+
try {
|
|
356
|
+
process.kill(pid, "SIGTERM");
|
|
357
|
+
} catch {
|
|
358
|
+
/* gone or not ours */
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
// Wait up to 2 s for graceful exits.
|
|
362
|
+
for (let i = 0; i < 20; i++) {
|
|
363
|
+
let alive = 0;
|
|
364
|
+
for (const pid of pids) {
|
|
365
|
+
try {
|
|
366
|
+
process.kill(pid, 0);
|
|
367
|
+
alive += 1;
|
|
368
|
+
} catch {
|
|
369
|
+
/* exited */
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
if (alive === 0) return;
|
|
373
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
374
|
+
}
|
|
375
|
+
for (const pid of pids) {
|
|
376
|
+
try {
|
|
377
|
+
process.kill(pid, "SIGKILL");
|
|
378
|
+
} catch {
|
|
379
|
+
/* gone or denied */
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
async function killByLockfile(stateDir) {
|
|
327
385
|
const { readFileSync } = await import("node:fs");
|
|
328
386
|
const lockPath = join(stateDir, "daemon.lock");
|
|
329
387
|
let payload;
|
|
File without changes
|