@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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/watch.ts +3 -70
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcreflex/agent-transcripts",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "Transform AI coding agent session files into readable transcripts",
5
5
  "type": "module",
6
6
  "repository": {
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
- * Lockfile prevents concurrent watchers on the same archive.
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, unlinkSync, type FSWatcher } from "fs";
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;