claudelink 1.4.3 → 1.5.0

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.
Files changed (47) hide show
  1. package/README.md +34 -1
  2. package/dist/arm-compact.d.ts +2 -0
  3. package/dist/arm-compact.js +182 -0
  4. package/dist/arm-compact.js.map +1 -0
  5. package/dist/cli.js +145 -0
  6. package/dist/cli.js.map +1 -1
  7. package/dist/compact-analyzer.d.ts +67 -0
  8. package/dist/compact-analyzer.js +309 -0
  9. package/dist/compact-analyzer.js.map +1 -0
  10. package/dist/compact-decision.d.ts +19 -0
  11. package/dist/compact-decision.js +47 -0
  12. package/dist/compact-decision.js.map +1 -0
  13. package/dist/compact-executor.d.ts +27 -0
  14. package/dist/compact-executor.js +160 -0
  15. package/dist/compact-executor.js.map +1 -0
  16. package/dist/context-watcher-settings.d.ts +21 -0
  17. package/dist/context-watcher-settings.js +176 -0
  18. package/dist/context-watcher-settings.js.map +1 -0
  19. package/dist/context-watcher.d.ts +70 -0
  20. package/dist/context-watcher.js +1005 -0
  21. package/dist/context-watcher.js.map +1 -0
  22. package/dist/db.d.ts +22 -1
  23. package/dist/db.js +184 -5
  24. package/dist/db.js.map +1 -1
  25. package/dist/hooks/stop-hook.js +30 -1
  26. package/dist/hooks/stop-hook.js.map +1 -1
  27. package/dist/index.js +144 -12
  28. package/dist/index.js.map +1 -1
  29. package/dist/manual-decision.d.ts +23 -0
  30. package/dist/manual-decision.js +67 -0
  31. package/dist/manual-decision.js.map +1 -0
  32. package/dist/prompt-clear.d.ts +8 -0
  33. package/dist/prompt-clear.js +33 -0
  34. package/dist/prompt-clear.js.map +1 -0
  35. package/dist/recovery-watcher.d.ts +6 -0
  36. package/dist/recovery-watcher.js +20 -0
  37. package/dist/recovery-watcher.js.map +1 -1
  38. package/dist/role-collision.d.ts +6 -0
  39. package/dist/role-collision.js +51 -0
  40. package/dist/role-collision.js.map +1 -0
  41. package/dist/ui-server.d.ts +4 -0
  42. package/dist/ui-server.js +899 -20
  43. package/dist/ui-server.js.map +1 -1
  44. package/dist/usage-reader.d.ts +79 -0
  45. package/dist/usage-reader.js +553 -0
  46. package/dist/usage-reader.js.map +1 -0
  47. package/package.json +8 -2
