agentvigil 1.0.8 → 1.0.9

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 (60) hide show
  1. package/dist/commands/daemon.d.ts.map +1 -1
  2. package/dist/commands/daemon.js +3 -0
  3. package/dist/commands/daemon.js.map +1 -1
  4. package/dist/commands/setup.d.ts.map +1 -1
  5. package/dist/commands/setup.js +2 -1
  6. package/dist/commands/setup.js.map +1 -1
  7. package/dist/hooks/hook-handler.d.ts.map +1 -1
  8. package/dist/hooks/hook-handler.js +7 -0
  9. package/dist/hooks/hook-handler.js.map +1 -1
  10. package/dist/index.js +9 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/notifications/mac-notifier.d.ts +11 -0
  13. package/dist/notifications/mac-notifier.d.ts.map +1 -0
  14. package/dist/notifications/mac-notifier.js +28 -0
  15. package/dist/notifications/mac-notifier.js.map +1 -0
  16. package/dist/notifications/ntfy-client.d.ts +2 -0
  17. package/dist/notifications/ntfy-client.d.ts.map +1 -1
  18. package/dist/notifications/ntfy-client.js +10 -0
  19. package/dist/notifications/ntfy-client.js.map +1 -1
  20. package/dist/relay/relay-handler.d.ts.map +1 -1
  21. package/dist/relay/relay-handler.js +3 -0
  22. package/dist/relay/relay-handler.js.map +1 -1
  23. package/dist/sessions/process-detector.d.ts +9 -0
  24. package/dist/sessions/process-detector.d.ts.map +1 -1
  25. package/dist/sessions/process-detector.js +63 -1
  26. package/dist/sessions/process-detector.js.map +1 -1
  27. package/dist/sessions/session-manager.d.ts.map +1 -1
  28. package/dist/sessions/session-manager.js +17 -1
  29. package/dist/sessions/session-manager.js.map +1 -1
  30. package/dist/sessions/token-calculator.d.ts +15 -0
  31. package/dist/sessions/token-calculator.d.ts.map +1 -0
  32. package/dist/sessions/token-calculator.js +94 -0
  33. package/dist/sessions/token-calculator.js.map +1 -0
  34. package/dist/stats/daily-tracker.d.ts +114 -0
  35. package/dist/stats/daily-tracker.d.ts.map +1 -0
  36. package/dist/stats/daily-tracker.js +484 -0
  37. package/dist/stats/daily-tracker.js.map +1 -0
  38. package/dist/stats/session-utils.d.ts +2 -0
  39. package/dist/stats/session-utils.d.ts.map +1 -0
  40. package/dist/stats/session-utils.js +11 -0
  41. package/dist/stats/session-utils.js.map +1 -0
  42. package/dist/stats/summary-formatter.d.ts +67 -0
  43. package/dist/stats/summary-formatter.d.ts.map +1 -0
  44. package/dist/stats/summary-formatter.js +116 -0
  45. package/dist/stats/summary-formatter.js.map +1 -0
  46. package/dist/stats/transcript-sync.d.ts +18 -0
  47. package/dist/stats/transcript-sync.d.ts.map +1 -0
  48. package/dist/stats/transcript-sync.js +143 -0
  49. package/dist/stats/transcript-sync.js.map +1 -0
  50. package/dist/types.d.ts +4 -1
  51. package/dist/types.d.ts.map +1 -1
  52. package/dist/utils/config.d.ts +4 -0
  53. package/dist/utils/config.d.ts.map +1 -1
  54. package/dist/utils/config.js +2 -0
  55. package/dist/utils/config.js.map +1 -1
  56. package/dist/utils/prompt.d.ts +3 -0
  57. package/dist/utils/prompt.d.ts.map +1 -0
  58. package/dist/utils/prompt.js +14 -0
  59. package/dist/utils/prompt.js.map +1 -0
  60. package/package.json +2 -2
