@newrelic/preflight 1.71.0 → 1.72.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 (152) hide show
  1. package/dist/dashboard/routes/api-handler.d.ts.map +1 -1
  2. package/dist/dashboard/routes/api-handler.js +2 -9
  3. package/dist/dashboard/routes/api-handler.js.map +1 -1
  4. package/dist/dashboard/subagent-timeline-store.d.ts +12 -1
  5. package/dist/dashboard/subagent-timeline-store.d.ts.map +1 -1
  6. package/dist/dashboard/subagent-timeline-store.js +32 -4
  7. package/dist/dashboard/subagent-timeline-store.js.map +1 -1
  8. package/dist/dashboard/workflow-store.d.ts.map +1 -1
  9. package/dist/dashboard/workflow-store.js +2 -3
  10. package/dist/dashboard/workflow-store.js.map +1 -1
  11. package/dist/hooks/event-processor.d.ts +20 -5
  12. package/dist/hooks/event-processor.d.ts.map +1 -1
  13. package/dist/hooks/event-processor.js +135 -39
  14. package/dist/hooks/event-processor.js.map +1 -1
  15. package/dist/hooks/index.d.ts +1 -1
  16. package/dist/hooks/index.d.ts.map +1 -1
  17. package/dist/hooks/index.js +1 -1
  18. package/dist/hooks/index.js.map +1 -1
  19. package/dist/hooks/parent-transcript-watcher.d.ts +1 -1
  20. package/dist/hooks/parent-transcript-watcher.d.ts.map +1 -1
  21. package/dist/hooks/parent-transcript-watcher.js +6 -2
  22. package/dist/hooks/parent-transcript-watcher.js.map +1 -1
  23. package/dist/hooks/session-resolver.d.ts.map +1 -1
  24. package/dist/hooks/session-resolver.js +2 -1
  25. package/dist/hooks/session-resolver.js.map +1 -1
  26. package/dist/hooks/subagent-watcher.d.ts +3 -1
  27. package/dist/hooks/subagent-watcher.d.ts.map +1 -1
  28. package/dist/hooks/subagent-watcher.js +6 -4
  29. package/dist/hooks/subagent-watcher.js.map +1 -1
  30. package/dist/hooks/workflow-watcher.d.ts.map +1 -1
  31. package/dist/hooks/workflow-watcher.js +2 -2
  32. package/dist/hooks/workflow-watcher.js.map +1 -1
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +53 -60
  35. package/dist/index.js.map +1 -1
  36. package/dist/install/cli.d.ts.map +1 -1
  37. package/dist/install/cli.js +81 -7
  38. package/dist/install/cli.js.map +1 -1
  39. package/dist/install/copilot-install-helper.d.ts +1 -0
  40. package/dist/install/copilot-install-helper.d.ts.map +1 -1
  41. package/dist/install/copilot-install-helper.js +82 -26
  42. package/dist/install/copilot-install-helper.js.map +1 -1
  43. package/dist/install/diagnostics.d.ts.map +1 -1
  44. package/dist/install/diagnostics.js +6 -3
  45. package/dist/install/diagnostics.js.map +1 -1
  46. package/dist/install/install-helper.d.ts +9 -0
  47. package/dist/install/install-helper.d.ts.map +1 -1
  48. package/dist/install/install-helper.js +42 -17
  49. package/dist/install/install-helper.js.map +1 -1
  50. package/dist/install/schedule.d.ts.map +1 -1
  51. package/dist/install/schedule.js +4 -1
  52. package/dist/install/schedule.js.map +1 -1
  53. package/dist/install/target-user.d.ts +33 -0
  54. package/dist/install/target-user.d.ts.map +1 -0
  55. package/dist/install/target-user.js +121 -0
  56. package/dist/install/target-user.js.map +1 -0
  57. package/dist/lib/claude-config-dir.d.ts +3 -0
  58. package/dist/lib/claude-config-dir.d.ts.map +1 -0
  59. package/dist/lib/claude-config-dir.js +10 -0
  60. package/dist/lib/claude-config-dir.js.map +1 -0
  61. package/dist/lib/claude-settings-env.d.ts +18 -0
  62. package/dist/lib/claude-settings-env.d.ts.map +1 -0
  63. package/dist/lib/claude-settings-env.js +78 -0
  64. package/dist/lib/claude-settings-env.js.map +1 -0
  65. package/dist/lib/date.d.ts +7 -0
  66. package/dist/lib/date.d.ts.map +1 -1
  67. package/dist/lib/date.js +11 -1
  68. package/dist/lib/date.js.map +1 -1
  69. package/dist/lib/subagent-transcript-parser.d.ts +2 -0
  70. package/dist/lib/subagent-transcript-parser.d.ts.map +1 -1
  71. package/dist/lib/subagent-transcript-parser.js +5 -0
  72. package/dist/lib/subagent-transcript-parser.js.map +1 -1
  73. package/dist/lib/transcript-types.d.ts +4 -0
  74. package/dist/lib/transcript-types.d.ts.map +1 -1
  75. package/dist/metrics/cost-forecast.d.ts +2 -0
  76. package/dist/metrics/cost-forecast.d.ts.map +1 -1
  77. package/dist/metrics/cost-forecast.js +46 -24
  78. package/dist/metrics/cost-forecast.js.map +1 -1
  79. package/dist/metrics/cost-tracker.d.ts +3 -3
  80. package/dist/metrics/cost-tracker.js +3 -3
  81. package/dist/metrics/efficiency-score.d.ts +2 -2
  82. package/dist/metrics/efficiency-score.js +2 -2
  83. package/dist/metrics/first-save-baselines.d.ts +60 -0
  84. package/dist/metrics/first-save-baselines.d.ts.map +1 -0
  85. package/dist/metrics/first-save-baselines.js +77 -0
  86. package/dist/metrics/first-save-baselines.js.map +1 -0
  87. package/dist/metrics/local-session-aggregator.d.ts +2 -1
  88. package/dist/metrics/local-session-aggregator.d.ts.map +1 -1
  89. package/dist/metrics/local-session-aggregator.js +21 -0
  90. package/dist/metrics/local-session-aggregator.js.map +1 -1
  91. package/dist/metrics/model-pricing.d.ts +1 -1
  92. package/dist/metrics/model-pricing.d.ts.map +1 -1
  93. package/dist/metrics/model-pricing.js +2 -2
  94. package/dist/metrics/model-pricing.js.map +1 -1
  95. package/dist/metrics/model-usage-tracker.d.ts +2 -2
  96. package/dist/metrics/model-usage-tracker.js +2 -2
  97. package/dist/metrics/pricing-init.d.ts.map +1 -1
  98. package/dist/metrics/pricing-init.js +5 -3
  99. package/dist/metrics/pricing-init.js.map +1 -1
  100. package/dist/metrics/pricing-overlay.d.ts.map +1 -1
  101. package/dist/metrics/pricing-overlay.js +1 -4
  102. package/dist/metrics/pricing-overlay.js.map +1 -1
  103. package/dist/metrics/pricing-refresh.d.ts +16 -4
  104. package/dist/metrics/pricing-refresh.d.ts.map +1 -1
  105. package/dist/metrics/pricing-refresh.js +47 -1
  106. package/dist/metrics/pricing-refresh.js.map +1 -1
  107. package/dist/metrics/quality-proxy-tracker.d.ts +2 -2
  108. package/dist/metrics/quality-proxy-tracker.js +2 -2
  109. package/dist/metrics/session-tracker.d.ts +5 -1
  110. package/dist/metrics/session-tracker.d.ts.map +1 -1
  111. package/dist/metrics/session-tracker.js +58 -17
  112. package/dist/metrics/session-tracker.js.map +1 -1
  113. package/dist/metrics/task-detector.d.ts +2 -2
  114. package/dist/metrics/task-detector.js +2 -2
  115. package/dist/metrics/token-usage.d.ts +6 -0
  116. package/dist/metrics/token-usage.d.ts.map +1 -0
  117. package/dist/metrics/token-usage.js +34 -0
  118. package/dist/metrics/token-usage.js.map +1 -0
  119. package/dist/metrics/turn-cost-attributor.d.ts.map +1 -1
  120. package/dist/metrics/turn-cost-attributor.js +3 -0
  121. package/dist/metrics/turn-cost-attributor.js.map +1 -1
  122. package/dist/platforms/copilot-adapter.d.ts.map +1 -1
  123. package/dist/platforms/copilot-adapter.js +3 -0
  124. package/dist/platforms/copilot-adapter.js.map +1 -1
  125. package/dist/platforms/copilot-sdk-adapter.d.ts.map +1 -1
  126. package/dist/platforms/copilot-sdk-adapter.js +3 -0
  127. package/dist/platforms/copilot-sdk-adapter.js.map +1 -1
  128. package/dist/storage/drain-claims.d.ts +33 -10
  129. package/dist/storage/drain-claims.d.ts.map +1 -1
  130. package/dist/storage/drain-claims.js +78 -13
  131. package/dist/storage/drain-claims.js.map +1 -1
  132. package/dist/storage/local-store.d.ts +21 -0
  133. package/dist/storage/local-store.d.ts.map +1 -1
  134. package/dist/storage/local-store.js +118 -19
  135. package/dist/storage/local-store.js.map +1 -1
  136. package/dist/storage/retention.d.ts.map +1 -1
  137. package/dist/storage/retention.js +7 -6
  138. package/dist/storage/retention.js.map +1 -1
  139. package/dist/storage/session-store.d.ts +16 -2
  140. package/dist/storage/session-store.d.ts.map +1 -1
  141. package/dist/storage/session-store.js +242 -37
  142. package/dist/storage/session-store.js.map +1 -1
  143. package/dist/storage/types.d.ts +7 -0
  144. package/dist/storage/types.d.ts.map +1 -1
  145. package/dist/storage/types.js +4 -0
  146. package/dist/storage/types.js.map +1 -1
  147. package/dist/tools/cost-tools.d.ts.map +1 -1
  148. package/dist/tools/cost-tools.js +1 -0
  149. package/dist/tools/cost-tools.js.map +1 -1
  150. package/dist/web/assets/{index-U9DPZ-Tb.js → index-CZvLy2Qy.js} +2 -2
  151. package/dist/web/index.html +1 -1
  152. package/package.json +4 -1