@@ -0,0 +1,553 @@
1
+ "use strict";
2
+ // Fleet token meter — reads each registered agent's LOCAL Claude Code session
3
+ // transcripts and aggregates real token usage per project / per model / per day.
4
+ //
5
+ // Why this is possible: Claude Code writes one JSONL transcript per session at
6
+ // ~/.claude/projects/<project-id>/<session-uuid>.jsonl
7
+ // and every assistant message line carries a `message.usage` block with real
8
+ // token counts (input_tokens, output_tokens, cache_creation_input_tokens,
9
+ // cache_read_input_tokens) plus `message.model` and a top-level `timestamp`.
10
+ // We parse those to surface where the weekly burn goes. This is READ-ONLY: we
11
+ // never write to the transcripts and never touch terminals.
12
+ //
13
+ // What we CAN'T see: the Max-plan weekly quota CEILING is server-side at
14
+ // Anthropic with no local API. We report consumption + breakdown + trend, not
15
+ // "% of quota". Cost is an ESTIMATE from per-model price constants below.
16
+ //
17
+ // Attribution model (honest about its limits):
18
+ // - project-id is derived deterministically from an agent's working dir
19
+ // (cwd), which we read live via `lsof` on the registered claudelink-server
20
+ // pid. cwd is stable for a process's lifetime, so we memoize it.
21
+ // - When exactly one registered agent maps to a project dir, we label that
22
+ // project with the agent's role (clean 1:1).
23
+ // - When several agents share a project dir (e.g. a fleet all launched in the
24
+ // same repo), we can't reliably attribute a transcript SESSION to a
25
+ // specific agent — there is no stored agent->sessionId key today — so we
26
+ // report the project as a GROUP and list the roles. Per-agent split within
27
+ // a shared project is a fast-follow that needs register-time sessionId
28
+ // capture (schema v3).
29
+ var __importDefault = (this && this.__importDefault) || function (mod) {
30
+ return (mod && mod.__esModule) ? mod : { "default": mod };
31
+ };
32
+ Object.defineProperty(exports, "__esModule", { value: true });
33
+ exports.OPUS_CACHE_READ_PER_MTOK = exports.PROJECTS_DIR = void 0;
34
+ exports.cwdForPid = cwdForPid;
35
+ exports.projectIdFromCwd = projectIdFromCwd;
36
+ exports.cacheReadPricePerMtok = cacheReadPricePerMtok;
37
+ exports.modelContextWindow = modelContextWindow;
38
+ exports.effectiveContextWindow = effectiveContextWindow;
39
+ exports.readAgentTimelines = readAgentTimelines;
40
+ exports.readFleetUsage = readFleetUsage;
41
+ const fs_1 = __importDefault(require("fs"));
42
+ const path_1 = __importDefault(require("path"));
43
+ const os_1 = __importDefault(require("os"));
44
+ const readline_1 = __importDefault(require("readline"));
45
+ const child_process_1 = require("child_process");
46
+ exports.PROJECTS_DIR = path_1.default.join(os_1.default.homedir(), ".claude", "projects");
47
+ const PRICES = {
48
+ opus: { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 },
49
+ sonnet: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
50
+ haiku: { input: 0.8, output: 4, cacheRead: 0.08, cacheWrite: 1 },
51
+ };
52
+ function priceFor(model) {
53
+ const m = model.toLowerCase();
54
+ if (m.includes("opus"))
55
+ return PRICES.opus;
56
+ if (m.includes("haiku"))
57
+ return PRICES.haiku;
58
+ // Unknown / sonnet → sonnet-tier as a neutral, clearly-labeled fallback.
59
+ return PRICES.sonnet;
60
+ }
61
+ function emptyBucket() {
62
+ return { input: 0, output: 0, cacheRead: 0, cacheCreation: 0, totalTokens: 0, estCostUsd: 0 };
63
+ }
64
+ function addUsage(b, model, u) {
65
+ const input = Number(u.input_tokens) || 0;
66
+ const output = Number(u.output_tokens) || 0;
67
+ const cacheRead = Number(u.cache_read_input_tokens) || 0;
68
+ const cacheCreation = Number(u.cache_creation_input_tokens) || 0;
69
+ b.input += input;
70
+ b.output += output;
71
+ b.cacheRead += cacheRead;
72
+ b.cacheCreation += cacheCreation;
73
+ b.totalTokens += input + output + cacheRead + cacheCreation;
74
+ const p = priceFor(model);
75
+ b.estCostUsd +=
76
+ (input * p.input +
77
+ output * p.output +
78
+ cacheRead * p.cacheRead +
79
+ cacheCreation * p.cacheWrite) /
80
+ 1000000;
81
+ }
82
+ // cwd of a pid, via lsof. Memoized for the process lifetime — cwd never
83
+ // changes for a running process, and lsof is comparatively slow.
84
+ const cwdCache = new Map();
85
+ function cwdForPid(pid) {
86
+ if (cwdCache.has(pid))
87
+ return cwdCache.get(pid);
88
+ let cwd = null;
89
+ try {
90
+ const out = (0, child_process_1.execFileSync)("lsof", ["-a", "-p", String(pid), "-d", "cwd", "-Fn"], {
91
+ timeout: 2000,
92
+ stdio: ["ignore", "pipe", "ignore"],
93
+ encoding: "utf-8",
94
+ });
95
+ const line = out.split("\n").find((l) => l.startsWith("n"));
96
+ if (line)
97
+ cwd = line.slice(1).trim();
98
+ }
99
+ catch {
100
+ cwd = null;
101
+ }
102
+ cwdCache.set(pid, cwd);
103
+ return cwd;
104
+ }
105
+ // Claude Code encodes a project's cwd into its transcript dir name by replacing
106
+ // every non-alphanumeric character with a dash. Verified against the live
107
+ // fleet (spaces and slashes both map to '-'). We derive the name AND confirm
108
+ // the dir exists before trusting it.
109
+ function projectIdFromCwd(cwd) {
110
+ return cwd.replace(/[^a-zA-Z0-9]/g, "-");
111
+ }
112
+ // Opus cache-read list price (USD per million tokens). The context-hygiene
113
+ // projection values "excess" re-read tokens at this rate. Labeled as an
114
+ // estimate wherever surfaced.
115
+ exports.OPUS_CACHE_READ_PER_MTOK = PRICES.opus.cacheRead;
116
+ // Model-aware cache-read price (USD per million tokens). The $/turn economic
117
+ // trigger uses this so the threshold auto-adjusts across models — Opus triggers
118
+ // far earlier than Haiku for the same context size, which is correct.
119
+ function cacheReadPricePerMtok(model) {
120
+ return priceFor(model).cacheRead;
121
+ }
122
+ // Model context window (tokens). Default 200K — the standard window for Opus
123
+ // 4.x / Sonnet 4.x / Haiku 4.x. Honors the 1M-context beta when the model id
124
+ // carries the `[1m]` suffix or a `-1m` variant. Used by the per-model
125
+ // proportional-occupancy threshold so the arming criterion is "what fraction
126
+ // of this model's window is currently re-sent each turn" — proportional, not a
127
+ // raw-size or raw-dollar absolute. The 50%-of-window default replaces the
128
+ // model-blind dollar gate the rollout originally shipped with.
129
+ function modelContextWindow(model) {
130
+ if (!model)
131
+ return 200000;
132
+ const m = model.toLowerCase();
133
+ if (m.includes("[1m]") || m.includes("-1m") || m.includes(" 1m"))
134
+ return 1000000;
135
+ return 200000;
136
+ }
137
+ // The window to divide observed context by. The model ID alone is not enough:
138
+ // the 1M-context beta is a request HEADER, so Claude Code records the model as
139
+ // plain "claude-opus-4-8" even when it's running on a 1M window — modelContextWindow
140
+ // then defaults to 200K and occupancy reads >100% (e.g. a real 572K turn shows 286%).
141
+ //
142
+ // We infer from evidence instead: if a turn's input-side tokens EXCEED 200K, the
143
+ // API accepted a request a 200K model would have rejected, so that session is
144
+ // provably on a >200K (i.e. 1M) window. Below 200K the label is unchanged —
145
+ // correct for a 200K model, harmless for a 1M one — so this only corrects the
146
+ // misleading >100% case. Self-correcting, no config, no transcript internals.
147
+ function effectiveContextWindow(model, contextTokens) {
148
+ if (contextTokens > 200000)
149
+ return 1000000;
150
+ return modelContextWindow(model);
151
+ }
152
+ function localDate(ts) {
153
+ const d = new Date(ts);
154
+ const y = d.getFullYear();
155
+ const m = String(d.getMonth() + 1).padStart(2, "0");
156
+ const day = String(d.getDate()).padStart(2, "0");
157
+ return `${y}-${m}-${day}`;
158
+ }
159
+ async function scanTranscript(file, windowStartMs, proj, perDay, seen, opp, fileBucket, fileInfo) {
160
+ const rl = readline_1.default.createInterface({
161
+ input: fs_1.default.createReadStream(file, { encoding: "utf-8" }),
162
+ crlfDelay: Infinity,
163
+ });
164
+ for await (const line of rl) {
165
+ // Capture the agent's self-identified role: each session registers through
166
+ // ClaudeLink, so the transcript contains its own register tool_use with the
167
+ // role. This labels per-session sub-rows by registered name with no
168
+ // dependence on the deploy/session-capture. Cheap-gated on the substring.
169
+ if (fileInfo.registerRole === null && line.indexOf("register") !== -1) {
170
+ try {
171
+ const ro = JSON.parse(line);
172
+ const content = ro?.message?.content;
173
+ if (Array.isArray(content)) {
174
+ for (const b of content) {
175
+ if (b && b.type === "tool_use" &&
176
+ typeof b.name === "string" &&
177
+ // Tighten match: an MCP server with a tool named e.g.
178
+ // "register_user" would have leaked through includes("register").
179
+ // The ClaudeLink register tool is namespaced under mcp__claudelink
180
+ // by Claude Code, so the trailing-name is "register" or
181
+ // "mcp__claudelink__register" — match the suffix exactly.
182
+ (b.name === "register" ||
183
+ b.name.endsWith("__register") ||
184
+ b.name === "mcp__claudelink__register") &&
185
+ b.input && typeof b.input.role === "string" && b.input.role) {
186
+ fileInfo.registerRole = b.input.role;
187
+ break;
188
+ }
189
+ }
190
+ }
191
+ }
192
+ catch {
193
+ /* ignore */
194
+ }
195
+ }
196
+ // Cheap pre-filter: skip lines that obviously can't carry usage.
197
+ if (line.indexOf('"usage"') === -1)
198
+ continue;
199
+ let o;
200
+ try {
201
+ o = JSON.parse(line);
202
+ }
203
+ catch {
204
+ continue;
205
+ }
206
+ const msg = o?.message;
207
+ const u = msg?.usage;
208
+ if (!u || !msg?.model)
209
+ continue;
210
+ const model = msg.model;
211
+ // Claude Code tags synthetic assistant turns (injected context, hook
212
+ // output) with model "<synthetic>" — no real API call, no billing. Skip so
213
+ // they don't clutter the per-model breakdown.
214
+ if (model === "<synthetic>")
215
+ continue;
216
+ // Fork/resume dedupe: when a session is resumed or forked, Claude Code can
217
+ // re-emit the same assistant message (same message.id + requestId) in a new
218
+ // transcript. Counting both double-counts — and because the re-emit carries
219
+ // the cached context, the inflation lands almost entirely in cache_read.
220
+ // Dedupe on the same key ccusage uses. Lines lacking both ids are counted.
221
+ if (msg.id && o.requestId) {
222
+ const key = msg.id + "::" + o.requestId;
223
+ if (seen.has(key))
224
+ continue;
225
+ seen.add(key);
226
+ }
227
+ const ts = Date.parse(o.timestamp || "");
228
+ if (!Number.isFinite(ts) || ts < windowStartMs)
229
+ continue;
230
+ // Compact-opportunity, same pass: a turn's input-side tokens = context
231
+ // occupancy; count the excess over the post-compact baseline for turns
232
+ // above threshold (upper-bound savings if compacted at threshold).
233
+ const ctxTokens = (Number(u.input_tokens) || 0) +
234
+ (Number(u.cache_read_input_tokens) || 0) +
235
+ (Number(u.cache_creation_input_tokens) || 0);
236
+ if (ctxTokens > opp.thresholdTokens) {
237
+ opp.flaggedTurns++;
238
+ opp.excessTokens += Math.max(0, ctxTokens - opp.baselineTokens);
239
+ }
240
+ addUsage(proj.totals, model, u);
241
+ if (!proj.perModel[model])
242
+ proj.perModel[model] = emptyBucket();
243
+ addUsage(proj.perModel[model], model, u);
244
+ addUsage(fileBucket, model, u); // per-session total for the + expand
245
+ // Fleet per-day trend (across all projects). Tallied separately from the
246
+ // project buckets so a zero-filled dense series is easy to emit later.
247
+ const day = localDate(ts);
248
+ const slot = perDay.get(day) || { totalTokens: 0, estCostUsd: 0 };
249
+ const input = Number(u.input_tokens) || 0;
250
+ const output = Number(u.output_tokens) || 0;
251
+ const cacheRead = Number(u.cache_read_input_tokens) || 0;
252
+ const cacheCreation = Number(u.cache_creation_input_tokens) || 0;
253
+ const p = priceFor(model);
254
+ slot.totalTokens += input + output + cacheRead + cacheCreation;
255
+ slot.estCostUsd +=
256
+ (input * p.input + output * p.output + cacheRead * p.cacheRead + cacheCreation * p.cacheWrite) /
257
+ 1000000;
258
+ perDay.set(day, slot);
259
+ }
260
+ }
261
+ async function scanFileForTimeline(file, seen) {
262
+ const out = { registerRole: null, tokens: 0, estUsd: 0, compacts: [], latestCtxTokens: 0, latestModel: "", latestTs: 0 };
263
+ const bucket = emptyBucket();
264
+ const rl = readline_1.default.createInterface({ input: fs_1.default.createReadStream(file, { encoding: "utf-8" }), crlfDelay: Infinity });
265
+ for await (const line of rl) {
266
+ // compact boundary marker (#3)
267
+ if (line.indexOf("compact_boundary") !== -1) {
268
+ try {
269
+ const o = JSON.parse(line);
270
+ if (o?.type === "system" && o?.subtype === "compact_boundary") {
271
+ const cm = o.compactMetadata || {};
272
+ out.compacts.push({ ts: o.timestamp || "", trigger: cm.trigger ?? "?", preTokens: cm.preTokens ?? 0, postTokens: cm.postTokens ?? 0 });
273
+ // A compact is the most-recent EVENT when the agent hasn't taken a
274
+ // turn since — current-context is then the post-compact size (e.g.
275
+ // 13K), not the stale pre-compact turn. Latest event wins.
276
+ const cts = Date.parse(o.timestamp || "") || 0;
277
+ if (cts >= out.latestTs && cm.postTokens != null) {
278
+ out.latestTs = cts;
279
+ out.latestCtxTokens = cm.postTokens;
280
+ }
281
+ continue;
282
+ }
283
+ }
284
+ catch { /* fall through */ }
285
+ }
286
+ // register-role capture (agent identity)
287
+ if (out.registerRole === null && line.indexOf("register") !== -1) {
288
+ try {
289
+ const c = JSON.parse(line)?.message?.content;
290
+ if (Array.isArray(c))
291
+ for (const b of c)
292
+ if (b && b.type === "tool_use" && typeof b.name === "string" && b.name.includes("register") && b.input && typeof b.input.role === "string" && b.input.role) {
293
+ out.registerRole = b.input.role;
294
+ break;
295
+ }
296
+ }
297
+ catch { /* ignore */ }
298
+ }
299
+ if (line.indexOf('"usage"') === -1)
300
+ continue;
301
+ let o;
302
+ try {
303
+ o = JSON.parse(line);
304
+ }
305
+ catch {
306
+ continue;
307
+ }
308
+ const msg = o?.message;
309
+ const u = msg?.usage;
310
+ if (!u || !msg?.model || msg.model === "<synthetic>")
311
+ continue;
312
+ if (msg.id && o.requestId) {
313
+ const k = msg.id + "::" + o.requestId;
314
+ if (seen.has(k))
315
+ continue;
316
+ seen.add(k);
317
+ }
318
+ addUsage(bucket, msg.model, u);
319
+ const ts = Date.parse(o.timestamp || "") || 0;
320
+ // current-context = the chronologically-latest turn's input-side tokens
321
+ const ctx = (Number(u.input_tokens) || 0) + (Number(u.cache_read_input_tokens) || 0) + (Number(u.cache_creation_input_tokens) || 0);
322
+ if (ts >= out.latestTs) {
323
+ out.latestTs = ts;
324
+ out.latestCtxTokens = ctx;
325
+ out.latestModel = msg.model;
326
+ }
327
+ }
328
+ out.tokens = bucket.totalTokens;
329
+ out.estUsd = bucket.estCostUsd;
330
+ return out;
331
+ }
332
+ async function readAgentTimelines(agents) {
333
+ // Group by project; remember each project's roles + transcript_path→role map.
334
+ const byProject = new Map();
335
+ for (const a of agents) {
336
+ const cwd = cwdForPid(a.pid);
337
+ if (!cwd)
338
+ continue;
339
+ const id = projectIdFromCwd(cwd);
340
+ const dir = path_1.default.join(exports.PROJECTS_DIR, id);
341
+ if (!fs_1.default.existsSync(dir))
342
+ continue;
343
+ const e = byProject.get(id) || { dir, roles: [], pathRole: new Map() };
344
+ e.roles.push(a.role);
345
+ if (a.transcriptPath)
346
+ e.pathRole.set(a.transcriptPath, a.role);
347
+ byProject.set(id, e);
348
+ }
349
+ const perRole = new Map();
350
+ const get = (role) => {
351
+ let t = perRole.get(role);
352
+ if (!t) {
353
+ t = { role, cumulativeTokens: 0, cumulativeEstUsd: 0, currentContextTokens: 0, currentContextPerTurnUsd: 0, compactEvents: [], sessions: 0, lastActivity: null };
354
+ perRole.set(role, t);
355
+ }
356
+ return t;
357
+ };
358
+ const seen = new Set();
359
+ const latestTsByRole = new Map();
360
+ for (const { dir, roles, pathRole } of byProject.values()) {
361
+ let files = [];
362
+ try {
363
+ files = fs_1.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl")).map((f) => path_1.default.join(dir, f));
364
+ }
365
+ catch {
366
+ continue;
367
+ }
368
+ for (const file of files) {
369
+ const ft = await scanFileForTimeline(file, seen);
370
+ if (ft.tokens === 0 && ft.compacts.length === 0)
371
+ continue;
372
+ // attribute: transcript_path map → role; else register-role; else single-agent project's role; else skip
373
+ const role = pathRole.get(file) || ft.registerRole || (roles.length === 1 ? roles[0] : null);
374
+ if (!role)
375
+ continue;
376
+ const t = get(role);
377
+ t.cumulativeTokens += ft.tokens;
378
+ t.cumulativeEstUsd += ft.estUsd;
379
+ t.sessions += 1;
380
+ for (const c of ft.compacts)
381
+ t.compactEvents.push(c);
382
+ // current-context = latest turn across the role's most-recent session
383
+ if (ft.latestTs > (latestTsByRole.get(role) || 0) && ft.latestCtxTokens > 0) {
384
+ latestTsByRole.set(role, ft.latestTs);
385
+ t.currentContextTokens = ft.latestCtxTokens;
386
+ t.currentContextPerTurnUsd = (ft.latestCtxTokens * priceFor(ft.latestModel).cacheRead) / 1000000;
387
+ t.lastActivity = new Date(ft.latestTs).toISOString();
388
+ }
389
+ }
390
+ }
391
+ for (const t of perRole.values())
392
+ t.compactEvents.sort((a, b) => (Date.parse(a.ts) || 0) - (Date.parse(b.ts) || 0));
393
+ return [...perRole.values()].filter((t) => agents.some((a) => a.role === t.role)).sort((a, b) => b.cumulativeTokens - a.cumulativeTokens);
394
+ }
395
+ async function readFleetUsage(agents, windowDays = 7, thresholdTokens = 200000, compactBaselineTokens = 60000) {
396
+ const now = Date.now();
397
+ const windowStartMs = now - windowDays * 24 * 60 * 60 * 1000;
398
+ const opp = {
399
+ thresholdTokens,
400
+ baselineTokens: compactBaselineTokens,
401
+ flaggedTurns: 0,
402
+ excessTokens: 0,
403
+ };
404
+ // Map live agents -> project dirs, grouping agents that share a cwd. pathRole
405
+ // maps a captured transcript_path to its agent role, so per-session sub-rows
406
+ // can be labeled by agent even in a shared repo dir (once session-capture is
407
+ // populated).
408
+ const byProject = new Map();
409
+ const skippedNoCwd = [];
410
+ for (const a of agents) {
411
+ const cwd = cwdForPid(a.pid);
412
+ if (!cwd) {
413
+ skippedNoCwd.push(a.role);
414
+ continue;
415
+ }
416
+ const projectId = projectIdFromCwd(cwd);
417
+ const dir = path_1.default.join(exports.PROJECTS_DIR, projectId);
418
+ if (!fs_1.default.existsSync(dir)) {
419
+ skippedNoCwd.push(a.role);
420
+ continue;
421
+ }
422
+ const entry = byProject.get(projectId) || { cwd, projectId, roles: [], pathRole: new Map() };
423
+ entry.roles.push(a.role);
424
+ if (a.transcriptPath)
425
+ entry.pathRole.set(a.transcriptPath, a.role);
426
+ byProject.set(projectId, entry);
427
+ }
428
+ const perDay = new Map();
429
+ const projects = [];
430
+ // Global dedupe key set, shared across every transcript in this read, so a
431
+ // message re-emitted in a forked session is counted exactly once.
432
+ const seen = new Set();
433
+ for (const { cwd, projectId, roles, pathRole } of byProject.values()) {
434
+ const dir = path_1.default.join(exports.PROJECTS_DIR, projectId);
435
+ const proj = {
436
+ projectId,
437
+ cwd,
438
+ label: roles.length === 1
439
+ ? roles[0]
440
+ : `${path_1.default.basename(cwd)} (${roles.length} agents)`,
441
+ agentRoles: roles,
442
+ sessions: 0,
443
+ totals: emptyBucket(),
444
+ perModel: {},
445
+ breakdown: [],
446
+ };
447
+ let files = [];
448
+ try {
449
+ files = fs_1.default
450
+ .readdirSync(dir)
451
+ .filter((f) => f.endsWith(".jsonl"))
452
+ .map((f) => path_1.default.join(dir, f));
453
+ }
454
+ catch {
455
+ files = [];
456
+ }
457
+ for (const file of files) {
458
+ // mtime guard: a transcript not touched since the window opened can hold
459
+ // no in-window usage. Skips ancient sessions cheaply.
460
+ try {
461
+ if (fs_1.default.statSync(file).mtimeMs < windowStartMs)
462
+ continue;
463
+ }
464
+ catch {
465
+ continue;
466
+ }
467
+ proj.sessions++;
468
+ const fileBucket = emptyBucket();
469
+ const fileInfo = { registerRole: null };
470
+ await scanTranscript(file, windowStartMs, proj, perDay, seen, opp, fileBucket, fileInfo);
471
+ if (fileBucket.totalTokens > 0) {
472
+ const sessionId = path_1.default.basename(file).replace(/\.jsonl$/, "");
473
+ // Label priority: (1) exact session-capture map; (2) the agent's own
474
+ // register call found in the transcript (works NOW, no deploy);
475
+ // (3) single-agent project owns its sessions; (4) session-id stub.
476
+ let label;
477
+ let mapped;
478
+ if (pathRole.has(file)) {
479
+ label = pathRole.get(file);
480
+ mapped = true;
481
+ }
482
+ else if (fileInfo.registerRole) {
483
+ label = fileInfo.registerRole;
484
+ mapped = true;
485
+ }
486
+ else if (roles.length === 1) {
487
+ label = roles[0];
488
+ mapped = true;
489
+ }
490
+ else {
491
+ label = "session " + sessionId.slice(0, 8);
492
+ mapped = false;
493
+ }
494
+ proj.breakdown.push({
495
+ sessionId,
496
+ label,
497
+ mapped,
498
+ totalTokens: fileBucket.totalTokens,
499
+ estCostUsd: fileBucket.estCostUsd,
500
+ });
501
+ }
502
+ }
503
+ proj.breakdown.sort((a, b) => b.totalTokens - a.totalTokens);
504
+ projects.push(proj);
505
+ }
506
+ // Fleet roll-ups.
507
+ const fleetTotals = emptyBucket();
508
+ const fleetPerModel = {};
509
+ for (const proj of projects) {
510
+ fleetTotals.input += proj.totals.input;
511
+ fleetTotals.output += proj.totals.output;
512
+ fleetTotals.cacheRead += proj.totals.cacheRead;
513
+ fleetTotals.cacheCreation += proj.totals.cacheCreation;
514
+ fleetTotals.totalTokens += proj.totals.totalTokens;
515
+ fleetTotals.estCostUsd += proj.totals.estCostUsd;
516
+ for (const [model, b] of Object.entries(proj.perModel)) {
517
+ if (!fleetPerModel[model])
518
+ fleetPerModel[model] = emptyBucket();
519
+ const t = fleetPerModel[model];
520
+ t.input += b.input;
521
+ t.output += b.output;
522
+ t.cacheRead += b.cacheRead;
523
+ t.cacheCreation += b.cacheCreation;
524
+ t.totalTokens += b.totalTokens;
525
+ t.estCostUsd += b.estCostUsd;
526
+ }
527
+ }
528
+ // Dense per-day series across the window (zero-filled), oldest → newest.
529
+ const perDaySeries = [];
530
+ for (let i = windowDays - 1; i >= 0; i--) {
531
+ const date = localDate(now - i * 24 * 60 * 60 * 1000);
532
+ const v = perDay.get(date) || { totalTokens: 0, estCostUsd: 0 };
533
+ perDaySeries.push({ date, totalTokens: v.totalTokens, estCostUsd: v.estCostUsd });
534
+ }
535
+ // Heaviest projects first.
536
+ projects.sort((a, b) => b.totals.totalTokens - a.totals.totalTokens);
537
+ return {
538
+ generatedAt: new Date(now).toISOString(),
539
+ windowDays,
540
+ scannedProjects: projects.length,
541
+ skippedNoCwd,
542
+ fleet: { totals: fleetTotals, perModel: fleetPerModel, perDay: perDaySeries },
543
+ projects,
544
+ compactOpportunity: {
545
+ thresholdTokens,
546
+ compactBaselineTokens,
547
+ flaggedTurns: opp.flaggedTurns,
548
+ excessTokensUpperBound: opp.excessTokens,
549
+ estUsdUpperBound: (opp.excessTokens * exports.OPUS_CACHE_READ_PER_MTOK) / 1000000,
550
+ },
551
+ };
552
+ }
553
+ //# sourceMappingURL=usage-reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-reader.js","sourceRoot":"","sources":["../src/usage-reader.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudelink",
3
- "version": "1.4.3",
3
+ "version": "1.5.0",
4
4
  "description": "The hub where your AI agents connect. Multi-terminal Claude Code agent communication via MCP.",
5
5
  "main": "./dist/index.js",
6
6
  "bin": {
@@ -13,7 +13,11 @@
13
13
  "scripts": {
14
14
  "build": "tsc",
15
15
  "prepare": "npm run build",
16
- "start": "node dist/index.js"
16
+ "start": "node dist/index.js",
17
+ "test": "tsx --test test/*.test.ts",
18
+ "test:watch": "tsx --test --watch test/*.test.ts",
19
+ "test:e2e": "playwright test test/e2e",
20
+ "test:all": "npm test && npm run test:e2e"
17
21
  },
18
22
  "files": [
19
23
  "dist",
@@ -51,8 +55,10 @@
51
55
  "zod": "^3.23.0"
52
56
  },
53
57
  "devDependencies": {
58
+ "@playwright/test": "^1.61.0",
54
59
  "@types/better-sqlite3": "^7.6.12",
55
60
  "@types/node": "^20.11.0",
61
+ "tsx": "^4.22.4",
56
62
  "typescript": "^5.3.0"
57
63
  }
58
64
  }