agent-dag 1.33.84 → 1.33.85

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.
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
6
  <title>agents-deck</title>
7
7
  <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ctext y='84' font-size='84'%3E%E2%97%89%3C/text%3E%3C/svg%3E" />
8
- <script type="module" crossorigin src="/assets/index-BuV6fHfA.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-C7BvMlyW.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-dwRx-2y0.css">
10
10
  </head>
11
11
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-dag",
3
- "version": "1.33.84",
3
+ "version": "1.33.85",
4
4
  "description": "Live deck of Claude Code and Codex agents — watch parallel subagents fork, call tools, and return on one calm canvas. Also available as npx ccdeck and npx agent-dag.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -175,7 +175,6 @@ function newContextBreakdown() {
175
175
  function newTranscriptState() {
176
176
  return {
177
177
  offset: 0, // bytes already folded in
178
- touchedAt: 0,
179
178
  rootModel: null,
180
179
  lastModel: null, // last claude-* model on any line, sidechain included
181
180
  subagentModels: {},
@@ -259,14 +258,25 @@ function foldTranscriptLine(state, line) {
259
258
  }
260
259
  }
261
260
 
261
+ /** Record a use of `path` and keep the map under the cap. Re-inserting on
262
+ * every touch makes the Map's own insertion order the LRU order, so eviction
263
+ * reads one key instead of scanning for the smallest timestamp. Scanning a
264
+ * timestamp is also what broke the cache: a state is created with no stamp
265
+ * yet, so the entry the scan had just inserted was the smallest of all and
266
+ * the one deleted, every time. Past 256 distinct transcripts the map froze on
267
+ * the first 256 paths and every later transcript re-read its whole JSONL from
268
+ * byte 0 on every throttled pass — the O(n)-per-pass stall the cursor exists
269
+ * to remove. */
270
+ function touchTranscriptScan(path, state) {
271
+ transcriptScans.delete(path);
272
+ transcriptScans.set(path, state);
273
+ pruneTranscriptScans();
274
+ }
275
+
262
276
  function pruneTranscriptScans() {
263
- if (transcriptScans.size <= MAX_TRANSCRIPT_SCANS) return;
264
- let oldestPath = null;
265
- let oldestAt = Infinity;
266
- for (const [p, st] of transcriptScans) {
267
- if (st.touchedAt < oldestAt) { oldestAt = st.touchedAt; oldestPath = p; }
277
+ while (transcriptScans.size > MAX_TRANSCRIPT_SCANS) {
278
+ transcriptScans.delete(transcriptScans.keys().next().value);
268
279
  }
269
- if (oldestPath !== null) transcriptScans.delete(oldestPath);
270
280
  }
271
281
 
272
282
  /** Bring a transcript's scan state up to date and return it. Concurrent
@@ -279,20 +289,17 @@ function scanTranscript(path) {
279
289
  if (inFlight) return inFlight;
280
290
  const run = (async () => {
281
291
  let state = transcriptScans.get(path);
282
- if (!state) {
283
- state = newTranscriptState();
284
- transcriptScans.set(path, state);
285
- pruneTranscriptScans();
286
- }
287
- state.touchedAt = Date.now();
292
+ if (!state) state = newTranscriptState();
293
+ touchTranscriptScan(path, state);
288
294
  try {
289
295
  const s = await stat(path);
290
296
  // Shorter than the cursor means the file was truncated, rotated or
291
297
  // replaced — the offset now points at unrelated bytes, so start over.
292
298
  if (s.size < state.offset) {
293
299
  state = newTranscriptState();
294
- state.touchedAt = Date.now();
295
- transcriptScans.set(path, state);
300
+ // Touch again rather than set: the await above yielded, and another
301
+ // path's scan may have re-ordered or evicted this entry meanwhile.
302
+ touchTranscriptScan(path, state);
296
303
  }
297
304
  if (s.size <= state.offset) return state;
298
305
  const text = await readByteRange(path, state.offset, s.size);