@@ -2,12 +2,13 @@ import { readdirSync, statSync, unlinkSync } from 'node:fs';
2
2
  import { resolve } from 'node:path';
3
3
  import { createLogger } from '../shared/index.js';
4
4
  const logger = createLogger('retention');
5
+ const PURGED_SUFFIXES = ['.json', '.corrupt', '.tmp'];
5
6
  /**
6
- * Delete every `.json` file in `<storagePath>/<subdir>` whose mtime is older
7
- * than `retainDays`. Shared by `purgeOldSessions` and
7
+ * Delete every `PURGED_SUFFIXES` file in `<storagePath>/<subdir>` whose mtime
8
+ * is older than `retainDays`. Shared by `purgeOldSessions` and
8
9
  * `purgeOldWeeklySummaries` — only the subdirectory and log label differ.
9
10
  */
10
- function purgeOldJsonFiles(storagePath, subdir, retainDays, fileKind) {
11
+ function purgeOldFiles(storagePath, subdir, retainDays, fileKind) {
11
12
  const dir = resolve(storagePath, subdir);
12
13
  // Files are deleted if mtime < cutoff. Files exactly at the cutoff (rare in practice) are retained.
13
14
  const cutoffMs = Date.now() - retainDays * 24 * 60 * 60 * 1000;
@@ -20,7 +21,7 @@ function purgeOldJsonFiles(storagePath, subdir, retainDays, fileKind) {
20
21
  return 0; // directory doesn't exist yet
21
22
  }
22
23
  for (const file of files) {
23
- if (!file.endsWith('.json'))
24
+ if (!PURGED_SUFFIXES.some((suffix) => file.endsWith(suffix)))
24
25
  continue;
25
26
  const fullPath = resolve(dir, file);
26
27
  try {
@@ -56,9 +57,9 @@ function purgeOldJsonFiles(storagePath, subdir, retainDays, fileKind) {
56
57
  return deletedCount;
57
58
  }
58
59
  export function purgeOldSessions(storagePath, retainDays) {
59
- return purgeOldJsonFiles(storagePath, 'sessions', retainDays, 'session');
60
+ return purgeOldFiles(storagePath, 'sessions', retainDays, 'session');
60
61
  }
61
62
  export function purgeOldWeeklySummaries(storagePath, retainDays) {
62
- return purgeOldJsonFiles(storagePath, 'weekly_summaries', retainDays, 'weekly summary');
63
+ return purgeOldFiles(storagePath, 'weekly_summaries', retainDays, 'weekly summary');
63
64
  }
64
65
  //# sourceMappingURL=retention.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"retention.js","sourceRoot":"","sources":["../../src/storage/retention.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"retention.js","sourceRoot":"","sources":["../../src/storage/retention.ts"],"names":[],"mappings":"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"}
@@ -285,9 +285,23 @@ export declare class SessionStore {
285
285
  storagePath: string;
286
286
  });
287
287
  getSessionsDir(): string;
288
- saveSession(summary: FullSessionSummary): void;
288
+ /**
289
+ * Returns null when nothing was written, else the file the write merged
290
+ * against (`previous`, null for a new file).
291
+ */
292
+ saveSession(summary: FullSessionSummary): {
293
+ readonly previous: FullSessionSummary | null;
294
+ } | null;
289
295
  loadSession(sessionId: string): FullSessionSummary | null;
290
- /** Like loadSession(), but also returns the file path it was loaded from — used by saveSession() to detect and clean up a stale file after a merge relocates a session to a different filename. */
296
+ /**
297
+ * Like loadSession(), but also returns the file path it was loaded from — used by saveSession() to detect and clean up a stale file after a merge relocates a session to a different filename.
298
+ *
299
+ * An unreadable file is skipped rather than ending the search: returning null
300
+ * there made saveSession() treat the session as new and start a fresh file
301
+ * on every later save. Sibling files for one id are not merged here,
302
+ * because files split that way hold disjoint activity that mergeSummaries'
303
+ * per-counter max would drop.
304
+ */
291
305
  private loadSessionWithPath;
292
306
  listSessions(options?: ListSessionsOptions): SessionFileInfo[];
293
307
  loadAllSessions(options?: LoadSessionsOptions): FullSessionSummary[];
@@ -1 +1 @@
1
- {"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../../src/storage/session-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../../src/storage/session-store.ts"],"names":[],"mappings":"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"}
@@ -11,8 +11,9 @@
11
11
  * `buildSessionSummary()` pulls getMetrics() from each tracker and aggregates
12
12
  * task-level data into a single FullSessionSummary.
13
13
  */
14
- import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, unlinkSync, writeFileSync, } from 'node:fs';
15
- import { join, resolve, sep } from 'node:path';
14
+ import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, unlinkSync, writeFileSync, } from 'node:fs';
15
+ import { randomBytes } from 'node:crypto';
16
+ import { basename, dirname, join, resolve, sep } from 'node:path';
16
17
  import { createLogger } from '../shared/index.js';
