@sudocode-ai/claude-code-acp 0.12.10 → 0.13.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.
@@ -0,0 +1,32 @@
1
+ import { Readable, Writable } from "node:stream";
2
+ import { WritableStream, ReadableStream } from "node:stream/web";
3
+ import { Logger } from "./acp-agent.js";
4
+ import { ClaudeCodeSettings } from "./settings.js";
5
+ export declare class Pushable<T> implements AsyncIterable<T> {
6
+ private queue;
7
+ private resolvers;
8
+ private done;
9
+ push(item: T): void;
10
+ end(): void;
11
+ [Symbol.asyncIterator](): AsyncIterator<T>;
12
+ }
13
+ export declare function nodeToWebWritable(nodeStream: Writable): WritableStream<Uint8Array>;
14
+ export declare function nodeToWebReadable(nodeStream: Readable): ReadableStream<Uint8Array>;
15
+ export declare function unreachable(value: never, logger?: Logger): void;
16
+ export declare function sleep(time: number): Promise<void>;
17
+ export declare function loadManagedSettings(): ClaudeCodeSettings | null;
18
+ export declare function applyEnvironmentSettings(settings: ClaudeCodeSettings): void;
19
+ export interface ExtractLinesResult {
20
+ content: string;
21
+ wasLimited: boolean;
22
+ linesRead: number;
23
+ }
24
+ /**
25
+ * Extracts lines from file content with byte limit enforcement.
26
+ *
27
+ * @param fullContent - The complete file content
28
+ * @param maxContentLength - Maximum number of UTF-16 Code Units to return
29
+ * @returns Object containing extracted content and metadata
30
+ */
31
+ export declare function extractLinesWithByteLimit(fullContent: string, maxContentLength: number): ExtractLinesResult;
32
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjE,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAA0B,MAAM,eAAe,CAAC;AAG3E,qBAAa,QAAQ,CAAC,CAAC,CAAE,YAAW,aAAa,CAAC,CAAC,CAAC;IAClD,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,SAAS,CAA8C;IAC/D,OAAO,CAAC,IAAI,CAAS;IAErB,IAAI,CAAC,IAAI,EAAE,CAAC;IASZ,GAAG;IAQH,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC;CAgB3C;AAGD,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC,CAclF;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC,CAUlF;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,GAAE,MAAgB,QAQjE;AAED,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEjD;AAED,wBAAgB,mBAAmB,IAAI,kBAAkB,GAAG,IAAI,CAM/D;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAM3E;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EACnB,gBAAgB,EAAE,MAAM,GACvB,kBAAkB,CA8CpB"}
package/package.json CHANGED
@@ -3,15 +3,24 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.12.10",
6
+ "version": "0.13.1",
7
7
  "description": "An ACP-compatible coding agent powered by the Claude Code SDK (TypeScript)",
8
8
  "main": "dist/lib.js",
9
+ "types": "dist/lib.d.ts",
9
10
  "bin": {
10
11
  "claude-code-acp": "./dist/index.js"
11
12
  },
12
13
  "type": "module",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/lib.d.ts",