@@ -0,0 +1,484 @@
1
+ import fs from 'node:fs/promises';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { logger } from '../utils/logger.js';
5
+ import { getConfig } from '../utils/config.js';
6
+ import { sendDailySummaryToPhone } from '../notifications/ntfy-client.js';
7
+ import { sendDailySummaryToMac } from '../notifications/mac-notifier.js';
8
+ import { getActiveSessions } from '../sessions/session-manager.js';
9
+ import { findSessionFileForCwd, findSessionFileBySessionId, resolveProjectNameFromTranscript } from '../sessions/process-detector.js';
10
+ import { calculateTokenUsage } from '../sessions/token-calculator.js';
11
+ import { isTrackableClaudeSession } from './session-utils.js';
12
+ import { inferTaskCount, listTranscriptsForDate, timelineForStatsDate, } from './transcript-sync.js';
13
+ import { buildDailyStatsEvent } from './summary-formatter.js';
14
+ const MS_PER_DAY = 24 * 60 * 60 * 1000;
15
+ // Active sessions go quiet for long stretches between hook events (no
16
+ // permission prompts, not yet stopped) — poll their transcripts directly so
17
+ // the stats screen doesn't sit empty for the whole session.
18
+ const ACTIVE_SESSION_SYNC_INTERVAL_MS = 60_000;
19
+ const ACTIVE_SESSION_SYNC_INITIAL_DELAY_MS = 5_000;
20
+ export { isTrackableClaudeSession } from './session-utils.js';
21
+ function refreshDuration(stat, force = false) {
22
+ if (!force && stat.durationMs > 0)
23
+ return;
24
+ const end = stat.endTime ?? stat.lastActivityAt ?? stat.startTime;
25
+ const ms = end.getTime() - stat.startTime.getTime();
26
+ stat.durationMs = ms > 0 ? ms : 0;
27
+ }
28
+ function todayDateString() {
29
+ return new Date().toISOString().split('T')[0];
30
+ }
31
+ /** Parses persisted or in-memory values into a valid Date (Invalid Date → fallback). */
32
+ function coerceDate(value, fallback = new Date()) {
33
+ if (value instanceof Date && !Number.isNaN(value.getTime()))
34
+ return value;
35
+ if (value != null && value !== '') {
36
+ const parsed = new Date(value);
37
+ if (!Number.isNaN(parsed.getTime()))
38
+ return parsed;
39
+ }
40
+ return fallback;
41
+ }
42
+ function zeroedSessionStat(sessionId, projectName, agentType) {
43
+ return {
44
+ sessionId,
45
+ projectName,
46
+ agentType,
47
+ startTime: new Date(),
48
+ lastActivityAt: new Date(),
49
+ durationMs: 0,
50
+ inputTokens: 0,
51
+ outputTokens: 0,
52
+ cacheReadTokens: 0,
53
+ totalTokens: 0,
54
+ costUsd: 0,
55
+ tasksCompleted: 0,
56
+ filesModified: 0,
57
+ permissionPrompts: 0,
58
+ permissionsApproved: 0,
59
+ permissionsDenied: 0,
60
+ };
61
+ }
62
+ function projectMergeKey(stat) {
63
+ if (stat.projectName && stat.projectName !== '.') {
64
+ return stat.projectName;
65
+ }
66
+ return stat.sessionId;
67
+ }
68
+ /** Rolls up multiple Claude sessions in the same project into one stats row for the phone. */
69
+ export function mergeSessionsByProject(sessions) {
70
+ const merged = new Map();
71
+ for (const s of sessions) {
72
+ const key = projectMergeKey(s);
73
+ const existing = merged.get(key);
74
+ if (!existing) {
75
+ merged.set(key, { ...s });
76
+ continue;
77
+ }
78
+ if (s.startTime < existing.startTime)
79
+ existing.startTime = s.startTime;
80
+ if (!s.endTime) {
81
+ existing.endTime = undefined;
82
+ }
83
+ else if (!existing.endTime || s.endTime > existing.endTime) {
84
+ existing.endTime = s.endTime;
85
+ }
86
+ if (s.lastActivityAt > existing.lastActivityAt)
87
+ existing.lastActivityAt = s.lastActivityAt;
88
+ existing.durationMs += s.durationMs;
89
+ existing.inputTokens += s.inputTokens;
90
+ existing.outputTokens += s.outputTokens;
91
+ existing.cacheReadTokens += s.cacheReadTokens;
92
+ existing.totalTokens += s.totalTokens;
93
+ existing.costUsd += s.costUsd;
94
+ existing.tasksCompleted += s.tasksCompleted;
95
+ existing.filesModified += s.filesModified;
96
+ existing.permissionPrompts += s.permissionPrompts;
97
+ existing.permissionsApproved += s.permissionsApproved;
98
+ existing.permissionsDenied += s.permissionsDenied;
99
+ }
100
+ for (const [key, stat] of merged) {
101
+ if (stat.projectName && stat.projectName !== '.') {
102
+ stat.sessionId = `project:${key}`;
103
+ }
104
+ refreshDuration(stat, true);
105
+ }
106
+ return [...merged.values()];
107
+ }
108
+ /**
109
+ * Tracks coding-session activity throughout the day and sends an end-of-day
110
+ * summary to the phone (ntfy) and Mac (native notification).
111
+ *
112
+ * `agentvigil hook <type>` runs as a short-lived CLI process separate from
113
+ * the long-running daemon, so every public method reloads `stats.json`
114
+ * before mutating and saves immediately after — this is how state survives
115
+ * across those separate processes.
116
+ */
117
+ class DailyTracker {
118
+ statsFilePath;
119
+ todayStats = new Map();
120
+ broadcaster;
121
+ constructor(statsFilePath = path.join(os.homedir(), '.agentvigil', 'stats.json')) {
122
+ this.statsFilePath = statsFilePath;
123
+ }
124
+ async initialize(broadcaster) {
125
+ this.broadcaster = broadcaster;
126
+ await this.loadFromDisk();
127
+ if (this.purgeInvalidSessions()) {
128
+ await this.saveToDisk();
129
+ logger.info('Removed non-Claude session entries from daily stats');
130
+ }
131
+ await this.backfillMissingProjectNames();
132
+ await this.reconcileFromTranscripts();
133
+ this.scheduleEndOfDaySummary();
134
+ this.scheduleMidnightReset();
135
+ this.scheduleActiveSessionSync();
136
+ }
137
+ async trackSessionStart(sessionId, projectName, agentType) {
138
+ if (!isTrackableClaudeSession(sessionId))
139
+ return;
140
+ await this.loadFromDisk();
141
+ if (this.todayStats.has(sessionId))
142
+ return;
143
+ this.todayStats.set(sessionId, zeroedSessionStat(sessionId, projectName, agentType));
144
+ await this.saveToDisk();
145
+ this.broadcastStatsUpdate();
146
+ }
147
+ /** True if `sessionId` already has a tracked stat for today (in-memory). */
148
+ hasSession(sessionId) {
149
+ return this.todayStats.has(sessionId);
150
+ }
151
+ /** Called when a session's token usage/cost/files-modified is known (e.g. from the Stop hook). */
152
+ async updateTokenUsage(sessionId, usage, lastActivity, transcriptPath) {
153
+ if (!isTrackableClaudeSession(sessionId))
154
+ return;
155
+ await this.loadFromDisk();
156
+ const stat = this.todayStats.get(sessionId);
157
+ if (!stat)
158
+ return;
159
+ await this.ensureProjectName(stat, transcriptPath);
160
+ stat.lastActivityAt = coerceDate(lastActivity, stat.lastActivityAt ?? stat.endTime ?? stat.startTime);
161
+ if (usage.totalTokens > 0) {
162
+ stat.inputTokens = usage.inputTokens;
163
+ stat.outputTokens = usage.outputTokens;
164
+ stat.cacheReadTokens = usage.cacheReadTokens;
165
+ stat.totalTokens = usage.totalTokens;
166
+ stat.costUsd = usage.estimatedCostUsd;
167
+ stat.filesModified = usage.filesModified;
168
+ }
169
+ if (transcriptPath) {
170
+ await this.applyTranscriptTimeline(stat, transcriptPath, usage.totalTokens);
171
+ }
172
+ else {
173
+ refreshDuration(stat);
174
+ }
175
+ await this.saveToDisk();
176
+ this.broadcastStatsUpdate();
177
+ }
178
+ /** Called when a permission prompt fires. */
179
+ async trackPermission(sessionId) {
180
+ if (!isTrackableClaudeSession(sessionId))
181
+ return;
182
+ await this.loadFromDisk();
183
+ const stat = this.todayStats.get(sessionId);
184
+ if (!stat)
185
+ return;
186
+ stat.permissionPrompts++;
187
+ await this.saveToDisk();
188
+ this.broadcastStatsUpdate();
189
+ }
190
+ /** Called when a permission prompt is approved from the phone. */
191
+ async trackApproval(sessionId) {
192
+ if (!isTrackableClaudeSession(sessionId))
193
+ return;
194
+ await this.loadFromDisk();
195
+ const stat = this.todayStats.get(sessionId);
196
+ if (!stat)
197
+ return;
198
+ stat.permissionsApproved++;
199
+ await this.saveToDisk();
200
+ this.broadcastStatsUpdate();
201
+ }
202
+ /** Called when a permission prompt is denied from the phone. */
203
+ async trackDenial(sessionId) {
204
+ if (!isTrackableClaudeSession(sessionId))
205
+ return;
206
+ await this.loadFromDisk();
207
+ const stat = this.todayStats.get(sessionId);
208
+ if (!stat)
209
+ return;
210
+ stat.permissionsDenied++;
211
+ await this.saveToDisk();
212
+ this.broadcastStatsUpdate();
213
+ }
214
+ /** Called when the Stop hook fires for a session. */
215
+ async trackSessionEnd(sessionId, usage, transcriptPath) {
216
+ if (!isTrackableClaudeSession(sessionId))
217
+ return;
218
+ await this.loadFromDisk();
219
+ const stat = this.todayStats.get(sessionId);
220
+ if (!stat)
221
+ return;
222
+ await this.ensureProjectName(stat, transcriptPath);
223
+ stat.endTime = new Date();
224
+ stat.lastActivityAt = stat.endTime;
225
+ stat.durationMs = stat.endTime.getTime() - stat.startTime.getTime();
226
+ stat.tasksCompleted++;
227
+ if (usage && usage.totalTokens > 0) {
228
+ stat.inputTokens = usage.inputTokens;
229
+ stat.outputTokens = usage.outputTokens;
230
+ stat.cacheReadTokens = usage.cacheReadTokens;
231
+ stat.totalTokens = usage.totalTokens;
232
+ stat.costUsd = usage.estimatedCostUsd;
233
+ stat.filesModified = usage.filesModified;
234
+ }
235
+ await this.saveToDisk();
236
+ this.broadcastStatsUpdate();
237
+ }
238
+ /** Pushes the current daily summary to the phone over the live WS tunnel, if connected. */
239
+ broadcastStatsUpdate() {
240
+ if (!this.broadcaster?.isPhoneConnected)
241
+ return;
242
+ try {
243
+ this.broadcaster.sendEvent(buildDailyStatsEvent(this.buildDailySummary()));
244
+ }
245
+ catch (err) {
246
+ logger.warn('Failed to broadcast daily stats update', err);
247
+ }
248
+ }
249
+ buildDailySummary() {
250
+ for (const stat of this.todayStats.values()) {
251
+ refreshDuration(stat);
252
+ }
253
+ const sessions = mergeSessionsByProject(Array.from(this.todayStats.values()));
254
+ const topProject = sessions.reduce((top, s) => (s.costUsd > (top?.costUsd ?? 0) ? s : top), undefined);
255
+ return {
256
+ date: todayDateString(),
257
+ totalSessions: sessions.length,
258
+ totalActiveTimeMs: sessions.reduce((s, x) => s + x.durationMs, 0),
259
+ totalInputTokens: sessions.reduce((s, x) => s + x.inputTokens, 0),
260
+ totalOutputTokens: sessions.reduce((s, x) => s + x.outputTokens, 0),
261
+ totalCacheReadTokens: sessions.reduce((s, x) => s + x.cacheReadTokens, 0),
262
+ totalTokens: sessions.reduce((s, x) => s + x.totalTokens, 0),
263
+ totalCostUsd: sessions.reduce((s, x) => s + x.costUsd, 0),
264
+ totalTasksCompleted: sessions.reduce((s, x) => s + x.tasksCompleted, 0),
265
+ totalFilesModified: sessions.reduce((s, x) => s + x.filesModified, 0),
266
+ totalPermissionPrompts: sessions.reduce((s, x) => s + x.permissionPrompts, 0),
267
+ permissionsApproved: sessions.reduce((s, x) => s + x.permissionsApproved, 0),
268
+ permissionsDenied: sessions.reduce((s, x) => s + x.permissionsDenied, 0),
269
+ topProject: topProject?.projectName ?? 'none',
270
+ topProjectCost: topProject?.costUsd ?? 0,
271
+ topProjectTimeMs: topProject?.durationMs ?? 0,
272
+ sessions,
273
+ generatedAt: new Date(),
274
+ };
275
+ }
276
+ async sendDailySummary() {
277
+ const summary = this.buildDailySummary();
278
+ if (summary.totalSessions === 0) {
279
+ logger.dim('No sessions today — skipping daily summary');
280
+ return;
281
+ }
282
+ const config = await getConfig();
283
+ logger.info('Sending daily summary...');
284
+ await Promise.all([
285
+ sendDailySummaryToPhone(config.ntfy_topic, summary),
286
+ sendDailySummaryToMac(summary),
287
+ ]);
288
+ logger.success('Daily summary sent');
289
+ }
290
+ async scheduleEndOfDaySummary() {
291
+ const config = await getConfig();
292
+ const summaryHour = config.dailySummaryHour ?? 23;
293
+ const summaryMinute = config.dailySummaryMinute ?? 59;
294
+ const now = new Date();
295
+ const target = new Date();
296
+ target.setHours(summaryHour, summaryMinute, 0, 0);
297
+ // If today's slot already passed, schedule for tomorrow.
298
+ if (target <= now) {
299
+ target.setDate(target.getDate() + 1);
300
+ }
301
+ const msUntilSummary = target.getTime() - now.getTime();
302
+ logger.info(`Daily summary scheduled for ${target.toLocaleTimeString()}`);
303
+ setTimeout(() => {
304
+ void this.sendDailySummary();
305
+ setInterval(() => void this.sendDailySummary(), MS_PER_DAY);
306
+ }, msUntilSummary);
307
+ }
308
+ /**
309
+ * Polls every active session's transcript so the stats screen reflects
310
+ * running sessions, not just ones that have fired a hook. Runs once
311
+ * shortly after startup, then every ACTIVE_SESSION_SYNC_INTERVAL_MS.
312
+ */
313
+ scheduleActiveSessionSync() {
314
+ setTimeout(() => {
315
+ void syncActiveSessionStats();
316
+ setInterval(() => void syncActiveSessionStats(), ACTIVE_SESSION_SYNC_INTERVAL_MS);
317
+ }, ACTIVE_SESSION_SYNC_INITIAL_DELAY_MS);
318
+ }
319
+ scheduleMidnightReset() {
320
+ const now = new Date();
321
+ const midnight = new Date();
322
+ midnight.setHours(24, 0, 0, 0);
323
+ const msUntilMidnight = midnight.getTime() - now.getTime();
324
+ setTimeout(() => {
325
+ void this.resetForNewDay();
326
+ setInterval(() => void this.resetForNewDay(), MS_PER_DAY);
327
+ }, msUntilMidnight);
328
+ }
329
+ async resetForNewDay() {
330
+ logger.info('Midnight reset — clearing daily stats');
331
+ this.todayStats.clear();
332
+ await this.saveToDisk();
333
+ }
334
+ async applyTranscriptTimeline(stat, transcriptPath, totalTokens) {
335
+ const timeline = await timelineForStatsDate(transcriptPath, todayDateString());
336
+ if (timeline.firstActivity) {
337
+ stat.startTime = timeline.firstActivity;
338
+ }
339
+ if (timeline.lastActivity) {
340
+ stat.lastActivityAt = timeline.lastActivity;
341
+ if (timeline.stopCount > 0) {
342
+ stat.endTime = timeline.lastActivity;
343
+ }
344
+ }
345
+ const tasks = inferTaskCount(timeline.stopCount, totalTokens);
346
+ if (tasks > stat.tasksCompleted)
347
+ stat.tasksCompleted = tasks;
348
+ refreshDuration(stat);
349
+ }
350
+ /** Scans today's transcripts so every project with Claude activity appears in stats. */
351
+ async reconcileFromTranscriptsPublic() {
352
+ await this.loadFromDisk();
353
+ await this.reconcileFromTranscripts();
354
+ this.broadcastStatsUpdate();
355
+ }
356
+ /** Scans today's transcripts so every project with Claude activity appears in stats. */
357
+ async reconcileFromTranscripts() {
358
+ const date = todayDateString();
359
+ const transcripts = await listTranscriptsForDate(date);
360
+ let changed = false;
361
+ for (const { sessionId, filePath } of transcripts) {
362
+ let stat = this.todayStats.get(sessionId);
363
+ if (!stat) {
364
+ const projectName = (await resolveProjectNameFromTranscript(filePath)) ?? '';
365
+ stat = zeroedSessionStat(sessionId, projectName, 'claude-code');
366
+ this.todayStats.set(sessionId, stat);
367
+ changed = true;
368
+ }
369
+ await this.ensureProjectName(stat, filePath);
370
+ const usage = await calculateTokenUsage(filePath);
371
+ if (usage.totalTokens > 0) {
372
+ stat.inputTokens = usage.inputTokens;
373
+ stat.outputTokens = usage.outputTokens;
374
+ stat.cacheReadTokens = usage.cacheReadTokens;
375
+ stat.totalTokens = usage.totalTokens;
376
+ stat.costUsd = usage.estimatedCostUsd;
377
+ stat.filesModified = usage.filesModified;
378
+ changed = true;
379
+ }
380
+ await this.applyTranscriptTimeline(stat, filePath, usage.totalTokens);
381
+ refreshDuration(stat);
382
+ changed = true;
383
+ }
384
+ if (changed) {
385
+ await this.saveToDisk();
386
+ logger.info(`Reconciled daily stats from ${transcripts.length} transcript(s)`);
387
+ }
388
+ }
389
+ async ensureProjectName(stat, transcriptPath) {
390
+ if (stat.projectName && stat.projectName !== '.')
391
+ return;
392
+ const filePath = transcriptPath
393
+ ?? (await findSessionFileBySessionId(stat.sessionId))?.filePath;
394
+ if (!filePath)
395
+ return;
396
+ const name = await resolveProjectNameFromTranscript(filePath);
397
+ if (name)
398
+ stat.projectName = name;
399
+ }
400
+ async backfillMissingProjectNames() {
401
+ let changed = false;
402
+ for (const stat of this.todayStats.values()) {
403
+ const before = stat.projectName;
404
+ await this.ensureProjectName(stat);
405
+ if (stat.projectName !== before)
406
+ changed = true;
407
+ }
408
+ if (changed) {
409
+ await this.saveToDisk();
410
+ logger.info('Backfilled missing project names in daily stats');
411
+ }
412
+ }
413
+ purgeInvalidSessions() {
414
+ let removed = false;
415
+ for (const id of [...this.todayStats.keys()]) {
416
+ if (!isTrackableClaudeSession(id)) {
417
+ this.todayStats.delete(id);
418
+ removed = true;
419
+ }
420
+ }
421
+ return removed;
422
+ }
423
+ async loadFromDisk() {
424
+ try {
425
+ const raw = await fs.readFile(this.statsFilePath, 'utf-8');
426
+ const data = JSON.parse(raw);
427
+ const today = todayDateString();
428
+ if (data.date === today && Array.isArray(data.sessions)) {
429
+ for (const s of data.sessions) {
430
+ if (!isTrackableClaudeSession(s.sessionId))
431
+ continue;
432
+ s.startTime = coerceDate(s.startTime);
433
+ if (s.endTime != null)
434
+ s.endTime = coerceDate(s.endTime, s.startTime);
435
+ s.lastActivityAt = coerceDate(s.lastActivityAt, s.endTime ?? s.startTime);
436
+ this.todayStats.set(s.sessionId, s);
437
+ }
438
+ }
439
+ this.purgeInvalidSessions();
440
+ }
441
+ catch {
442
+ // No stats file yet, or it's malformed/stale — start fresh.
443
+ }
444
+ }
445
+ async saveToDisk() {
446
+ try {
447
+ await fs.mkdir(path.dirname(this.statsFilePath), { recursive: true });
448
+ await fs.writeFile(this.statsFilePath, JSON.stringify({
449
+ date: todayDateString(),
450
+ sessions: Array.from(this.todayStats.values()),
451
+ }, null, 2));
452
+ }
453
+ catch (err) {
454
+ logger.warn('Failed to save daily stats', err);
455
+ }
456
+ }
457
+ }
458
+ export { DailyTracker };
459
+ export const dailyTracker = new DailyTracker();
460
+ /**
461
+ * Brings today's stats up to date for every currently-active session,
462
+ * regardless of whether a hook has fired for it yet — a long `working`
463
+ * session can otherwise go hours without appearing on the stats screen.
464
+ */
465
+ export async function syncActiveSessionStats() {
466
+ await dailyTracker.reconcileFromTranscriptsPublic();
467
+ for (const session of getActiveSessions()) {
468
+ if (!isTrackableClaudeSession(session.session_id, session.cwd))
469
+ continue;
470
+ const fileInfo = (await findSessionFileBySessionId(session.session_id))
471
+ ?? (session.cwd ? await findSessionFileForCwd(session.cwd) : null);
472
+ if (!fileInfo)
473
+ continue;
474
+ if (!dailyTracker.hasSession(session.session_id)) {
475
+ const projectName = session.project_name && session.project_name !== '.'
476
+ ? session.project_name
477
+ : (await resolveProjectNameFromTranscript(fileInfo.filePath)) ?? session.project_name;
478
+ await dailyTracker.trackSessionStart(session.session_id, projectName, session.agent);
479
+ }
480
+ const usage = await calculateTokenUsage(fileInfo.filePath);
481
+ await dailyTracker.updateTokenUsage(session.session_id, usage, session.last_activity, fileInfo.filePath);
482
+ }
483
+ }
484
+ //# sourceMappingURL=daily-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daily-tracker.js","sourceRoot":"","sources":["../../src/stats/daily-tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function isTrackableClaudeSession(sessionId: string, cwd?: string): boolean;
2
+ //# sourceMappingURL=session-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-utils.d.ts","sourceRoot":"","sources":["../../src/stats/session-utils.ts"],"names":[],"mappings":"AAKA,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAIjF"}
@@ -0,0 +1,11 @@
1
+ import { isBlocklisted } from '../sessions/session-watcher.js';
2
+ /** Claude Code names transcript files `{uuid}.jsonl` — reject test/dev ids like "abc123". */
3
+ const CLAUDE_SESSION_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
4
+ export function isTrackableClaudeSession(sessionId, cwd) {
5
+ if (!CLAUDE_SESSION_ID.test(sessionId))
6
+ return false;
7
+ if (cwd && isBlocklisted(cwd))
8
+ return false;
9
+ return true;
10
+ }
11
+ //# sourceMappingURL=session-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-utils.js","sourceRoot":"","sources":["../../src/stats/session-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAE/D,6FAA6F;AAC7F,MAAM,iBAAiB,GAAG,iEAAiE,CAAC;AAE5F,MAAM,UAAU,wBAAwB,CAAC,SAAiB,EAAE,GAAY;IACtE,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC;QAAE,OAAO,KAAK,CAAC;IACrD,IAAI,GAAG,IAAI,aAAa,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5C,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,67 @@
1
+ import type { DailySummary } from './daily-tracker.js';
2
+ import type { AgentEvent } from '../types.js';
3
+ export interface PhoneSummaryText {
4
+ title: string;
5
+ }
6
+ /**
7
+ * `Title` is sent as an ntfy HTTP header, which must be Latin-1 — keep it
8
+ * emoji-free. The real notification text is rendered client-side by the
9
+ * Flutter app from the JSON payload (see `buildSummaryPayload`).
10
+ */
11
+ export declare function formatSummaryForPhone(summary: DailySummary): PhoneSummaryText;
12
+ export interface MacSummaryText {
13
+ title: string;
14
+ subtitle: string;
15
+ body: string;
16
+ }
17
+ export declare function formatSummaryForMac(summary: DailySummary): MacSummaryText;
18
+ export interface SessionSummaryWire {
19
+ session_id: string;
20
+ project: string;
21
+ agent: string;
22
+ start_time: string;
23
+ end_time: string | null;
24
+ last_activity: string;
25
+ duration_ms: number;
26
+ input_tokens: number;
27
+ output_tokens: number;
28
+ tokens: number;
29
+ cost_usd: number;
30
+ tasks: number;
31
+ }
32
+ /** Wire shape shared by the once-daily ntfy payload and the live WS broadcast. */
33
+ export interface DailySummaryWirePayload {
34
+ type: 'daily_summary';
35
+ date: string;
36
+ total_sessions: number;
37
+ total_active_time_ms: number;
38
+ total_input_tokens: number;
39
+ total_output_tokens: number;
40
+ total_cache_read_tokens: number;
41
+ total_tokens: number;
42
+ total_cost_usd: number;
43
+ /** Human-readable usage line for subscription users — not a dollar bill. */
44
+ usage_summary: string;
45
+ cost_label: string;
46
+ cost_note: string;
47
+ cost_is_api_estimate: boolean;
48
+ total_tasks_completed: number;
49
+ total_files_modified: number;
50
+ total_permission_prompts: number;
51
+ permissions_approved: number;
52
+ permissions_denied: number;
53
+ average_tokens_per_session: number;
54
+ average_spend_per_session: number;
55
+ top_project: string;
56
+ top_project_cost: number;
57
+ top_project_time_ms: number;
58
+ sessions: SessionSummaryWire[];
59
+ generated_at: string;
60
+ }
61
+ /** Builds the wire shape shared by the once-daily ntfy payload and the live WS broadcast. */
62
+ export declare function buildSummaryObject(summary: DailySummary): DailySummaryWirePayload;
63
+ /** JSON payload sent as the ntfy message body — parsed by the Flutter app's `DailySummary.fromJson`. */
64
+ export declare function buildSummaryPayload(summary: DailySummary): string;
65
+ /** Live WS event broadcast to the phone whenever today's stats change. */
66
+ export declare function buildDailyStatsEvent(summary: DailySummary): AgentEvent;
67
+ //# sourceMappingURL=summary-formatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summary-formatter.d.ts","sourceRoot":"","sources":["../../src/stats/summary-formatter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAyB9C,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,YAAY,GAAG,gBAAgB,CAK7E;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,cAAc,CAwBzE;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,kFAAkF;AAClF,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,uBAAuB,EAAE,MAAM,CAAC;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,4EAA4E;IAC5E,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,wBAAwB,EAAE,MAAM,CAAC;IACjC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,0BAA0B,EAAE,MAAM,CAAC;IACnC,yBAAyB,EAAE,MAAM,CAAC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,kBAAkB,EAAE,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,6FAA6F;AAC7F,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,YAAY,GAAG,uBAAuB,CA4CjF;AAED,wGAAwG;AACxG,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAEjE;AAED,0EAA0E;AAC1E,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,UAAU,CAWtE"}