17
18
  import { redactIdentifier, redactSensitive } from '../config.js';
18
19
  import { stripRepoNameCredentials } from '../lib/git-remote.js';
@@ -389,10 +390,14 @@ export class SessionStore {
389
390
  getSessionsDir() {
390
391
  return this.sessionsDir;
391
392
  }
393
+ /**
394
+ * Returns null when nothing was written, else the file the write merged
395
+ * against (`previous`, null for a new file).
396
+ */
392
397
  saveSession(summary) {
393
398
  if (!/^[A-Za-z0-9_-]{1,128}$/.test(summary.sessionId) || summary.sessionId === 'unknown') {
394
399
  logger.warn('Rejecting invalid sessionId for file path', { sessionId: summary.sessionId });
395
- return;
400
+ return null;
396
401
  }
397
402
  if (!existsSync(this.sessionsDir)) {
398
403
  mkdirSync(this.sessionsDir, { recursive: true, mode: 0o700 });
@@ -408,7 +413,7 @@ export class SessionStore {
408
413
  // merged (inflated, since counters take the max) result to a NEW file
409
414
  // while leaving the OLD file on disk untouched — the session then
410
415
  // appeared twice in history with overlapping, double-counted totals.
411
- const existingWithPath = this.loadSessionWithPath(summary.sessionId);
416
+ const { existing: existingWithPath, filesRead } = this.loadSessionWithPath(summary.sessionId);
412
417
  // Every MCP server process checkpoints every 30s, including windows that
413
418
  // never saw a tool call or a token. Writing those first-time files filled
414
419
  // history with model-less zero-activity rows that dragged down every
@@ -417,7 +422,7 @@ export class SessionStore {
417
422
  logger.debug('Skipping first write of a session with no recorded usage', {
418
423
  sessionId: summary.sessionId,
419
424
  });
420
- return;
425
+ return null;
421
426
  }
422
427
  // A second process saving under the same sessionId (e.g. two MCP
423
428
  // servers both resumed/forked against one real session ID) would
@@ -437,7 +442,7 @@ export class SessionStore {
437
442
  logger.warn('Refusing to overwrite recorded session with an empty summary', {
438
443
  sessionId: summary.sessionId,
439
444
  });
440
- return;
445
+ return null;
441
446
  }
442
447
  // Two processes legitimately share one session id: the CLI/editor
443
448
  // spawns an MCP engine that owns the session natively, while a
@@ -465,8 +470,28 @@ export class SessionStore {
465
470
  if (!filepath.startsWith(this.sessionsDir + sep)) {
466
471
  throw new Error(`Session path escaped storage directory: ${filepath}`);
467
472
  }
473
+ const unparsedFilesReplaced = filesRead.filter((file) => file.parsed.kind !== 'clean' &&
474
+ (file.filepath === filepath || file.filepath === existingWithPath?.filepath));
475
+ // Write-then-rename so two processes saving the same session id can never
476
+ // interleave bytes in the target file (the temp name does not end in .json,
477
+ // so loaders never see it).
478
+ const content = JSON.stringify(toWrite, null, 2) + '\n';
479
+ const tmpPath = `${filepath}.${process.pid}.${randomBytes(4).toString('hex')}.tmp`;
468
480
  try {
469
- writeFileSync(filepath, JSON.stringify(toWrite, null, 2) + '\n', { mode: 0o600 });
481
+ try {
482
+ writeFileSync(tmpPath, content, { mode: 0o600 });
483
+ if (!unparsedFilesReplaced.every(copiedAsideUnchanged))
484
+ return null;
485
+ renameIntoPlace(tmpPath, filepath, content);
486
+ }
487
+ finally {
488
+ try {
489
+ unlinkSync(tmpPath);
490
+ }
491
+ catch {
492
+ // Renamed into place, or never written.
493
+ }
494
+ }
470
495
  // The merge landed on a different filename than where the existing
471
496
  // record lived (a date-rollover case) — remove the now-superseded
472
497
  // file so the session isn't left duplicated across two files.
@@ -483,6 +508,7 @@ export class SessionStore {
483
508
  }
484
509
  }
485
510
  logger.debug('Session saved', { sessionId: toWrite.sessionId, filename });
511
+ return { previous: existingWithPath?.summary ?? null };
486
512
  }
487
513
  catch (err) {
488
514
  const message = err instanceof Error ? err.message : String(err);
@@ -491,42 +517,57 @@ export class SessionStore {
491
517
  filename,
492
518
  error: message,
493
519
  });
520
+ return null;
494
521
  }
495
522
  }
496
523
  loadSession(sessionId) {
497
- return this.loadSessionWithPath(sessionId)?.summary ?? null;
524
+ return this.loadSessionWithPath(sessionId).existing?.summary ?? null;
498
525
  }
499
- /** Like loadSession(), but also returns the file path it was loaded from — used by saveSession() to detect and clean up a stale file after a merge relocates a session to a different filename. */
526
+ /**
527
+ * Like loadSession(), but also returns the file path it was loaded from — used by saveSession() to detect and clean up a stale file after a merge relocates a session to a different filename.
528
+ *
529
+ * An unreadable file is skipped rather than ending the search: returning null
530
+ * there made saveSession() treat the session as new and start a fresh file
531
+ * on every later save. Sibling files for one id are not merged here,
532
+ * because files split that way hold disjoint activity that mergeSummaries'
533
+ * per-counter max would drop.
534
+ */
500
535
  loadSessionWithPath(sessionId) {
501
536
  if (!existsSync(this.sessionsDir))
502
- return null;
503
- for (const file of readdirSync(this.sessionsDir)) {
504
- if (!file.endsWith('.json'))
505
- continue;
506
- if (parseSessionFilename(file)?.sessionId !== sessionId)
507
- continue;
508
- const filepath = join(this.sessionsDir, file);
537
+ return { existing: null, filesRead: [] };
538
+ const names = readdirSync(this.sessionsDir)
539
+ .filter((file) => parseSessionFilename(file)?.sessionId === sessionId)
540
+ .sort();
541
+ const filesRead = [];
542
+ for (const file of names) {
543
+ const filepath = resolve(this.sessionsDir, file);
509
544
  try {
510
- const raw = readFileSync(filepath, 'utf-8');
511
- const session = deserializeSession(raw);
512
- if (session === null) {
513
- logger.warn('Failed to deserialize session file', { file });
514
- return null;
515
- }
516
- return { summary: session, filepath };
545
+ const bytes = readFileSync(filepath);
546
+ filesRead.push({
547
+ filepath,
548
+ bytes,
549
+ parsed: parseSessionFile(bytes.toString('utf-8'), filepath),
550
+ });
517
551
  }
518
552
  catch {
519
553
  logger.warn('Failed to read session file', { file });
520
554
  }
521
555
  }
522
- return null;
556
+ for (const { filepath, parsed } of filesRead) {
557
+ const summary = usableSummary(parsed, () => names.length - filesRead.filter((f) => f.parsed.kind === 'unreadable').length);
558
+ if (summary)
559
+ return { existing: { summary, filepath }, filesRead };
560
+ }
561
+ return { existing: null, filesRead };
523
562
  }
524
563
  listSessions(options) {
525
564
  if (!existsSync(this.sessionsDir))
526
565
  return [];
527
566
  const sinceDate = options?.since ? formatDate(options.since) : null;
528
567
  const results = [];
529
- for (const file of readdirSync(this.sessionsDir)) {
568
+ const names = readdirSync(this.sessionsDir);
569
+ const parsingFilesForId = parsingFileCounter(this.sessionsDir, names.flatMap((name) => parseSessionFilename(name) ?? []));
570
+ for (const file of names) {
530
571
  if (!file.endsWith('.json'))
531
572
  continue;
532
573
  const parsed = parseSessionFilename(file);
@@ -536,9 +577,9 @@ export class SessionStore {
536
577
  continue;
537
578
  if (options?.developer) {
538
579
  try {
539
- const raw = readFileSync(join(this.sessionsDir, file), 'utf-8');
540
- const session = deserializeSession(raw);
541
- if (session?.developer !== options.developer)
580
+ const filepath = join(this.sessionsDir, file);
581
+ const summary = usableSummary(parseSessionFile(readFileSync(filepath, 'utf-8'), filepath), () => parsingFilesForId(parsed.sessionId));
582
+ if (!summary || summary.developer !== options.developer)
542
583
  continue;
543
584
  }
544
585
  catch {
@@ -555,12 +596,10 @@ export class SessionStore {
555
596
  const sinceDate = options?.since ? formatDate(options.since) : null;
556
597
  const modifiedSinceMs = options?.includeModifiedSince?.getTime() ?? null;
557
598
  const results = [];
558
- for (const file of readdirSync(this.sessionsDir)) {
559
- if (!file.endsWith('.json'))
560
- continue;
561
- const parsed = parseSessionFilename(file);
562
- if (!parsed)
563
- continue;
599
+ const sessionFiles = readdirSync(this.sessionsDir).flatMap((file) => parseSessionFilename(file) ?? []);
600
+ const parsingFilesForId = parsingFileCounter(this.sessionsDir, sessionFiles);
601
+ for (const parsed of sessionFiles) {
602
+ const file = parsed.filename;
564
603
  if (sinceDate && parsed.date < sinceDate) {
565
604
  if (modifiedSinceMs === null)
566
605
  continue;
@@ -573,8 +612,8 @@ export class SessionStore {
573
612
  }
574
613
  }
575
614
  try {
576
- const raw = readFileSync(join(this.sessionsDir, file), 'utf-8');
577
- const session = deserializeSession(raw);
615
+ const filepath = join(this.sessionsDir, file);
616
+ const session = usableSummary(parseSessionFile(readFileSync(filepath, 'utf-8'), filepath), () => parsingFilesForId(parsed.sessionId));
578
617
  if (!session)
579
618
  continue;
580
619
  // Synthetic session IDs (`local-*`, `proxy-*`, `pending-*`) are
@@ -1315,11 +1354,77 @@ export function deserializeFullSessionSummary(obj) {
1315
1354
  attribution: parseAttribution(obj.attribution),
1316
1355
  };
1317
1356
  }
1357
+ const warnedKeys = new Set();
1358
+ function warnOnce(key, message, data) {
1359
+ if (warnedKeys.has(key))
1360
+ return;
1361
+ warnedKeys.add(key);
1362
+ logger.warn(message, data);
1363
+ }
1364
+ function parseSessionFile(raw, filepath) {
1365
+ const summary = parseSummary(raw);
1366
+ if (summary)
1367
+ return { kind: 'clean', summary };
1368
+ const first = firstTopLevelJsonDocument(raw);
1369
+ const recovered = first === null ? null : parseSummary(first);
1370
+ const file = basename(filepath);
1371
+ if (recovered) {
1372
+ warnOnce(`recovered:${filepath}`, 'Recovered first JSON document from corrupt session file', {
1373
+ file,
1374
+ });
1375
+ return { kind: 'recovered', summary: recovered };
1376
+ }
1377
+ warnOnce(`unreadable:${filepath}`, 'Failed to deserialize session file', { file });
1378
+ return { kind: 'unreadable' };
1379
+ }
1380
+ /**
1381
+ * A recovered document is used only when its file is the only one of its id
1382
+ * that parses. Beside a parsing sibling it may repeat activity the sibling
1383
+ * already holds, so adding the two could double count. It stays unread there,
1384
+ * as it was before recovery existed, until a session's split files are
1385
+ * combined. A sibling that parses as unreadable holds nothing to double count,
1386
+ * so it does not hide the recovered file. A sibling that cannot be read at all
1387
+ * might hold anything, so it counts as parsing. The count includes the file
1388
+ * itself and is only asked for when the file is recovered.
1389
+ */
1390
+ function usableSummary(parsed, parsingFilesForId) {
1391
+ if (parsed.kind === 'unreadable')
1392
+ return null;
1393
+ return parsed.kind === 'clean' || parsingFilesForId() === 1 ? parsed.summary : null;
1394
+ }
1395
+ /**
1396
+ * Counts, per session id, the files that parse as clean or recovered. A file
1397
+ * that cannot be read at all might hold anything, so it counts as parsing.
1398
+ * Reads an id's files once, on first ask.
1399
+ */
1400
+ function parsingFileCounter(sessionsDir, files) {
1401
+ const filenamesById = new Map();
1402
+ for (const { sessionId, filename } of files) {
1403
+ filenamesById.set(sessionId, [...(filenamesById.get(sessionId) ?? []), filename]);
1404
+ }
1405
+ const counts = new Map();
1406
+ return (sessionId) => {
1407
+ const known = counts.get(sessionId);
1408
+ if (known !== undefined)
1409
+ return known;
1410
+ const count = (filenamesById.get(sessionId) ?? []).filter((filename) => {
1411
+ const filepath = join(sessionsDir, filename);
1412
+ try {
1413
+ return parseSessionFile(readFileSync(filepath, 'utf-8'), filepath).kind !== 'unreadable';
1414
+ }
1415
+ catch {
1416
+ return true;
1417
+ }
1418
+ }).length;
1419
+ counts.set(sessionId, count);
1420
+ return count;
1421
+ };
1422
+ }
1318
1423
  /**
1319
1424
  * Parse a raw session JSON string and extract known fields. Delegates field
1320
1425
  * extraction to `deserializeFullSessionSummary` to avoid duplication.
1321
1426
  */
1322
- function deserializeSession(raw) {
1427
+ function parseSummary(raw) {
1323
1428
  let parsed;
1324
1429
  try {
1325
1430
  parsed = JSON.parse(raw);
@@ -1331,6 +1436,106 @@ function deserializeSession(raw) {
1331
1436
  return null;
1332
1437
  return deserializeFullSessionSummary(parsed);
1333
1438
  }
1439
+ function copiedAsideUnchanged(file) {
1440
+ const name = basename(file.filepath);
1441
+ try {
1442
+ if (!readFileSync(file.filepath).equals(file.bytes)) {
1443
+ logger.warn('Session file changed since it was read; skipping this save', { file: name });
1444
+ return false;
1445
+ }
1446
+ if (hasCorruptCopy(file))
1447
+ return true;
1448
+ const suffix = `${Date.now()}.${process.pid}.${randomBytes(4).toString('hex')}`;
1449
+ writeFileSync(`${file.filepath}.${suffix}.corrupt`, file.bytes, {
1450
+ mode: 0o600,
1451
+ flag: 'wx',
1452
+ });
1453
+ return true;
1454
+ }
1455
+ catch (err) {
1456
+ logger.warn('Could not copy an unparsed session file aside; skipping this save', {
1457
+ file: name,
1458
+ error: err instanceof Error ? err.message : String(err),
1459
+ });
1460
+ return false;
1461
+ }
1462
+ }
1463
+ /** True when a `.corrupt` copy of these exact bytes already sits beside the file. */
1464
+ function hasCorruptCopy(file) {
1465
+ const dir = dirname(file.filepath);
1466
+ const prefix = `${basename(file.filepath)}.`;
1467
+ return readdirSync(dir).some((entry) => {
1468
+ if (!entry.startsWith(prefix) || !entry.endsWith('.corrupt'))
1469
+ return false;
1470
+ try {
1471
+ return readFileSync(join(dir, entry)).equals(file.bytes);
1472
+ }
1473
+ catch {
1474
+ return false;
1475
+ }
1476
+ });
1477
+ }
1478
+ const RENAME_RETRY_CODES = new Set(['EPERM', 'EACCES', 'EBUSY']);
1479
+ const RENAME_BACKOFF_MS = [10, 20, 40, 80];
1480
+ const SLEEP_CELL = new Int32Array(new SharedArrayBuffer(4));
1481
+ /**
1482
+ * Windows refuses to rename over a file another process has open, which
1483
+ * antivirus scanners do briefly after each write. Retry with backoff, then
1484
+ * write the target directly so saves never silently stop.
1485
+ */
1486
+ function renameIntoPlace(tmpPath, filepath, content) {
1487
+ for (let attempt = 0;; attempt++) {
1488
+ try {
1489
+ renameSync(tmpPath, filepath);
1490
+ return;
1491
+ }
1492
+ catch (err) {
1493
+ const code = err.code ?? '';
1494
+ if (!RENAME_RETRY_CODES.has(code))
1495
+ throw err;
1496
+ if (process.platform !== 'win32' || attempt === RENAME_BACKOFF_MS.length)
1497
+ break;
1498
+ Atomics.wait(SLEEP_CELL, 0, 0, RENAME_BACKOFF_MS[attempt]);
1499
+ }
1500
+ }
1501
+ try {
1502
+ writeFileSync(filepath, content, { mode: 0o600 });
1503
+ }
1504
+ catch (err) {
1505
+ warnOnce(`rename-failed:${filepath}`, 'Could not rename session file into place and the direct write failed too', { file: basename(filepath), error: err instanceof Error ? err.message : String(err) });
1506
+ throw err;
1507
+ }
1508
+ warnOnce(`rename:${filepath}`, 'Could not rename session file into place; wrote it directly', {
1509
+ file: basename(filepath),
1510
+ });
1511
+ }
1512
+ /** Returns the leading `{...}` of `raw` (string- and escape-aware), or null if it never closes. */
1513
+ function firstTopLevelJsonDocument(raw) {
1514
+ const start = raw.search(/\S/);
1515
+ if (start === -1 || raw[start] !== '{')
1516
+ return null;
1517
+ let depth = 0;
1518
+ let inString = false;
1519
+ for (let i = start; i < raw.length; i++) {
1520
+ const ch = raw[i];
1521
+ if (inString) {
1522
+ if (ch === '\\')
1523
+ i++;
1524
+ else if (ch === '"')
1525
+ inString = false;
1526
+ }
1527
+ else if (ch === '"') {
1528
+ inString = true;
1529
+ }
1530
+ else if (ch === '{') {
1531
+ depth++;
1532
+ }
1533
+ else if (ch === '}' && --depth === 0) {
1534
+ return raw.slice(start, i + 1);
1535
+ }
1536
+ }
1537
+ return null;
1538
+ }
1334
1539
  function parseSessionFilename(filename) {
1335
1540
  // Expected format: YYYY-MM-DD_sessionId.json
1336
1541
  const match = filename.match(/^(\d{4}-\d{2}-\d{2})_(.+)\.json$/);