17
+ "import": "./dist/lib.js"
18
+ },
19
+ "./*": "./*"
20
+ },
13
21
  "files": [
14
22
  "dist/",
23
+ "!dist/tests/",
15
24
  "README.md",
16
25
  "LICENSE",
17
26
  "package.json"
@@ -25,6 +34,7 @@
25
34
  "format": "prettier --write .",
26
35
  "format:check": "prettier --check .",
27
36
  "check": "npm run lint && npm run format:check",
37
+ "sync-upstream": "git merge upstream/main",
28
38
  "test": "vitest",
29
39
  "test:integration": "RUN_INTEGRATION_TESTS=true vitest run",
30
40
  "test:run": "vitest run",
@@ -56,23 +66,23 @@
56
66
  "author": "Sudocode AI",
57
67
  "license": "Apache-2.0",
58
68
  "dependencies": {
59
- "@agentclientprotocol/sdk": "0.12.0",
60
- "@anthropic-ai/claude-agent-sdk": "0.1.70",
61
- "@modelcontextprotocol/sdk": "1.25.0",
62
- "diff": "8.0.2",
63
- "minimatch": "^10.1.1"
69
+ "@agentclientprotocol/sdk": "0.13.0",
70
+ "@anthropic-ai/claude-agent-sdk": "0.2.7",
71
+ "@modelcontextprotocol/sdk": "1.25.2",
72
+ "diff": "8.0.3",
73
+ "minimatch": "10.1.1"
64
74
  },
65
75
  "devDependencies": {
66
76
  "@anthropic-ai/sdk": "0.71.2",
67
- "@types/node": "25.0.2",
68
- "@typescript-eslint/eslint-plugin": "8.50.0",
69
- "@typescript-eslint/parser": "8.50.0",
77
+ "@types/node": "25.0.8",
78
+ "@typescript-eslint/eslint-plugin": "8.53.0",
79
+ "@typescript-eslint/parser": "8.53.0",
70
80
  "eslint": "9.39.2",
71
81
  "eslint-config-prettier": "10.1.8",
72
- "globals": "16.5.0",
73
- "prettier": "3.7.4",
82
+ "globals": "17.0.0",
83
+ "prettier": "3.8.0",
74
84
  "ts-node": "10.9.2",
75
85
  "typescript": "5.9.3",
76
- "vitest": "4.0.15"
86
+ "vitest": "4.0.17"
77
87
  }
78
88
  }
