claude-yes 1.31.1 → 1.32.1

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 (44) hide show
  1. package/README.md +225 -21
  2. package/dist/agent-yes.js +2 -0
  3. package/dist/amp-yes.js +2 -0
  4. package/dist/auggie-yes.js +2 -0
  5. package/dist/claude-yes.js +2 -20432
  6. package/dist/cli.js +18341 -10955
  7. package/dist/cli.js.map +141 -150
  8. package/dist/codex-yes.js +2 -20432
  9. package/dist/copilot-yes.js +2 -20432
  10. package/dist/cursor-yes.js +2 -20432
  11. package/dist/gemini-yes.js +2 -20432
  12. package/dist/grok-yes.js +2 -20432
  13. package/dist/index.js +16258 -13586
  14. package/dist/index.js.map +176 -191
  15. package/dist/qwen-yes.js +2 -20432
  16. package/package.json +95 -84
  17. package/ts/ReadyManager.spec.ts +10 -10
  18. package/ts/ReadyManager.ts +1 -1
  19. package/ts/SUPPORTED_CLIS.ts +4 -0
  20. package/ts/catcher.spec.ts +69 -70
  21. package/ts/cli-idle.spec.ts +8 -8
  22. package/ts/cli.ts +18 -26
  23. package/ts/defineConfig.ts +4 -4
  24. package/ts/idleWaiter.spec.ts +9 -9
  25. package/ts/index.ts +474 -233
  26. package/ts/logger.ts +22 -0
  27. package/ts/parseCliArgs.spec.ts +146 -147
  28. package/ts/parseCliArgs.ts +127 -59
  29. package/ts/postbuild.ts +29 -15
  30. package/ts/pty-fix.ts +155 -0
  31. package/ts/pty.ts +19 -0
  32. package/ts/removeControlCharacters.spec.ts +37 -38
  33. package/ts/removeControlCharacters.ts +2 -1
  34. package/ts/runningLock.spec.ts +119 -125
  35. package/ts/runningLock.ts +44 -55
  36. package/ts/session-integration.spec.ts +34 -42
  37. package/ts/utils.spec.ts +35 -35
  38. package/ts/utils.ts +7 -7
  39. package/ts/codex-resume.spec.ts +0 -239
  40. package/ts/codexSessionManager.spec.ts +0 -51
  41. package/ts/codexSessionManager.test.ts +0 -259
  42. package/ts/codexSessionManager.ts +0 -312
  43. package/ts/yesLog.spec.ts +0 -74
  44. package/ts/yesLog.ts +0 -27
@@ -1,9 +1,8 @@
1
- import { execSync } from 'child_process';
2
- import { existsSync } from 'fs';
3
- import { mkdir, readFile, rm, writeFile } from 'fs/promises';
4
- import { homedir } from 'os';
5
- import path from 'path';
6
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
1
+ import { execSync } from "child_process";
2
+ import { existsSync } from "fs";
3
+ import { mkdir, readFile, rm, writeFile } from "fs/promises";
4
+ import path from "path";
5
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
7
6
  import {
8
7
  acquireLock,
9
8
  cleanStaleLocks,
@@ -11,13 +10,16 @@ import {
11
10
  shouldUseLock,
12
11
  type Task,
13
12
  updateCurrentTaskStatus,
14
- } from './runningLock';
13
+ } from "./runningLock";
15
14
 
16
- const LOCK_DIR = path.join(homedir(), '.claude-yes');
17
- const LOCK_FILE = path.join(LOCK_DIR, 'running.lock.json');
18
- const TEST_DIR = path.join(process.cwd(), '.cache', 'test-lock');
15
+ // Keep lock files inside the repo to avoid $HOME permission issues in CI
16
+ process.env.CLAUDE_YES_HOME = path.join(process.cwd(), ".cache");
19
17
 
