fix(hooks): use shared renameWithRetry in writeWarnState (ecc-context-monitor)

Mirror the previous commit's Windows-EPERM retry on the companion
`writeWarnState` in `scripts/hooks/ecc-context-monitor.js`. Same
race: two PostToolUse subprocesses writing concurrent debounce
state racing on `MoveFileExW`, target-in-use throwing EPERM on
Windows even though each writer's tmp path is now unique.

Implementation: import `renameWithRetry` from `scripts/lib/session-bridge.js`
(exported in the previous commit) instead of duplicating the helper.
The retry policy, backoff schedule, and main-thread `Atomics.wait`
strategy stay identical to `writeBridgeAtomic`.

Three writers in the repo now share the same atomic-write contract:
- `writeBridgeAtomic` (scripts/lib/session-bridge.js) — round 1 +
  this round's retry
- `writeWarnState` (this file) — round 1 + this round's retry via shared helper
- `writeCostWarningIfChanged` (scripts/hooks/ecc-metrics-bridge.js) —
  out of scope for this PR (already uses unique tmp suffix; a future
  consolidation could move it to the shared helper too).

Local: `yarn test` green, `yarn lint` clean. The companion test
suite for `ecc-context-monitor.js` does not currently exercise
concurrent `writeWarnState` writes, but the helper it now uses is
covered by the `tests/lib/session-bridge.test.js` concurrent-write
regression added in round 1's last commit.
This commit is contained in:
Jamkris
2026-05-19 11:01:28 +09:00
committed by Affaan Mustafa
parent 116e61d8cb
commit f93e8f6869

View File

@@ -13,7 +13,7 @@ const crypto = require('crypto');
const fs = require('fs');
const os = require('os');
const path = require('path');
const { sanitizeSessionId, readBridge } = require('../lib/session-bridge');
const { sanitizeSessionId, readBridge, renameWithRetry } = require('../lib/session-bridge');
const CONTEXT_WARNING_PCT = 35;
const CONTEXT_CRITICAL_PCT = 25;
@@ -81,7 +81,7 @@ function writeWarnState(sessionId, state) {
const tmp = `${target}.${process.pid}.${crypto.randomBytes(4).toString('hex')}.tmp`;
fs.writeFileSync(tmp, JSON.stringify(state), 'utf8');
try {
fs.renameSync(tmp, target);
renameWithRetry(tmp, target);
} catch (err) {
try { fs.unlinkSync(tmp); } catch { /* ignore */ }
throw err;