claude-code-watch 0.0.9 → 0.0.10
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.
- package/package.json +1 -1
- package/src/watcher/watcher.js +54 -6
package/package.json
CHANGED
package/src/watcher/watcher.js
CHANGED
|
@@ -456,8 +456,16 @@ class Watcher extends EventEmitter {
|
|
|
456
456
|
}
|
|
457
457
|
|
|
458
458
|
_handleFsWrite(p) {
|
|
459
|
-
|
|
460
|
-
|
|
459
|
+
let ctx = this.fileContexts.get(p);
|
|
460
|
+
|
|
461
|
+
// If fileContexts is missing (race condition during async session registration),
|
|
462
|
+
// try to infer the session context from the path
|
|
463
|
+
if (!ctx) {
|
|
464
|
+
ctx = this._inferFileContext(p);
|
|
465
|
+
if (!ctx) return;
|
|
466
|
+
// Register it so future events are found directly
|
|
467
|
+
this.fileContexts.set(p, ctx);
|
|
468
|
+
}
|
|
461
469
|
|
|
462
470
|
// Debounce
|
|
463
471
|
const existing = this.debounceTimers.get(p);
|
|
@@ -476,6 +484,28 @@ class Watcher extends EventEmitter {
|
|
|
476
484
|
this.debounceTimers.set(p, timer);
|
|
477
485
|
}
|
|
478
486
|
|
|
487
|
+
_inferFileContext(p) {
|
|
488
|
+
if (!p.endsWith('.jsonl')) return null;
|
|
489
|
+
|
|
490
|
+
// Subagent file: infer sessionID and agentID from path structure
|
|
491
|
+
if (p.includes('/subagents/')) {
|
|
492
|
+
const subagentsDir = path.dirname(p);
|
|
493
|
+
const sessionDir = path.dirname(subagentsDir);
|
|
494
|
+
const sessionID = path.basename(sessionDir);
|
|
495
|
+
const agentID = path.basename(p).replace(/^agent-/, '').replace(/\.jsonl$/, '');
|
|
496
|
+
const session = this.sessions.get(sessionID);
|
|
497
|
+
if (!session) return null;
|
|
498
|
+
return { sessionID, agentID };
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Main session file: infer sessionID from filename
|
|
502
|
+
const basename = path.basename(p);
|
|
503
|
+
const sessionID = basename.replace(/\.jsonl$/, '');
|
|
504
|
+
const session = this.sessions.get(sessionID);
|
|
505
|
+
if (!session) return null;
|
|
506
|
+
return { sessionID, agentID: '' };
|
|
507
|
+
}
|
|
508
|
+
|
|
479
509
|
// =========================================================================
|
|
480
510
|
// New session handlers
|
|
481
511
|
// =========================================================================
|
|
@@ -500,6 +530,12 @@ class Watcher extends EventEmitter {
|
|
|
500
530
|
this.emit('broadcast', 'newAgent', { sessionID: session.id, agentID, agentType });
|
|
501
531
|
}
|
|
502
532
|
|
|
533
|
+
// Read initial data from the new session's files
|
|
534
|
+
if (this.useFsnotify) {
|
|
535
|
+
await this._skipToEndOfFiles(session);
|
|
536
|
+
await this._readSessionFiles(session);
|
|
537
|
+
}
|
|
538
|
+
|
|
503
539
|
// Process any subagent files that arrived before the session was discovered
|
|
504
540
|
const pending = this.pendingSubagents.get(session.id);
|
|
505
541
|
if (pending) {
|
|
@@ -537,6 +573,13 @@ class Watcher extends EventEmitter {
|
|
|
537
573
|
|
|
538
574
|
this._addFileWatch(p, sessionID, agentID);
|
|
539
575
|
this.emit('broadcast', 'newAgent', { sessionID, agentID, agentType });
|
|
576
|
+
|
|
577
|
+
// Read initial data from the new subagent file
|
|
578
|
+
if (this.useFsnotify) {
|
|
579
|
+
const pos = await this._findPositionForLastNLines(p, KeepRecentLines);
|
|
580
|
+
this.filePositions.set(p, pos);
|
|
581
|
+
await this._readFile(p, sessionID, agentID, agentType);
|
|
582
|
+
}
|
|
540
583
|
}
|
|
541
584
|
|
|
542
585
|
async _handleNewToolResultFile(p) {
|
|
@@ -610,6 +653,8 @@ class Watcher extends EventEmitter {
|
|
|
610
653
|
|
|
611
654
|
if (this.useFsnotify) {
|
|
612
655
|
this._registerSessionWatches(c.session);
|
|
656
|
+
await this._skipToEndOfFiles(c.session);
|
|
657
|
+
await this._readSessionFiles(c.session);
|
|
613
658
|
}
|
|
614
659
|
|
|
615
660
|
this.emit('broadcast', 'newSession', { sessionID: c.session.id, projectPath: c.session.projectPath });
|
|
@@ -914,15 +959,16 @@ class Watcher extends EventEmitter {
|
|
|
914
959
|
newPos = pos;
|
|
915
960
|
// Read in chunks to avoid large buffer allocations for big file deltas
|
|
916
961
|
let carryOver = ''; // incomplete trailing line from previous chunk
|
|
962
|
+
let carryOverBytes = 0; // byte length of carryOver (to avoid re-reading it)
|
|
917
963
|
const buf = Buffer.alloc(MaxReadChunk);
|
|
918
964
|
|
|
919
965
|
while (true) {
|
|
920
966
|
const currentStats = await handle.stat();
|
|
921
|
-
const
|
|
922
|
-
if (
|
|
967
|
+
const readFrom = newPos + carryOverBytes;
|
|
968
|
+
if (readFrom >= currentStats.size) break;
|
|
923
969
|
|
|
924
|
-
const readLen = Math.min(MaxReadChunk, currentStats.size -
|
|
925
|
-
const { bytesRead } = await handle.read(buf, 0, readLen,
|
|
970
|
+
const readLen = Math.min(MaxReadChunk, currentStats.size - readFrom);
|
|
971
|
+
const { bytesRead } = await handle.read(buf, 0, readLen, readFrom);
|
|
926
972
|
if (bytesRead === 0) break;
|
|
927
973
|
|
|
928
974
|
const chunk = bytesRead < readLen ? buf.toString('utf-8', 0, bytesRead) : buf.toString('utf-8');
|
|
@@ -939,9 +985,11 @@ class Watcher extends EventEmitter {
|
|
|
939
985
|
// Save it as carryOver for the next chunk; don't process it yet.
|
|
940
986
|
if (!chunk.endsWith('\n')) {
|
|
941
987
|
carryOver = rawLines.pop();
|
|
988
|
+
carryOverBytes = Buffer.byteLength(carryOver, 'utf-8');
|
|
942
989
|
} else {
|
|
943
990
|
// chunk ends with \n — split produces a trailing empty string; clear carryOver
|
|
944
991
|
carryOver = '';
|
|
992
|
+
carryOverBytes = 0;
|
|
945
993
|
}
|
|
946
994
|
|
|
947
995
|
let chunkBytes = 0;
|