@@ -1,338 +0,0 @@
1
- /**
2
- * Tests for fork-related helper methods in ClaudeAcpAgent.
3
- *
4
- * Since the methods are private, we test them by:
5
- * 1. Creating a test subclass that exposes the private methods
6
- * 2. Testing the file manipulation logic directly
7
- */
8
- import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
9
- import { ClaudeAcpAgent } from "../acp-agent.js";
10
- import * as fs from "node:fs";
11
- import * as path from "node:path";
12
- import * as os from "node:os";
13
- // Create a test subclass that exposes private methods for testing
14
- class TestableClaudeAcpAgent extends ClaudeAcpAgent {
15
- // Expose private methods for testing
16
- testExtractInternalSessionId(filePath) {
17
- return this.extractInternalSessionId(filePath);
18
- }
19
- testPromoteToFullSession(filePath) {
20
- return this.promoteToFullSession(filePath);
21
- }
22
- testUpdateSessionIdInFile(filePath, newSessionId) {
23
- return this.updateSessionIdInFile(filePath, newSessionId);
24
- }
25
- testGetSessionDirPath(cwd) {
26
- return this.getSessionDirPath(cwd);
27
- }
28
- testGetSessionFilePath(sessionId, cwd) {
29
- return this.getSessionFilePath(sessionId, cwd);
30
- }
31
- async testDiscoverCliSessionId(sessionDir, beforeFiles, fallbackId, timeout) {
32
- return this.discoverCliSessionId(sessionDir, beforeFiles, fallbackId, timeout);
33
- }
34
- async testWaitForSessionFile(filePath, timeout) {
35
- return this.waitForSessionFile(filePath, timeout);
36
- }
37
- }
38
- describe("ClaudeAcpAgent fork helpers", () => {
39
- let tempDir;
40
- let agent;
41
- const mockLogger = {
42
- log: vi.fn(),
43
- error: vi.fn(),
44
- };
45
- // Create a minimal mock client
46
- const mockClient = {
47
- sessionUpdate: vi.fn(),
48
- readTextFile: vi.fn(),
49
- writeTextFile: vi.fn(),
50
- requestPermission: vi.fn(),
51
- };
52
- beforeEach(async () => {
53
- tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "acp-agent-fork-test-"));
54
- agent = new TestableClaudeAcpAgent(mockClient, mockLogger);
55
- vi.clearAllMocks();
56
- });
57
- afterEach(async () => {
58
- await fs.promises.rm(tempDir, { recursive: true, force: true });
59
- });
60
- describe("extractInternalSessionId", () => {
61
- it("should extract UUID sessionId from valid JSONL file", async () => {
62
- const filePath = path.join(tempDir, "session.jsonl");
63
- const sessionId = "12345678-1234-1234-1234-123456789abc";
64
- await fs.promises.writeFile(filePath, JSON.stringify({ sessionId, type: "init" }) + "\n");
65
- const result = agent.testExtractInternalSessionId(filePath);
66
- expect(result).toBe(sessionId);
67
- });
68
- it("should return null for non-existent file", () => {
69
- const result = agent.testExtractInternalSessionId(path.join(tempDir, "nonexistent.jsonl"));
70
- expect(result).toBeNull();
71
- });
72
- it("should return null for file without sessionId", async () => {
73
- const filePath = path.join(tempDir, "session.jsonl");
74
- await fs.promises.writeFile(filePath, JSON.stringify({ type: "init" }) + "\n");
75
- const result = agent.testExtractInternalSessionId(filePath);
76
- expect(result).toBeNull();
77
- });
78
- it("should return null for non-UUID sessionId", async () => {
79
- const filePath = path.join(tempDir, "session.jsonl");
80
- await fs.promises.writeFile(filePath, JSON.stringify({ sessionId: "not-a-uuid", type: "init" }) + "\n");
81
- const result = agent.testExtractInternalSessionId(filePath);
82
- expect(result).toBeNull();
83
- });
84
- it("should handle empty file", async () => {
85
- const filePath = path.join(tempDir, "session.jsonl");
86
- await fs.promises.writeFile(filePath, "");
87
- const result = agent.testExtractInternalSessionId(filePath);
88
- expect(result).toBeNull();
89
- });
90
- it("should find sessionId from first non-empty line", async () => {
91
- const filePath = path.join(tempDir, "session.jsonl");
92
- const sessionId = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee";
93
- await fs.promises.writeFile(filePath, "\n\n" + JSON.stringify({ sessionId, type: "init" }) + "\n");
94
- const result = agent.testExtractInternalSessionId(filePath);
95
- expect(result).toBe(sessionId);
96
- });
97
- });
98
- describe("promoteToFullSession", () => {
99
- it("should change isSidechain from true to false", async () => {
100
- const filePath = path.join(tempDir, "session.jsonl");
101
- const lines = [
102
- JSON.stringify({ sessionId: "test-id", isSidechain: true }),
103
- JSON.stringify({ type: "message", content: "hello" }),
104
- ];
105
- await fs.promises.writeFile(filePath, lines.join("\n"));
106
- const result = agent.testPromoteToFullSession(filePath);
107
- expect(result).toBe(true);
108
- const content = await fs.promises.readFile(filePath, "utf-8");
109
- const parsedLines = content.split("\n").map(line => JSON.parse(line));
110
- expect(parsedLines[0].isSidechain).toBe(false);
111
- expect(parsedLines[1].content).toBe("hello");
112
- });
113
- it("should return false for non-existent file", () => {
114
- const result = agent.testPromoteToFullSession(path.join(tempDir, "nonexistent.jsonl"));
115
- expect(result).toBe(false);
116
- });
117
- it("should preserve other fields when promoting", async () => {
118
- const filePath = path.join(tempDir, "session.jsonl");
119
- const original = {
120
- sessionId: "test-id",
121
- isSidechain: true,
122
- cwd: "/some/path",
123
- model: "claude-3",
124
- };
125
- await fs.promises.writeFile(filePath, JSON.stringify(original));
126
- agent.testPromoteToFullSession(filePath);
127
- const content = await fs.promises.readFile(filePath, "utf-8");
128
- const parsed = JSON.parse(content);
129
- expect(parsed.sessionId).toBe("test-id");
130
- expect(parsed.isSidechain).toBe(false);
131
- expect(parsed.cwd).toBe("/some/path");
132
- expect(parsed.model).toBe("claude-3");
133
- });
134
- it("should handle file without isSidechain field", async () => {
135
- const filePath = path.join(tempDir, "session.jsonl");
136
- await fs.promises.writeFile(filePath, JSON.stringify({ sessionId: "test-id", type: "init" }));
137
- const result = agent.testPromoteToFullSession(filePath);
138
- expect(result).toBe(true);
139
- const content = await fs.promises.readFile(filePath, "utf-8");
140
- const parsed = JSON.parse(content);
141
- expect(parsed.isSidechain).toBeUndefined();
142
- });
143
- it("should log success message", async () => {
144
- const filePath = path.join(tempDir, "session.jsonl");
145
- await fs.promises.writeFile(filePath, JSON.stringify({ sessionId: "test-id", isSidechain: true }));
146
- agent.testPromoteToFullSession(filePath);
147
- expect(mockLogger.log).toHaveBeenCalledWith(expect.stringContaining("Promoted sidechain to full session"));
148
- });
149
- });
150
- describe("updateSessionIdInFile", () => {
151
- it("should update sessionId in all lines", async () => {
152
- const filePath = path.join(tempDir, "session.jsonl");
153
- const oldId = "old-session-id";
154
- const newId = "new-session-id";
155
- const lines = [
156
- JSON.stringify({ sessionId: oldId, type: "init" }),
157
- JSON.stringify({ sessionId: oldId, type: "message", content: "hello" }),
158
- JSON.stringify({ sessionId: oldId, type: "tool_use", name: "Read" }),
159
- ];
160
- await fs.promises.writeFile(filePath, lines.join("\n"));
161
- const result = agent.testUpdateSessionIdInFile(filePath, newId);
162
- expect(result).toBe(true);
163
- const content = await fs.promises.readFile(filePath, "utf-8");
164
- const parsedLines = content.split("\n").map(line => JSON.parse(line));
165
- for (const line of parsedLines) {
166
- expect(line.sessionId).toBe(newId);
167
- }
168
- });
169
- it("should return false for non-existent file", () => {
170
- const result = agent.testUpdateSessionIdInFile(path.join(tempDir, "nonexistent.jsonl"), "new-id");
171
- expect(result).toBe(false);
172
- });
173
- it("should preserve lines without sessionId", async () => {
174
- const filePath = path.join(tempDir, "session.jsonl");
175
- const lines = [
176
- JSON.stringify({ sessionId: "old-id", type: "init" }),
177
- JSON.stringify({ type: "comment", text: "no sessionId here" }),
178
- ];
179
- await fs.promises.writeFile(filePath, lines.join("\n"));
180
- agent.testUpdateSessionIdInFile(filePath, "new-id");
181
- const content = await fs.promises.readFile(filePath, "utf-8");
182
- const parsedLines = content.split("\n").map(line => JSON.parse(line));
183
- expect(parsedLines[0].sessionId).toBe("new-id");
184
- expect(parsedLines[1].sessionId).toBeUndefined();
185
- expect(parsedLines[1].text).toBe("no sessionId here");
186
- });
187
- it("should handle empty lines gracefully", async () => {
188
- const filePath = path.join(tempDir, "session.jsonl");
189
- const content = JSON.stringify({ sessionId: "old-id" }) + "\n\n" + JSON.stringify({ sessionId: "old-id" });
190
- await fs.promises.writeFile(filePath, content);
191
- const result = agent.testUpdateSessionIdInFile(filePath, "new-id");
192
- expect(result).toBe(true);
193
- const newContent = await fs.promises.readFile(filePath, "utf-8");
194
- const lines = newContent.split("\n");
195
- expect(JSON.parse(lines[0]).sessionId).toBe("new-id");
196
- expect(lines[1]).toBe(""); // Empty line preserved
197
- expect(JSON.parse(lines[2]).sessionId).toBe("new-id");
198
- });
199
- it("should log success message", async () => {
200
- const filePath = path.join(tempDir, "session.jsonl");
201
- await fs.promises.writeFile(filePath, JSON.stringify({ sessionId: "old-id" }));
202
- agent.testUpdateSessionIdInFile(filePath, "new-id");
203
- expect(mockLogger.log).toHaveBeenCalledWith(expect.stringContaining("Updated session ID in file"));
204
- });
205
- });
206
- describe("getSessionDirPath", () => {
207
- it("should compute correct path with cwd hash", () => {
208
- const result = agent.testGetSessionDirPath("/private/tmp");
209
- const homeDir = os.homedir();
210
- expect(result).toBe(`${homeDir}/.claude/projects/-private-tmp`);
211
- });
212
- it("should replace both / and _ with -", () => {
213
- // Use tempDir which exists
214
- const testDir = path.join(tempDir, "my_project");
215
- fs.mkdirSync(testDir, { recursive: true });
216
- const result = agent.testGetSessionDirPath(testDir);
217
- const realPath = fs.realpathSync(testDir);
218
- const expectedHash = realPath.replace(/[/_]/g, "-");
219
- expect(result).toBe(`${os.homedir()}/.claude/projects/${expectedHash}`);
220
- });
221
- it("should resolve symlinks", () => {
222
- // /var on macOS is a symlink to /private/var
223
- const result = agent.testGetSessionDirPath("/var/tmp");
224
- const homeDir = os.homedir();
225
- // Should use the resolved path
226
- expect(result).toBe(`${homeDir}/.claude/projects/-private-var-tmp`);
227
- });
228
- });
229
- describe("getSessionFilePath", () => {
230
- it("should append sessionId.jsonl to session dir", () => {
231
- const result = agent.testGetSessionFilePath("my-session-id", "/private/tmp");
232
- const homeDir = os.homedir();
233
- expect(result).toBe(`${homeDir}/.claude/projects/-private-tmp/my-session-id.jsonl`);
234
- });
235
- });
236
- describe("waitForSessionFile", () => {
237
- it("should return true immediately if file exists", async () => {
238
- const filePath = path.join(tempDir, "session.jsonl");
239
- await fs.promises.writeFile(filePath, "{}");
240
- const start = Date.now();
241
- const result = await agent.testWaitForSessionFile(filePath, 1000);
242
- const elapsed = Date.now() - start;
243
- expect(result).toBe(true);
244
- expect(elapsed).toBeLessThan(200);
245
- });
246
- it("should return true when file appears before timeout", async () => {
247
- const filePath = path.join(tempDir, "session.jsonl");
248
- // Create file after 200ms
249
- setTimeout(async () => {
250
- await fs.promises.writeFile(filePath, "{}");
251
- }, 200);
252
- const start = Date.now();
253
- const result = await agent.testWaitForSessionFile(filePath, 2000);
254
- const elapsed = Date.now() - start;
255
- expect(result).toBe(true);
256
- expect(elapsed).toBeGreaterThanOrEqual(200);
257
- expect(elapsed).toBeLessThan(2000);
258
- });
259
- it("should return false when timeout expires", async () => {
260
- const filePath = path.join(tempDir, "nonexistent.jsonl");
261
- const start = Date.now();
262
- const result = await agent.testWaitForSessionFile(filePath, 300);
263
- const elapsed = Date.now() - start;
264
- expect(result).toBe(false);
265
- expect(elapsed).toBeGreaterThanOrEqual(300);
266
- expect(elapsed).toBeLessThan(500);
267
- });
268
- });
269
- describe("discoverCliSessionId", () => {
270
- it("should find new agent-xxx file", async () => {
271
- const sessionDir = path.join(tempDir, "sessions");
272
- await fs.promises.mkdir(sessionDir, { recursive: true });
273
- const beforeFiles = new Set();
274
- // Create an agent-xxx file
275
- const agentFile = "agent-abc123.jsonl";
276
- await fs.promises.writeFile(path.join(sessionDir, agentFile), "{}");
277
- const result = await agent.testDiscoverCliSessionId(sessionDir, beforeFiles, "fallback", 1000);
278
- expect(result).toBe("agent-abc123");
279
- });
280
- it("should ignore non-agent files", async () => {
281
- const sessionDir = path.join(tempDir, "sessions");
282
- await fs.promises.mkdir(sessionDir, { recursive: true });
283
- const beforeFiles = new Set();
284
- // Create a UUID-named file (not agent-xxx)
285
- const uuidFile = "12345678-1234-1234-1234-123456789abc.jsonl";
286
- await fs.promises.writeFile(path.join(sessionDir, uuidFile), "{}");
287
- const result = await agent.testDiscoverCliSessionId(sessionDir, beforeFiles, "fallback", 500);
288
- expect(result).toBe("fallback");
289
- });
290
- it("should return fallback when no new files found", async () => {
291
- const sessionDir = path.join(tempDir, "sessions");
292
- await fs.promises.mkdir(sessionDir, { recursive: true });
293
- const beforeFiles = new Set();
294
- const result = await agent.testDiscoverCliSessionId(sessionDir, beforeFiles, "fallback-id", 300);
295
- expect(result).toBe("fallback-id");
296
- });
297
- it("should ignore files that existed before", async () => {
298
- const sessionDir = path.join(tempDir, "sessions");
299
- await fs.promises.mkdir(sessionDir, { recursive: true });
300
- // Create file before
301
- const existingFile = "agent-existing.jsonl";
302
- await fs.promises.writeFile(path.join(sessionDir, existingFile), "{}");
303
- const beforeFiles = new Set([existingFile]);
304
- const result = await agent.testDiscoverCliSessionId(sessionDir, beforeFiles, "fallback", 300);
305
- expect(result).toBe("fallback");
306
- });
307
- it("should return newest file when multiple agent files appear", async () => {
308
- const sessionDir = path.join(tempDir, "sessions");
309
- await fs.promises.mkdir(sessionDir, { recursive: true });
310
- const beforeFiles = new Set();
311
- // Create first file - use hex chars to match agent-[a-f0-9]+ pattern
312
- const firstPath = path.join(sessionDir, "agent-aaa111.jsonl");
313
- await fs.promises.writeFile(firstPath, "{}");
314
- // Wait a bit to ensure different mtime, then create second file
315
- await new Promise(resolve => setTimeout(resolve, 100));
316
- const secondPath = path.join(sessionDir, "agent-bbb222.jsonl");
317
- await fs.promises.writeFile(secondPath, "{}");
318
- // Verify files exist before calling discover
319
- expect(fs.existsSync(firstPath)).toBe(true);
320
- expect(fs.existsSync(secondPath)).toBe(true);
321
- const result = await agent.testDiscoverCliSessionId(sessionDir, beforeFiles, "fallback", 1000);
322
- expect(result).toBe("agent-bbb222");
323
- });
324
- it("should handle non-existent session directory initially", async () => {
325
- const sessionDir = path.join(tempDir, "nonexistent-dir");
326
- const beforeFiles = new Set();
327
- // Start the discovery in parallel with file creation
328
- const discoverPromise = agent.testDiscoverCliSessionId(sessionDir, beforeFiles, "fallback", 2000);
329
- // Create directory and file after 200ms (within the 2000ms timeout)
330
- // Use hex chars to match agent-[a-f0-9]+ pattern
331
- await new Promise(resolve => setTimeout(resolve, 200));
332
- await fs.promises.mkdir(sessionDir, { recursive: true });
333
- await fs.promises.writeFile(path.join(sessionDir, "agent-ccc333.jsonl"), "{}");
334
- const result = await discoverPromise;
335
- expect(result).toBe("agent-ccc333");
336
- });
337
- });
338
- });