@arcreflex/agent-transcripts 0.1.11 → 0.1.12
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/watch.ts +3 -70
package/package.json
CHANGED
package/src/watch.ts
CHANGED
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
* Watch module: keep archive in sync with source directories.
|
|
3
3
|
*
|
|
4
4
|
* Uses fs.watch for change detection with periodic full scan as fallback.
|
|
5
|
-
*
|
|
5
|
+
* Multiple watchers can safely target the same archive — writes are atomic
|
|
6
|
+
* (tmp + rename) and archiving is idempotent.
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
|
-
import { watch,
|
|
9
|
-
import { join } from "path";
|
|
10
|
-
import { mkdir, writeFile, readFile } from "fs/promises";
|
|
9
|
+
import { watch, type FSWatcher } from "fs";
|
|
11
10
|
import { getAdapters } from "./adapters/index.ts";
|
|
12
11
|
import {
|
|
13
12
|
archiveAll,
|
|
@@ -23,63 +22,6 @@ export interface WatchOptions {
|
|
|
23
22
|
quiet?: boolean;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
|
-
function lockPath(archiveDir: string): string {
|
|
27
|
-
return join(archiveDir, "archive.lock");
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async function acquireLock(archiveDir: string): Promise<boolean> {
|
|
31
|
-
await mkdir(archiveDir, { recursive: true });
|
|
32
|
-
const lock = lockPath(archiveDir);
|
|
33
|
-
try {
|
|
34
|
-
await writeFile(lock, String(process.pid), { flag: "wx" });
|
|
35
|
-
return true;
|
|
36
|
-
} catch (err: unknown) {
|
|
37
|
-
if (
|
|
38
|
-
err &&
|
|
39
|
-
typeof err === "object" &&
|
|
40
|
-
"code" in err &&
|
|
41
|
-
err.code === "EEXIST"
|
|
42
|
-
) {
|
|
43
|
-
// Lock file exists — check if the holding process is still alive
|
|
44
|
-
try {
|
|
45
|
-
const existing = await readFile(lock, "utf-8");
|
|
46
|
-
const pid = parseInt(existing, 10);
|
|
47
|
-
if (!isNaN(pid)) {
|
|
48
|
-
try {
|
|
49
|
-
process.kill(pid, 0);
|
|
50
|
-
return false; // Process is alive, lock is held
|
|
51
|
-
} catch {
|
|
52
|
-
// Process is dead, stale lock — reclaim
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
await writeFile(lock, String(process.pid), { flag: "w" });
|
|
56
|
-
return true;
|
|
57
|
-
} catch {
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
throw err;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function releaseLock(archiveDir: string): void {
|
|
66
|
-
try {
|
|
67
|
-
unlinkSync(lockPath(archiveDir));
|
|
68
|
-
} catch (err: unknown) {
|
|
69
|
-
if (
|
|
70
|
-
err &&
|
|
71
|
-
typeof err === "object" &&
|
|
72
|
-
"code" in err &&
|
|
73
|
-
err.code === "ENOENT"
|
|
74
|
-
) {
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
console.error(
|
|
78
|
-
`Warning: failed to release lock: ${err instanceof Error ? err.message : String(err)}`,
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
25
|
export class ArchiveWatcher {
|
|
84
26
|
private sourceDirs: string[];
|
|
85
27
|
private archiveDir: string;
|
|
@@ -101,13 +43,6 @@ export class ArchiveWatcher {
|
|
|
101
43
|
}
|
|
102
44
|
|
|
103
45
|
async start(): Promise<void> {
|
|
104
|
-
const locked = await acquireLock(this.archiveDir);
|
|
105
|
-
if (!locked) {
|
|
106
|
-
throw new Error(
|
|
107
|
-
`Another watcher is already running on ${this.archiveDir}`,
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
46
|
// Initial scan
|
|
112
47
|
await this.scan();
|
|
113
48
|
|
|
@@ -143,8 +78,6 @@ export class ArchiveWatcher {
|
|
|
143
78
|
clearInterval(this.pollTimer);
|
|
144
79
|
this.pollTimer = null;
|
|
145
80
|
}
|
|
146
|
-
|
|
147
|
-
releaseLock(this.archiveDir);
|
|
148
81
|
}
|
|
149
82
|
|
|
150
83
|
private debounceTimer: ReturnType<typeof setTimeout> | null = null;
|