20
- describe('runningLock', () => {
18
+ const LOCK_DIR = path.join(process.env.CLAUDE_YES_HOME, ".claude-yes");
19
+ const LOCK_FILE = path.join(LOCK_DIR, "running.lock.json");
20
+ const TEST_DIR = path.join(process.cwd(), ".cache", "test-lock");
21
+
22
+ describe("runningLock", () => {
21
23
  beforeEach(async () => {
22
24
  // Clean up before each test
23
25
  await cleanupLockFile();
@@ -30,25 +32,25 @@ describe('runningLock', () => {
30
32
  await rm(TEST_DIR, { recursive: true, force: true });
31
33
  });
32
34
 
33
- describe('shouldUseLock', () => {
34
- it('should return true for any directory', () => {
35
+ describe("shouldUseLock", () => {
36
+ it("should return true for any directory", () => {
35
37
  expect(shouldUseLock(process.cwd())).toBe(true);
36
- expect(shouldUseLock('/tmp')).toBe(true);
38
+ expect(shouldUseLock("/tmp")).toBe(true);
37
39
  expect(shouldUseLock(TEST_DIR)).toBe(true);
38
40
  });
39
41
  });
40
42
 
41
- describe('acquireLock and releaseLock', () => {
42
- it('should acquire and release lock successfully', async () => {
43
- await acquireLock(TEST_DIR, 'Test task');
43
+ describe("acquireLock and releaseLock", () => {
44
+ it("should acquire and release lock successfully", async () => {
45
+ await acquireLock(TEST_DIR, "Test task");
44
46
 
45
47
  // Check lock file exists and contains task
46
48
  const lockData = await readLockFile();
47
49
  expect(lockData.tasks).toHaveLength(1);
48
50
  expect(lockData.tasks[0].cwd).toBe(path.resolve(TEST_DIR));
49
- expect(lockData.tasks[0].task).toBe('Test task');
51
+ expect(lockData.tasks[0].task).toBe("Test task");
50
52
  expect(lockData.tasks[0].pid).toBe(process.pid);
51
- expect(lockData.tasks[0].status).toBe('running');
53
+ expect(lockData.tasks[0].status).toBe("running");
52
54
 
53
55
  // Release lock
54
56
  await releaseLock();
@@ -58,11 +60,11 @@ describe('runningLock', () => {
58
60
  expect(lockDataAfter.tasks).toHaveLength(0);
59
61
  });
60
62
 
61
- it('should create lock directory if it does not exist', async () => {
63
+ it("should create lock directory if it does not exist", async () => {
62
64
  // Remove lock directory
63
65
  await rm(LOCK_DIR, { recursive: true, force: true });
64
66
 
65
- await acquireLock(TEST_DIR, 'Test task');
67
+ await acquireLock(TEST_DIR, "Test task");
66
68
 
67
69
  // Check directory and file exist
68
70
  expect(existsSync(LOCK_DIR)).toBe(true);
@@ -71,21 +73,21 @@ describe('runningLock', () => {
71
73
  await releaseLock();
72
74
  });
73
75
 
74
- it('should handle prompt longer than 100 characters', async () => {
75
- const longPrompt = 'A'.repeat(150);
76
+ it("should handle prompt longer than 100 characters", async () => {
77
+ const longPrompt = "A".repeat(150);
76
78
 
77
79
  await acquireLock(TEST_DIR, longPrompt);
78
80
 
79
81
  const lockData = await readLockFile();
80
82
  expect(lockData.tasks[0].task).toHaveLength(100);
81
- expect(lockData.tasks[0].task).toBe('A'.repeat(100));
83
+ expect(lockData.tasks[0].task).toBe("A".repeat(100));
82
84
 
83
85
  await releaseLock();
84
86
  });
85
87
 
86
- it('should include timestamp fields', async () => {
88
+ it("should include timestamp fields", async () => {
87
89
  const before = Date.now();
88
- await acquireLock(TEST_DIR, 'Test task');
90
+ await acquireLock(TEST_DIR, "Test task");
89
91
  const after = Date.now();
90
92
 
91
93
  const lockData = await readLockFile();
@@ -100,15 +102,15 @@ describe('runningLock', () => {
100
102
  });
101
103
  });
102
104
 
103
- describe('git repository detection', () => {
104
- it('should detect git root for repository', async () => {
105
+ describe("git repository detection", () => {
106
+ it("should detect git root for repository", async () => {
105
107
  // Use current directory which is a git repo
106
- const gitRoot = execSync('git rev-parse --show-toplevel', {
108
+ const gitRoot = execSync("git rev-parse --show-toplevel", {
107
109
  cwd: process.cwd(),
108
- encoding: 'utf8',
110
+ encoding: "utf8",
109
111
  }).trim();
110
112
 
111
- await acquireLock(process.cwd(), 'Git repo task');
113
+ await acquireLock(process.cwd(), "Git repo task");
112
114
 
113
115
  const lockData = await readLockFile();
114
116
  expect(lockData.tasks[0].gitRoot).toBe(gitRoot);
@@ -116,14 +118,14 @@ describe('runningLock', () => {
116
118
  await releaseLock();
117
119
  });
118
120
 
119
- it('should detect same git root for subdirectory', async () => {
120
- const gitRoot = execSync('git rev-parse --show-toplevel', {
121
+ it("should detect same git root for subdirectory", async () => {
122
+ const gitRoot = execSync("git rev-parse --show-toplevel", {
121
123
  cwd: process.cwd(),
122
- encoding: 'utf8',
124
+ encoding: "utf8",
123
125
  }).trim();
124
- const subdir = path.join(process.cwd(), 'docs');
126
+ const subdir = path.join(process.cwd(), "docs");
125
127
 
126
- await acquireLock(subdir, 'Subdirectory task');
128
+ await acquireLock(subdir, "Subdirectory task");
127
129
 
128
130
  const lockData = await readLockFile();
129
131
  expect(lockData.tasks[0].gitRoot).toBe(gitRoot);
@@ -132,13 +134,13 @@ describe('runningLock', () => {
132
134
  await releaseLock();
133
135
  });
134
136
 
135
- it('should not have gitRoot for non-git directory', async () => {
137
+ it("should not have gitRoot for non-git directory", async () => {
136
138
  // Create a temporary directory outside of any git repo
137
- const tempDir = path.join('/tmp', 'test-non-git-' + Date.now());
139
+ const tempDir = path.join("/tmp", "test-non-git-" + Date.now());
138
140
  await mkdir(tempDir, { recursive: true });
139
141
 
140
142
  try {
141
- await acquireLock(tempDir, 'Non-git task');
143
+ await acquireLock(tempDir, "Non-git task");
142
144
 
143
145
  const lockData = await readLockFile();
144
146
  expect(lockData.tasks[0].gitRoot).toBeUndefined();
@@ -151,35 +153,35 @@ describe('runningLock', () => {
151
153
  });
152
154
  });
153
155
 
154
- describe('updateCurrentTaskStatus', () => {
155
- it('should update task status', async () => {
156
- await acquireLock(TEST_DIR, 'Test task');
156
+ describe("updateCurrentTaskStatus", () => {
157
+ it("should update task status", async () => {
158
+ await acquireLock(TEST_DIR, "Test task");
157
159
 
158
160
  // Update to completed
159
- await updateCurrentTaskStatus('completed');
161
+ await updateCurrentTaskStatus("completed");
160
162
 
161
163
  let lockData = await readLockFile();
162
- expect(lockData.tasks[0].status).toBe('completed');
164
+ expect(lockData.tasks[0].status).toBe("completed");
163
165
 
164
166
  // Update to failed
165
- await updateCurrentTaskStatus('failed');
167
+ await updateCurrentTaskStatus("failed");
166
168
 
167
169
  lockData = await readLockFile();
168
- expect(lockData.tasks[0].status).toBe('failed');
170
+ expect(lockData.tasks[0].status).toBe("failed");
169
171
 
170
172
  await releaseLock();
171
173
  });
172
174
 
173
- it('should not throw when updating non-existent task', async () => {
175
+ it("should not throw when updating non-existent task", async () => {
174
176
  // Should complete without throwing
175
- await updateCurrentTaskStatus('completed');
177
+ await updateCurrentTaskStatus("completed");
176
178
  // If we got here, no error was thrown
177
179
  expect(true).toBe(true);
178
180
  });
179
181
  });
180
182
 
181
- describe('cleanStaleLocks', () => {
182
- it('should remove stale locks with invalid PIDs', async () => {
183
+ describe("cleanStaleLocks", () => {
184
+ it("should remove stale locks with invalid PIDs", async () => {
183
185
  // Use a PID that definitely doesn't exist
184
186
  const invalidPid = 9999999;
185
187
 
@@ -188,9 +190,9 @@ describe('runningLock', () => {
188
190
  tasks: [
189
191
  {
190
192
  cwd: TEST_DIR,
191
- task: 'Stale task',
193
+ task: "Stale task",
192
194
  pid: invalidPid,
193
- status: 'running' as const,
195
+ status: "running" as const,
194
196
  startedAt: Date.now() - 60000,
195
197
  lockedAt: Date.now() - 60000,
196
198
  },
@@ -201,25 +203,25 @@ describe('runningLock', () => {
201
203
  await writeFile(LOCK_FILE, JSON.stringify(staleLock, null, 2));
202
204
 
203
205
  // Verify the stale lock was written
204
- let rawContent = await readFile(LOCK_FILE, 'utf8');
206
+ let rawContent = await readFile(LOCK_FILE, "utf8");
205
207
  let rawData = JSON.parse(rawContent);
206
208
  expect(rawData.tasks).toHaveLength(1);
207
209
  expect(rawData.tasks[0].pid).toBe(invalidPid);
208
210
 
209
211
  // Now acquire a lock - this will trigger cleanup of stale locks
210
- await acquireLock(TEST_DIR, 'New task');
212
+ await acquireLock(TEST_DIR, "New task");
211
213
 
212
214
  // The stale lock should be cleaned, and only our new task should remain
213
215
  const lockData = await readLockFile();
214
216
  expect(lockData.tasks).toHaveLength(1);
215
217
  expect(lockData.tasks[0].pid).toBe(process.pid);
216
- expect(lockData.tasks[0].task).toBe('New task');
218
+ expect(lockData.tasks[0].task).toBe("New task");
217
219
 
218
220
  await releaseLock();
219
221
  });
220
222
 
221
- it('should keep valid locks with running PIDs', async () => {
222
- await acquireLock(TEST_DIR, 'Valid task');
223
+ it("should keep valid locks with running PIDs", async () => {
224
+ await acquireLock(TEST_DIR, "Valid task");
223
225
 
224
226
  // Clean stale locks (should not remove our lock)
225
227
  await cleanStaleLocks();
@@ -231,10 +233,10 @@ describe('runningLock', () => {
231
233
  await releaseLock();
232
234
  });
233
235
 
234
- it('should handle corrupted lock file', async () => {
236
+ it("should handle corrupted lock file", async () => {
235
237
  // Write invalid JSON
236
238
  await mkdir(LOCK_DIR, { recursive: true });
237
- await writeFile(LOCK_FILE, 'invalid json{{{');
239
+ await writeFile(LOCK_FILE, "invalid json{{{");
238
240
 
239
241
  // Reading the lock file should handle corruption gracefully
240
242
  const lockData = await readLockFile();
@@ -243,7 +245,7 @@ describe('runningLock', () => {
243
245
  expect(lockData.tasks).toHaveLength(0);
244
246
  });
245
247
 
246
- it('should handle missing lock file', async () => {
248
+ it("should handle missing lock file", async () => {
247
249
  await rm(LOCK_FILE, { force: true });
248
250
 
249
251
  // Reading non-existent lock file should return empty
@@ -252,23 +254,23 @@ describe('runningLock', () => {
252
254
  });
253
255
  });
254
256
 
255
- describe('concurrent access', () => {
256
- it('should handle multiple tasks from different processes', async () => {
257
+ describe("concurrent access", () => {
258
+ it("should handle multiple tasks from different processes", async () => {
257
259
  // Acquire first task
258
- await acquireLock(TEST_DIR, 'Task 1');
260
+ await acquireLock(TEST_DIR, "Task 1");
259
261
 
260
262
  // Verify the task exists
261
263
  let lockData = await readLockFile();
262
264
  expect(lockData.tasks).toHaveLength(1);
263
- expect(lockData.tasks[0].task).toBe('Task 1');
265
+ expect(lockData.tasks[0].task).toBe("Task 1");
264
266
 
265
267
  // Acquire a second task with the same PID (should replace the first)
266
- await acquireLock('/tmp', 'Task 2');
268
+ await acquireLock("/tmp", "Task 2");
267
269
 
268
270
  // Should have only one task (the latest one)
269
271
  lockData = await readLockFile();
270
272
  expect(lockData.tasks).toHaveLength(1);
271
- expect(lockData.tasks[0].task).toBe('Task 2');
273
+ expect(lockData.tasks[0].task).toBe("Task 2");
272
274
 
273
275
  await releaseLock();
274
276
 
@@ -277,52 +279,47 @@ describe('runningLock', () => {
277
279
  expect(finalLockData.tasks).toHaveLength(0);
278
280
  });
279
281
 
280
- it('should not duplicate tasks with same PID', async () => {
281
- await acquireLock(TEST_DIR, 'Task 1');
282
+ it("should not duplicate tasks with same PID", async () => {
283
+ await acquireLock(TEST_DIR, "Task 1");
282
284
 
283
285
  // Try to acquire again with same PID
284
- await acquireLock(TEST_DIR, 'Task 2');
286
+ await acquireLock(TEST_DIR, "Task 2");
285
287
 
286
288
  // Should only have one task
287
289
  const lockData = await readLockFile();
288
290
  expect(lockData.tasks).toHaveLength(1);
289
- expect(lockData.tasks[0].task).toBe('Task 2'); // Latest task
291
+ expect(lockData.tasks[0].task).toBe("Task 2"); // Latest task
290
292
 
291
293
  await releaseLock();
292
294
  });
293
295
  });
294
296
 
295
- describe('lock file structure', () => {
296
- it('should have all required fields', async () => {
297
- await acquireLock(TEST_DIR, 'Complete task');
297
+ describe("lock file structure", () => {
298
+ it("should have all required fields", async () => {
299
+ await acquireLock(TEST_DIR, "Complete task");
298
300
 
299
301
  const lockData = await readLockFile();
300
302
  const task = lockData.tasks[0];
301
303
 
302
- expect(task).toHaveProperty('cwd');
303
- expect(task).toHaveProperty('task');
304
- expect(task).toHaveProperty('pid');
305
- expect(task).toHaveProperty('status');
306
- expect(task).toHaveProperty('startedAt');
307
- expect(task).toHaveProperty('lockedAt');
304
+ expect(task).toHaveProperty("cwd");
305
+ expect(task).toHaveProperty("task");
306
+ expect(task).toHaveProperty("pid");
307
+ expect(task).toHaveProperty("status");
308
+ expect(task).toHaveProperty("startedAt");
309
+ expect(task).toHaveProperty("lockedAt");
308
310
 
309
- expect(typeof task.cwd).toBe('string');
310
- expect(typeof task.task).toBe('string');
311
- expect(typeof task.pid).toBe('number');
312
- expect(typeof task.status).toBe('string');
313
- expect(typeof task.startedAt).toBe('number');
314
- expect(typeof task.lockedAt).toBe('number');
311
+ expect(typeof task.cwd).toBe("string");
312
+ expect(typeof task.task).toBe("string");
313
+ expect(typeof task.pid).toBe("number");
314
+ expect(typeof task.status).toBe("string");
315
+ expect(typeof task.startedAt).toBe("number");
316
+ expect(typeof task.lockedAt).toBe("number");
315
317
 
316
318
  await releaseLock();
317
319
  });
318
320
 
319
- it('should have valid status values', async () => {
320
- const validStatuses: Task['status'][] = [
321
- 'running',
322
- 'queued',
323
- 'completed',
324
- 'failed',
325
- ];
321
+ it("should have valid status values", async () => {
322
+ const validStatuses: Task["status"][] = ["running", "queued", "completed", "failed"];
326
323
 
327
324
  for (const status of validStatuses) {
328
325
  await acquireLock(TEST_DIR, `Task with ${status}`);
@@ -336,30 +333,29 @@ describe('runningLock', () => {
336
333
  });
337
334
  });
338
335
 
339
- describe('edge cases', () => {
340
- it('should handle empty task description', async () => {
341
- await acquireLock(TEST_DIR, '');
336
+ describe("edge cases", () => {
337
+ it("should handle empty task description", async () => {
338
+ await acquireLock(TEST_DIR, "");
342
339
 
343
340
  const lockData = await readLockFile();
344
- expect(lockData.tasks[0].task).toBe('');
341
+ expect(lockData.tasks[0].task).toBe("");
345
342
 
346
343
  await releaseLock();
347
344
  });
348
345
 
349
- it('should handle special characters in task description', async () => {
350
- const specialTask =
351
- 'Task with "quotes" and \'apostrophes\' and \n newlines';
346
+ it("should handle special characters in task description", async () => {
347
+ const specialTask = "Task with \"quotes\" and 'apostrophes' and \n newlines";
352
348
 
353
349
  await acquireLock(TEST_DIR, specialTask);
354
350
 
355
351
  const lockData = await readLockFile();
356
- expect(lockData.tasks[0].task).toContain('quotes');
352
+ expect(lockData.tasks[0].task).toContain("quotes");
357
353
 
358
354
  await releaseLock();
359
355
  });
360
356
 
361
- it('should resolve symlinks to real paths', async () => {
362
- await acquireLock(TEST_DIR, 'Symlink test');
357
+ it("should resolve symlinks to real paths", async () => {
358
+ await acquireLock(TEST_DIR, "Symlink test");
363
359
 
364
360
  const lockData = await readLockFile();
365
361
  // Should be an absolute path
@@ -368,7 +364,7 @@ describe('runningLock', () => {
368
364
  await releaseLock();
369
365
  });
370
366
 
371
- it('should handle rapid acquire/release cycles', async () => {
367
+ it("should handle rapid acquire/release cycles", async () => {
372
368
  for (let i = 0; i < 10; i++) {
373
369
  await acquireLock(TEST_DIR, `Rapid task ${i}`);
374
370
  await releaseLock();
@@ -380,24 +376,24 @@ describe('runningLock', () => {
380
376
  });
381
377
  });
382
378
 
383
- describe('queueing behavior', () => {
384
- it('should detect when lock is held by same git repo', async () => {
385
- const gitRoot = execSync('git rev-parse --show-toplevel', {
379
+ describe("queueing behavior", () => {
380
+ it("should detect when lock is held by same git repo", async () => {
381
+ const gitRoot = execSync("git rev-parse --show-toplevel", {
386
382
  cwd: process.cwd(),
387
- encoding: 'utf8',
383
+ encoding: "utf8",
388
384
  }).trim();
389
385
 
390
386
  // Acquire lock at root
391
- await acquireLock(gitRoot, 'Root task');
387
+ await acquireLock(gitRoot, "Root task");
392
388
 
393
389
  // Create a lock with different PID to simulate another process
394
390
  const lockData = await readLockFile();
395
391
  lockData.tasks.push({
396
- cwd: path.join(gitRoot, 'subdirectory'),
392
+ cwd: path.join(gitRoot, "subdirectory"),
397
393
  gitRoot: gitRoot,
398
- task: 'Subdirectory task',
394
+ task: "Subdirectory task",
399
395
  pid: process.pid + 1,
400
- status: 'running',
396
+ status: "running",
401
397
  startedAt: Date.now(),
402
398
  lockedAt: Date.now(),
403
399
  });
@@ -405,15 +401,13 @@ describe('runningLock', () => {
405
401
 
406
402
  // Both tasks should be in the same git repo
407
403
  const updatedLockData = await readLockFile();
408
- const gitRoots = updatedLockData.tasks
409
- .map((t) => t.gitRoot)
410
- .filter((g) => g);
404
+ const gitRoots = updatedLockData.tasks.map((t) => t.gitRoot).filter((g) => g);
411
405
  expect(new Set(gitRoots).size).toBe(1); // All same git root
412
406
 
413
407
  await releaseLock();
414
408
  });
415
409
 
416
- it('should allow different directories without git repos', async () => {
410
+ it("should allow different directories without git repos", async () => {
417
411
  // Test that when we already have a task, acquiring a new one replaces it
418
412
  // (since both use the same PID)
419
413
 
@@ -421,10 +415,10 @@ describe('runningLock', () => {
421
415
  const lock = {
422
416
  tasks: [
423
417
  {
424
- cwd: '/tmp',
425
- task: 'Tmp task',
418
+ cwd: "/tmp",
419
+ task: "Tmp task",
426
420
  pid: process.pid,
427
- status: 'running' as const,
421
+ status: "running" as const,
428
422
  startedAt: Date.now(),
429
423
  lockedAt: Date.now(),
430
424
  },
@@ -435,27 +429,27 @@ describe('runningLock', () => {
435
429
  // Verify initial state
436
430
  let lockData = await readLockFile();
437
431
  expect(lockData.tasks).toHaveLength(1);
438
- expect(lockData.tasks[0].task).toBe('Tmp task');
432
+ expect(lockData.tasks[0].task).toBe("Tmp task");
439
433
 
440
434
  // Acquire lock for different directory (should replace the existing task)
441
- await acquireLock(TEST_DIR, 'Test task');
435
+ await acquireLock(TEST_DIR, "Test task");
442
436
 
443
437
  // Should only have the new task
444
438
  lockData = await readLockFile();
445
439
  expect(lockData.tasks).toHaveLength(1);
446
- expect(lockData.tasks[0].task).toBe('Test task');
440
+ expect(lockData.tasks[0].task).toBe("Test task");
447
441
 
448
442
  await releaseLock();
449
443
  });
450
444
  });
451
445
 
452
- describe('disableLock option', () => {
453
- it('should respect lock file operations when disableLock is false', async () => {
446
+ describe("disableLock option", () => {
447
+ it("should respect lock file operations when disableLock is false", async () => {
454
448
  // Clean up first
455
449
  await rm(LOCK_FILE, { force: true });
456
450
 
457
451
  // When disableLock is not used (default behavior), locks work normally
458
- await acquireLock(TEST_DIR, 'Test task');
452
+ await acquireLock(TEST_DIR, "Test task");
459
453
  expect(existsSync(LOCK_FILE)).toBe(true);
460
454
 
461
455
  const lockData = await readLockFile();
@@ -481,7 +475,7 @@ async function cleanupLockFile() {
481
475
 
482
476
  async function readLockFile(): Promise<{ tasks: Task[] }> {
483
477
  try {
484
- const content = await readFile(LOCK_FILE, 'utf8');
478
+ const content = await readFile(LOCK_FILE, "utf8");
485
479
  const lockFile = JSON.parse(content);
486
480
  // Don't clean stale locks in tests - we want to see the raw data
487
481
  return lockFile;