@openlimiter/core 2.0.4 → 2.1.1

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.
@@ -4,7 +4,7 @@ export declare const MAX_CODEX_APP_SERVER_OUTPUT_BYTES = 1048576;
4
4
  export declare const CODEX_APP_SERVER_CLIENT_INFO: {
5
5
  readonly name: "openlimiter";
6
6
  readonly title: "OpenLimiter";
7
- readonly version: "2.0.4";
7
+ readonly version: "2.1.1";
8
8
  };
9
9
  export type CodexRateLimitsReadResult = {
10
10
  readonly ok: true;
@@ -116,6 +116,15 @@ export declare const REFRESH_SPAWN_FAILURE_NAME = "openlimiter-refresh-spawn.jso
116
116
  export declare function recordRefreshSpawnFailure(directory: string, now: string): Promise<void>;
117
117
  /** When the last background refresh failed to start, if one did. */
118
118
  export declare function readRefreshSpawnFailure(directory?: string): Promise<string | null>;
119
+ /**
120
+ * How long one start holds off the next.
121
+ *
122
+ * A child left suspended (its parent killed mid spawn on Windows) never runs,
123
+ * so it never takes the refresh lock, and the lock alone would let every
124
+ * render start one more. This bound makes it one start per window at most,
125
+ * whatever became of the child.
126
+ */
127
+ export declare const REFRESH_START_INTERVAL_MILLISECONDS = 120000;
119
128
  /** Forget it, which a refresh that actually ran is the proof of. */
120
129
  export declare function clearRefreshSpawnFailure(directory?: string): Promise<void>;
121
130
  export interface DetachedSpawn {
@@ -147,8 +156,8 @@ export type SpawnRefreshResult = {
147
156
  /**
148
157
  * Start a refresh behind the caller, and never wait for it.
149
158
  *
150
- * Everything expensive happens in the child. This function creates one lock
151
- * file and hands the operating system a detached process, so the render that
159
+ * Everything expensive happens in the child. This function creates one start
160
+ * token and hands the operating system a detached process, so the render that
152
161
  * called it returns in the time a file create takes. A failure to spawn is
153
162
  * reported and never thrown: a status line that cannot start a refresh still
154
163
  * has to draw the bars it already has.
@@ -1 +1 @@
1
- {"version":3,"file":"coordination.d.ts","sourceRoot":"","sources":["../../src/acquire/coordination.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"coordination.d.ts","sourceRoot":"","sources":["../../src/acquire/coordination.ts"],"names":[],"mappings":"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"}
@@ -13,7 +13,7 @@
13
13
  * never waits for the network; the next render shows what the refresh found.
14
14
  */
15
15
  import { randomUUID } from "node:crypto";
16
- import { lstat, open, readFile, unlink, utimes } from "node:fs/promises";
16
+ import { lstat, open, readdir, readFile, unlink, utimes, writeFile } from "node:fs/promises";
17
17
  import path from "node:path";
18
18
  import { prepareStateDirectory, readJsonFileSafely, resolveStateDirectory, writeFileAtomically } from "../cache.js";
19
19
  import { canonicalJson } from "../normalizer.js";
@@ -262,9 +262,9 @@ export const REFRESH_SPAWN_FAILURE_NAME = "openlimiter-refresh-spawn.json";
262
262
  export async function recordRefreshSpawnFailure(directory, now) {
263
263
  await writeFileAtomically(path.join(directory, REFRESH_SPAWN_FAILURE_NAME), canonicalJson({ at: now, version: 1 })).catch(() => undefined);
264
264
  }
265
- /** When the last background refresh failed to start, if one did. */
266
- export async function readRefreshSpawnFailure(directory = resolveStateDirectory()) {
267
- const document = await readJsonFileSafely(path.join(directory, REFRESH_SPAWN_FAILURE_NAME), 4_096);
265
+ /** The time a small `{ at, version }` record in the state directory holds. */
266
+ async function readRecordedAt(directory, name) {
267
+ const document = await readJsonFileSafely(path.join(directory, name), 4_096);
268
268
  if (!document.ok)
269
269
  return null;
270
270
  const value = document.value;
@@ -273,6 +273,34 @@ export async function readRefreshSpawnFailure(directory = resolveStateDirectory(
273
273
  const at = value["at"];
274
274
  return typeof at === "string" && Number.isFinite(Date.parse(at)) ? at : null;
275
275
  }
276
+ /** When the last background refresh failed to start, if one did. */
277
+ export async function readRefreshSpawnFailure(directory = resolveStateDirectory()) {
278
+ return readRecordedAt(directory, REFRESH_SPAWN_FAILURE_NAME);
279
+ }
280
+ /**
281
+ * How long one start holds off the next.
282
+ *
283
+ * A child left suspended (its parent killed mid spawn on Windows) never runs,
284
+ * so it never takes the refresh lock, and the lock alone would let every
285
+ * render start one more. This bound makes it one start per window at most,
286
+ * whatever became of the child.
287
+ */
288
+ export const REFRESH_START_INTERVAL_MILLISECONDS = 120_000;
289
+ /** The empty file whose exclusive creation reserves one start window. */
290
+ function startTokenName(window) {
291
+ return `openlimiter-refresh-start-${window}.token`;
292
+ }
293
+ /* Tokens of windows more than two behind hold nothing back. A token only two
294
+ behind stays, so a render whose clock runs slightly late cannot create it
295
+ again after a faster clock has moved on. */
296
+ async function removeOldStartTokens(directory, window) {
297
+ for (const name of await readdir(directory).catch(() => [])) {
298
+ const match = /^openlimiter-refresh-start-(\d+)\.token$/u.exec(name);
299
+ if (match !== null && window - Number(match[1]) > 2) {
300
+ await unlink(path.join(directory, name)).catch(() => undefined);
301
+ }
302
+ }
303
+ }
276
304
  /** Forget it, which a refresh that actually ran is the proof of. */
277
305
  export async function clearRefreshSpawnFailure(directory = resolveStateDirectory()) {
278
306
  await unlink(path.join(directory, REFRESH_SPAWN_FAILURE_NAME)).catch(() => undefined);
@@ -280,8 +308,8 @@ export async function clearRefreshSpawnFailure(directory = resolveStateDirectory
280
308
  /**
281
309
  * Start a refresh behind the caller, and never wait for it.
282
310
  *
283
- * Everything expensive happens in the child. This function creates one lock
284
- * file and hands the operating system a detached process, so the render that
311
+ * Everything expensive happens in the child. This function creates one start
312
+ * token and hands the operating system a detached process, so the render that
285
313
  * called it returns in the time a file create takes. A failure to spawn is
286
314
  * reported and never thrown: a status line that cannot start a refresh still
287
315
  * has to draw the bars it already has.
@@ -301,8 +329,22 @@ export async function spawnDetachedRefresh(options) {
301
329
  if (await refreshLockHeld(directory)) {
302
330
  return { spawned: false, reason: "already_running" };
303
331
  }
332
+ const window = Math.floor(Date.parse(options.now) / REFRESH_START_INTERVAL_MILLISECONDS);
304
333
  try {
305
334
  await prepareStateDirectory(directory);
335
+ /* Exclusive creation is the decision: the operating system lets exactly
336
+ one render, across every process, create this window's token, and only
337
+ that render spawns. Never best effort, so a start that could not be
338
+ reserved is not made and no child escapes the bound. */
339
+ try {
340
+ await writeFile(path.join(directory, startTokenName(window)), "", { flag: "wx", mode: 0o600 });
341
+ }
342
+ catch (error) {
343
+ if (errorCode(error) === "EEXIST")
344
+ return { spawned: false, reason: "already_running" };
345
+ throw error;
346
+ }
347
+ await removeOldStartTokens(directory, window);
306
348
  options.spawn(options.nodeExecutable, [options.openLimiterScript, "refresh", "--detached"], {
307
349
  cwd: directory,
308
350
  onError: () => {
@@ -1 +1 @@
1
- {"version":3,"file":"coordination.js","sourceRoot":"","sources":["../../src/acquire/coordination.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"coordination.js","sourceRoot":"","sources":["../../src/acquire/coordination.ts"],"names":[],"mappings":"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"}
@@ -14,7 +14,7 @@
14
14
  * package's own version, so the constant cannot drift.
15
15
  */
16
16
  import type { ProviderCode } from "../types.js";
17
- export declare const ACQUISITION_CLIENT_VERSION = "2.0.4";
17
+ export declare const ACQUISITION_CLIENT_VERSION = "2.1.1";
18
18
  /** The only user agent any acquisition request may carry. */
19
19
  export declare const OPENLIMITER_USER_AGENT: string;
20
20
  /** Mirrors provider_detection::opaque_account_id, including the zero separator. */
@@ -15,7 +15,7 @@
15
15
  */
16
16
  /** The published version this build identifies as. */
17
17
  import { createHash } from "node:crypto";
18
- export const ACQUISITION_CLIENT_VERSION = "2.0.4";
18
+ export const ACQUISITION_CLIENT_VERSION = "2.1.1";
19
19
  /** The only user agent any acquisition request may carry. */
20
20
  export const OPENLIMITER_USER_AGENT = "OpenLimiter/" + ACQUISITION_CLIENT_VERSION + " (+https://openlimiter.com)";
21
21
  /** Mirrors provider_detection::opaque_account_id, including the zero separator. */
package/dist/cache.d.ts CHANGED
@@ -2,6 +2,7 @@ export { freshnessPolicy } from "./data-rules.js";
2
2
  import { type CacheState, type CacheSuppression, type CollectionReport } from "./collection.js";
3
3
  import type { ProviderCode, Snapshot } from "./types.js";
4
4
  export declare const CACHE_FILE_NAME = "openlimiter-cache.json";
5
+ export declare const AUTHORITATIVE_CACHE_FILE_NAME = "openlimiter-authoritative.json";
5
6
  export declare const MAX_POLICY_TIMESTAMP = 253402300799999;
6
7
  /** Pure policy shared with the desktop contract. All instants are UTC. */
7
8
  export declare function retryPolicy(input: {
@@ -42,7 +43,7 @@ export declare const CACHE_LOCK_NAME = "openlimiter.lock";
42
43
  /** Largest JSON document this package will read into memory. */
43
44
  export declare const MAX_JSON_FILE_BYTES = 1048576;
44
45
  /** A lock older than this is treated as abandoned and reclaimed. */
45
- export declare const LOCK_STALE_MILLISECONDS = 5000;
46
+ export declare const LOCK_STALE_MILLISECONDS = 60000;
46
47
  export interface StateDirectoryOptions {
47
48
  platform?: NodeJS.Platform;
48
49
  environment?: Readonly<Record<string, string | undefined>>;
@@ -108,7 +109,7 @@ export declare function readSnapshotCache(directory?: string): Promise<CacheRead
108
109
  * so a fold can remove them properly instead of merging around a filtered view
109
110
  * and quietly resurrecting what it could not see.
110
111
  */
111
- export declare function readCacheState(directory?: string): Promise<{
112
+ export declare function readCacheState(directory?: string, fileName?: string): Promise<{
112
113
  ok: true;
113
114
  state: CacheState;
114
115
  } | {
@@ -123,6 +124,13 @@ export declare function readCacheState(directory?: string): Promise<{
123
124
  * after the rename cannot leave an empty file behind.
124
125
  */
125
126
  export declare function writeFileAtomically(target: string, contents: string): Promise<void>;
127
+ /**
128
+ * Run one cache mutation while holding the single cache lock.
129
+ *
130
+ * Readers never take this lock. They rely on the atomic replacement below, so
131
+ * the lock exists only to keep two writers from interleaving.
132
+ */
133
+ export declare function withStateLock<Result>(directory: string, action: () => Promise<Result>): Promise<Result>;
126
134
  /**
127
135
  * Document version of the snapshot cache.
128
136
  *
@@ -151,6 +159,9 @@ export declare const CACHE_DOCUMENT_VERSION = 3;
151
159
  * stamp so a writer that died cannot freeze the cache forever.
152
160
  */
153
161
  export declare function writeSnapshotCache(snapshots: readonly Snapshot[], directory?: string): Promise<void>;
162
+ /** Poll owned rows live apart from the statusline cache so legacy runtimes can
163
+ * never overwrite a weekly usage value. */
164
+ export declare function mergeAuthoritativeSnapshotCache(incoming: readonly Snapshot[], directory?: string, now?: string): Promise<Snapshot[]>;
154
165
  export interface CacheMergeResult {
155
166
  merged: Snapshot[];
156
167
  written: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
package/dist/cache.js CHANGED
@@ -1,14 +1,15 @@
1
- import { freshnessPolicy, retainSnapshots } from "./data-rules.js";
1
+ import { freshnessPolicy, isSnapshotDisplayEligible, retainSnapshots } from "./data-rules.js";
2
2
  export { freshnessPolicy } from "./data-rules.js";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { constants } from "node:fs";
5
- import { chmod, lstat, mkdir, open, readFile, rename, unlink } from "node:fs/promises";
5
+ import { chmod, lstat, mkdir, open, readFile, rename, rm, unlink } from "node:fs/promises";
6
6
  import { homedir } from "node:os";
7
7
  import path from "node:path";
8
8
  import { applyCollectionReport, readSuppressions, snapshotBelongsTo, visibleSnapshots } from "./collection.js";
9
9
  import { MAX_CACHE_ENTRIES, mergeSnapshots, snapshotIdentity } from "./merge.js";
10
10
  import { canonicalJson, normalizeMeter, normalizeMeters } from "./normalizer.js";
11
11
  export const CACHE_FILE_NAME = "openlimiter-cache.json";
12
+ export const AUTHORITATIVE_CACHE_FILE_NAME = "openlimiter-authoritative.json";
12
13
  export const MAX_POLICY_TIMESTAMP = 253_402_300_799_999;
13
14
  /** Pure policy shared with the desktop contract. All instants are UTC. */
14
15
  export function retryPolicy(input) {
@@ -125,7 +126,7 @@ export const CACHE_LOCK_NAME = "openlimiter.lock";
125
126
  /** Largest JSON document this package will read into memory. */
126
127
  export const MAX_JSON_FILE_BYTES = 1_048_576;
127
128
  /** A lock older than this is treated as abandoned and reclaimed. */
128
- export const LOCK_STALE_MILLISECONDS = 5_000;
129
+ export const LOCK_STALE_MILLISECONDS = 60_000;
129
130
  /** The longest pause between lock acquisition attempts. It is not a deadline. */
130
131
  const LOCK_BACKOFF_CEILING_MILLISECONDS = 25;
131
132
  export function resolveStateDirectory(options = {}) {
@@ -246,8 +247,21 @@ export async function readSnapshotCache(directory = resolveStateDirectory()) {
246
247
  return { ok: false, reason: "unsafe" };
247
248
  }
248
249
  const document = await readJsonFileSafely(path.join(directory, CACHE_FILE_NAME));
249
- if (!document.ok)
250
- return document;
250
+ if (!document.ok) {
251
+ if (document.reason !== "missing")
252
+ return document;
253
+ const authoritative = await readJsonFileSafely(path.join(directory, AUTHORITATIVE_CACHE_FILE_NAME));
254
+ if (!authoritative.ok)
255
+ return authoritative.reason === "missing" ? document : authoritative;
256
+ if (!isRecord(authoritative.value) || !Array.isArray(authoritative.value["snapshots"])) {
257
+ return { ok: false, reason: "corrupt" };
258
+ }
259
+ const snapshots = normalizeMeters(authoritative.value["snapshots"]);
260
+ return { ok: true, snapshots: snapshots.filter(isSnapshotDisplayEligible), dropped: authoritative.value["snapshots"].length - snapshots.length, suppressed: 0, suppressions: [] };
261
+ }
262
+ const authoritative = await readJsonFileSafely(path.join(directory, AUTHORITATIVE_CACHE_FILE_NAME));
263
+ if (!authoritative.ok && authoritative.reason !== "missing")
264
+ return authoritative;
251
265
  if (!isRecord(document.value))
252
266
  return { ok: false, reason: "corrupt" };
253
267
  const rawSnapshots = document.value["snapshots"];
@@ -262,8 +276,16 @@ export async function readSnapshotCache(directory = resolveStateDirectory()) {
262
276
  return { ok: false, reason: "corrupt" };
263
277
  }
264
278
  const migrated = migrateLegacyMeterIdentities(rawSnapshots, version);
265
- const validated = normalizeMeters(migrated);
266
- const dropped = rawSnapshots.length - validated.length;
279
+ const mainValidated = normalizeMeters(migrated);
280
+ const authoritativeRows = authoritative.ok && isRecord(authoritative.value) &&
281
+ Array.isArray(authoritative.value["snapshots"]) && authoritative.value["snapshots"].length <= MAX_CACHE_ENTRIES
282
+ ? normalizeMeters(authoritative.value["snapshots"])
283
+ : [];
284
+ const authoritativeIdentities = new Set(authoritativeRows.map(snapshotIdentity));
285
+ const validated = authoritativeRows.length > 0
286
+ ? mergeSnapshots(mainValidated.filter((snapshot) => !authoritativeIdentities.has(snapshotIdentity(snapshot))), authoritativeRows)
287
+ : mainValidated;
288
+ const dropped = rawSnapshots.length - mainValidated.length;
267
289
  const read = readSuppressions(document.value["suppressions"]);
268
290
  if (!read.ok) {
269
291
  /* Unreadable suppressions make every identity in the document unknown.
@@ -291,14 +313,14 @@ export async function readSnapshotCache(directory = resolveStateDirectory()) {
291
313
  * so a fold can remove them properly instead of merging around a filtered view
292
314
  * and quietly resurrecting what it could not see.
293
315
  */
294
- export async function readCacheState(directory = resolveStateDirectory()) {
316
+ export async function readCacheState(directory = resolveStateDirectory(), fileName = CACHE_FILE_NAME) {
295
317
  try {
296
318
  await rejectSymlink(directory);
297
319
  }
298
320
  catch {
299
321
  return { ok: false, reason: "unsafe" };
300
322
  }
301
- const document = await readJsonFileSafely(path.join(directory, CACHE_FILE_NAME));
323
+ const document = await readJsonFileSafely(path.join(directory, fileName));
302
324
  if (!document.ok)
303
325
  return document;
304
326
  if (!isRecord(document.value))
@@ -386,64 +408,87 @@ export async function writeFileAtomically(target, contents) {
386
408
  await unlink(tempPath).catch(() => undefined);
387
409
  }
388
410
  }
389
- /**
390
- * Decide whether an existing lock has been abandoned and remove it if so.
391
- *
392
- * The owner stamp inside the lock is the primary signal. An empty or unreadable
393
- * lock falls back to the file modification time, which covers the short window
394
- * between creating the lock and writing the stamp into it.
395
- */
396
- async function reclaimStaleLock(lockPath) {
397
- const now = Date.now();
398
- let heldSince = null;
399
- let observedContents = null;
411
+ async function processIsAlive(pid) {
412
+ if (!Number.isSafeInteger(pid) || pid <= 0)
413
+ return false;
400
414
  try {
401
- observedContents = await readFile(lockPath, "utf8");
402
- const parsed = JSON.parse(observedContents);
403
- const stamp = isRecord(parsed) ? parsed["at"] : undefined;
404
- if (typeof stamp === "number" && Number.isFinite(stamp) && stamp <= now) {
405
- heldSince = stamp;
406
- }
415
+ process.kill(pid, 0);
416
+ return true;
407
417
  }
408
- catch {
409
- heldSince = null;
418
+ catch (error) {
419
+ return errorCode(error) === "EPERM";
410
420
  }
411
- let observedDevice;
412
- let observedInode;
413
- let modificationTime;
421
+ }
422
+ async function reclaimStaleLock(lockPath) {
423
+ let stat;
414
424
  try {
415
- const observed = await lstat(lockPath);
416
- observedDevice = observed.dev;
417
- observedInode = observed.ino;
418
- modificationTime = observed.mtimeMs;
425
+ stat = await lstat(lockPath);
419
426
  }
420
427
  catch (error) {
421
428
  if (errorCode(error) === "ENOENT")
422
429
  return true;
423
430
  throw error;
424
431
  }
425
- if (heldSince === null) {
426
- heldSince = modificationTime;
427
- if (!Number.isFinite(heldSince) || heldSince > now)
428
- heldSince = now;
432
+ if (!stat.isDirectory() || stat.isSymbolicLink())
433
+ throw new Error("Unsafe state lock");
434
+ const ownerPath = path.join(lockPath, "owner.json");
435
+ let owner = null;
436
+ try {
437
+ const parsed = JSON.parse(await readFile(ownerPath, "utf8"));
438
+ if (isRecord(parsed) &&
439
+ Number.isSafeInteger(parsed["pid"]) &&
440
+ typeof parsed["startedAt"] === "number" &&
441
+ Number.isFinite(parsed["startedAt"]) &&
442
+ typeof parsed["token"] === "string") {
443
+ owner = {
444
+ pid: parsed["pid"],
445
+ startedAt: parsed["startedAt"],
446
+ token: parsed["token"]
447
+ };
448
+ }
449
+ }
450
+ catch {
451
+ /* A process can die between mkdir and the owner write. The directory mtime
452
+ is the only honest signal until the owner stamp exists. */
429
453
  }
430
- if (now - heldSince < LOCK_STALE_MILLISECONDS)
454
+ const now = Date.now();
455
+ const stale = owner === null
456
+ ? now - stat.mtimeMs >= LOCK_STALE_MILLISECONDS
457
+ : now - owner.startedAt >= LOCK_STALE_MILLISECONDS ||
458
+ !(await processIsAlive(owner.pid));
459
+ if (!stale)
431
460
  return false;
461
+ const displaced = lockPath + ".reclaim." + randomUUID();
432
462
  try {
433
- if (observedContents !== null &&
434
- (await readFile(lockPath, "utf8")) !== observedContents)
435
- return false;
436
- const observed = await lstat(lockPath);
437
- if (observed.dev !== observedDevice || observed.ino !== observedInode)
438
- return false;
439
- await unlink(lockPath);
440
- return true;
463
+ await rename(lockPath, displaced);
441
464
  }
442
465
  catch (error) {
443
466
  if (errorCode(error) === "ENOENT")
444
467
  return true;
445
- throw error;
468
+ return false;
469
+ }
470
+ let stillObserved = owner === null;
471
+ if (owner !== null) {
472
+ try {
473
+ const parsed = JSON.parse(await readFile(path.join(displaced, "owner.json"), "utf8"));
474
+ stillObserved = isRecord(parsed) && parsed["token"] === owner.token;
475
+ }
476
+ catch {
477
+ stillObserved = false;
478
+ }
446
479
  }
480
+ else {
481
+ try {
482
+ await lstat(path.join(displaced, "owner.json"));
483
+ stillObserved = false;
484
+ }
485
+ catch (error) {
486
+ stillObserved = errorCode(error) === "ENOENT";
487
+ }
488
+ }
489
+ if (stillObserved)
490
+ await rm(displaced, { recursive: true, force: true });
491
+ return true;
447
492
  }
448
493
  const transientLockCodes = new Set(["EEXIST", "EPERM", "EACCES", "EBUSY"]);
449
494
  async function lockPathExists(lockPath) {
@@ -462,19 +507,15 @@ async function acquireLock(lockPath) {
462
507
  abandoned owner becomes stale, so neither case should discard this write. */
463
508
  for (let attempt = 0;; attempt += 1) {
464
509
  try {
465
- const handle = await open(lockPath, "wx", 0o600);
466
- const token = JSON.stringify({
467
- at: Date.now(),
468
- id: randomUUID(),
469
- pid: process.pid
470
- });
510
+ await mkdir(lockPath, { mode: 0o700 });
511
+ const token = randomUUID();
512
+ const owner = { pid: process.pid, startedAt: Date.now(), token };
471
513
  try {
472
- await handle.writeFile(token, "utf8");
473
- return { handle, token };
514
+ await writeFileAtomically(path.join(lockPath, "owner.json"), canonicalJson(owner));
515
+ return { token };
474
516
  }
475
517
  catch (error) {
476
- await handle.close().catch(() => undefined);
477
- await unlink(lockPath).catch(() => undefined);
518
+ await rm(lockPath, { recursive: true, force: true }).catch(() => undefined);
478
519
  throw error;
479
520
  }
480
521
  }
@@ -492,13 +533,14 @@ async function acquireLock(lockPath) {
492
533
  }
493
534
  async function releaseLock(lockPath, token) {
494
535
  try {
495
- if ((await readFile(lockPath, "utf8")) !== token)
536
+ const parsed = JSON.parse(await readFile(path.join(lockPath, "owner.json"), "utf8"));
537
+ if (!isRecord(parsed) || parsed["token"] !== token)
496
538
  return;
497
539
  }
498
540
  catch {
499
541
  return;
500
542
  }
501
- await unlink(lockPath).catch(() => undefined);
543
+ await rm(lockPath, { recursive: true, force: true }).catch(() => undefined);
502
544
  }
503
545
  function rejectOutOfBounds(snapshots) {
504
546
  if (snapshots.length > MAX_CACHE_ENTRIES)
@@ -516,7 +558,7 @@ const processLockQueues = new Map();
516
558
  * Readers never take this lock. They rely on the atomic replacement below, so
517
559
  * the lock exists only to keep two writers from interleaving.
518
560
  */
519
- async function withCacheLock(directory, action) {
561
+ export async function withStateLock(directory, action) {
520
562
  const absoluteDirectory = path.resolve(directory);
521
563
  const queueKey = process.platform === "win32"
522
564
  ? absoluteDirectory.toLowerCase()
@@ -533,12 +575,11 @@ async function withCacheLock(directory, action) {
533
575
  await prepareStateDirectory(absoluteDirectory);
534
576
  const lockPath = path.join(absoluteDirectory, CACHE_LOCK_NAME);
535
577
  await rejectSymlink(lockPath);
536
- const { handle, token } = await acquireLock(lockPath);
578
+ const { token } = await acquireLock(lockPath);
537
579
  try {
538
580
  return await action();
539
581
  }
540
582
  finally {
541
- await handle.close().catch(() => undefined);
542
583
  await releaseLock(lockPath, token);
543
584
  }
544
585
  }
@@ -549,6 +590,8 @@ async function withCacheLock(directory, action) {
549
590
  }
550
591
  }
551
592
  }
593
+ /* Snapshot and configuration writers share one state directory lock. */
594
+ const withCacheLock = withStateLock;
552
595
  /**
553
596
  * Document version of the snapshot cache.
554
597
  *
@@ -603,6 +646,34 @@ export async function writeSnapshotCache(snapshots, directory = resolveStateDire
603
646
  await replaceCache(directory, snapshots);
604
647
  });
605
648
  }
649
+ /** Poll owned rows live apart from the statusline cache so legacy runtimes can
650
+ * never overwrite a weekly usage value. */
651
+ export async function mergeAuthoritativeSnapshotCache(incoming, directory = resolveStateDirectory(), now) {
652
+ rejectOutOfBounds(incoming);
653
+ return withStateLock(directory, async () => {
654
+ const cached = await readCacheState(directory, AUTHORITATIVE_CACHE_FILE_NAME);
655
+ const existing = cached.ok ? cached.state.snapshots : [];
656
+ const byIdentity = new Map(existing.map((row) => [snapshotIdentity(row), row]));
657
+ for (const row of incoming) {
658
+ const previous = byIdentity.get(snapshotIdentity(row));
659
+ if (previous === undefined || Date.parse(row.observedAt) >= Date.parse(previous.observedAt)) {
660
+ byIdentity.set(snapshotIdentity(row), row);
661
+ }
662
+ }
663
+ const retentionNow = now === undefined
664
+ ? incoming
665
+ .map((row) => Date.parse(row.observedAt))
666
+ .filter(Number.isFinite)
667
+ .reduce((latest, observed) => Math.max(latest, observed), 0)
668
+ : Date.parse(now);
669
+ const rows = retainSnapshots([...byIdentity.values()], retentionNow);
670
+ rejectOutOfBounds(rows);
671
+ const target = path.join(directory, AUTHORITATIVE_CACHE_FILE_NAME);
672
+ await rejectSymlink(target);
673
+ await writeFileAtomically(target, canonicalJson({ snapshots: rows, version: CACHE_DOCUMENT_VERSION }));
674
+ return rows;
675
+ });
676
+ }
606
677
  /**
607
678
  * Fold fresh snapshots into the cache under the lock.
608
679
  *