claude-yes 1.29.2 → 1.31.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-yes",
3
- "version": "1.29.2",
3
+ "version": "1.31.0",
4
4
  "description": "A wrapper tool that automates interactions with various AI CLI tools by automatically handling common prompts and responses.",
5
5
  "keywords": [
6
6
  "claude",
@@ -50,13 +50,15 @@
50
50
  },
51
51
  "files": [
52
52
  "ts/*.ts",
53
- "dist"
53
+ "dist",
54
+ "scripts"
54
55
  ],
55
56
  "scripts": {
56
57
  "build": "bun run build:index && bun run build:cli",
57
58
  "postbuild": "bun ./ts/postbuild.ts",
58
- "build:cli": "bun build ts/cli.ts --outdir=dist --target=node --sourcemap --external=node-pty --external=bun-pty --external=from-node-stream",
59
- "build:index": "bun build ts/index.ts --outdir=dist --target=node --sourcemap --external=node-pty --external=bun-pty --external=from-node-stream",
59
+ "build:cli": "bun build ts/cli.ts --outdir=dist --target=node --sourcemap --external=bun-pty --external=node-pty --external=from-node-stream --external=bun",
60
+ "build:index": "bun build ts/index.ts --outdir=dist --target=node --sourcemap --external=bun-pty --external=node-pty --external=from-node-stream --external=bun",
61
+ "demo": "bun run build && bun link && claude-yes -- demo",
60
62
  "dev": "bun ts/index.ts",
61
63
  "fmt": "bunx @biomejs/biome check --fix && bunx sort-package-json",
62
64
  "prepack": "bun run build",
@@ -89,6 +91,7 @@
89
91
  ]
90
92
  },
91
93
  "dependencies": {
94
+ "bun": "^1.3.1",
92
95
  "bun-pty": "^0.3.2",
93
96
  "from-node-stream": "^0.0.11"
94
97
  },
@@ -100,13 +103,14 @@
100
103
  "@semantic-release/release-notes-generator": "^14.1.0",
101
104
  "@types/bun": "^1.2.18",
102
105
  "@types/jest": "^30.0.0",
106
+ "@types/ms": "^2.1.0",
103
107
  "@types/node": "^24.0.10",
104
108
  "@types/yargs": "^17.0.33",
105
109
  "cpu-wait": "^0.0.10",
106
- "enhanced-ms": "^4.1.0",
107
110
  "execa": "^9.6.0",
108
111
  "husky": "^9.1.7",
109
112
  "lint-staged": "^16.1.4",
113
+ "ms": "^2.1.3",
110
114
  "p-map": "^7.0.3",
111
115
  "phpdie": "^1.7.0",
112
116
  "rambda": "^10.3.2",
@@ -119,7 +123,12 @@
119
123
  "yargs": "^18.0.0"
120
124
  },
121
125
  "peerDependencies": {
122
- "node-pty": "^1.0.0",
126
+ "node-pty": "^1.1.0-beta38",
123
127
  "typescript": "^5.8.3"
128
+ },
129
+ "peerDependenciesMeta": {
130
+ "node-pty": {
131
+ "optional": true
132
+ }
124
133
  }
125
134
  }
@@ -1,7 +1,7 @@
1
1
  import { describe, expect, it } from 'vitest';
2
- import { catcher } from './tryCatch';
2
+ import { catcher } from './catcher';
3
3
 
4
- describe('tryCatch', () => {
4
+ describe('catcher', () => {
5
5
  describe('curried overload', () => {
6
6
  it('should return a function when called with only catchFn', () => {
7
7
  const catchFn = () => 'error';
@@ -9,10 +9,14 @@ describe('tryCatch', () => {
9
9
  expect(typeof result).toBe('function');
10
10
  });
11
11
 
12
- it('should catch errors and call catchFn', () => {
12
+ it('should catch errors and call catchFn with error, function, and args', () => {
13
13
  let catchedError: unknown;
14
- const catchFn = (error: unknown) => {
14
+ let catchedFn: unknown;
15
+ let catchedArgs: unknown[];
16
+ const catchFn = (error: unknown, fn: unknown, ...args: unknown[]) => {
15
17
  catchedError = error;
18
+ catchedFn = fn;
19
+ catchedArgs = args;
16
20
  return 'caught';
17
21
  };
18
22
 
@@ -27,6 +31,8 @@ describe('tryCatch', () => {
27
31
 
28
32
  expect(result).toBe('caught');
29
33
  expect(catchedError).toBeInstanceOf(Error);
34
+ expect(catchedFn).toBe(errorFn);
35
+ expect(catchedArgs).toEqual(['arg1', 'arg2']);
30
36
  expect(calledArgs).toEqual(['arg1', 'arg2']);
31
37
  });
32
38
 
@@ -53,10 +59,14 @@ describe('tryCatch', () => {
53
59
  });
54
60
 
55
61
  describe('direct overload', () => {
56
- it('should catch errors and call catchFn directly', () => {
62
+ it('should catch errors and call catchFn with error, function, and args directly', () => {
57
63
  let catchedError: unknown;
58
- const catchFn = (error: unknown) => {
64
+ let catchedFn: unknown;
65
+ let catchedArgs: unknown[];
66
+ const catchFn = (error: unknown, fn: unknown, ...args: unknown[]) => {
59
67
  catchedError = error;
68
+ catchedFn = fn;
69
+ catchedArgs = args;
60
70
  return 'caught';
61
71
  };
62
72
 
@@ -71,6 +81,8 @@ describe('tryCatch', () => {
71
81
 
72
82
  expect(result).toBe('caught');
73
83
  expect(catchedError).toBeInstanceOf(Error);
84
+ expect(catchedFn).toBe(errorFn);
85
+ expect(catchedArgs).toEqual(['arg1', 'arg2']);
74
86
  expect(calledArgs).toEqual(['arg1', 'arg2']);
75
87
  });
76
88
 
@@ -97,40 +109,52 @@ describe('tryCatch', () => {
97
109
  });
98
110
 
99
111
  describe('error handling', () => {
100
- it('should handle different error types', () => {
112
+ it('should handle different error types and pass function context', () => {
101
113
  const results: unknown[] = [];
102
- const catchFn = (error: unknown) => {
114
+ const functions: unknown[] = [];
115
+ const catchFn = (error: unknown, fn: unknown, ...args: unknown[]) => {
103
116
  results.push(error);
117
+ functions.push(fn);
104
118
  return 'handled';
105
119
  };
106
120
 
107
121
  // String error
108
- const stringErrorFn = catcher(catchFn, () => {
122
+ const stringErrorFn = () => {
109
123
  throw 'string error';
110
- });
111
- expect(stringErrorFn()).toBe('handled');
124
+ };
125
+ const wrappedStringFn = catcher(catchFn, stringErrorFn);
126
+ expect(wrappedStringFn()).toBe('handled');
112
127
  expect(results[0]).toBe('string error');
128
+ expect(functions[0]).toBe(stringErrorFn);
113
129
 
114
130
  // Object error
115
131
  const objectError = { message: 'object error' };
116
- const objectErrorFn = catcher(catchFn, () => {
132
+ const objectErrorFn = () => {
117
133
  throw objectError;
118
- });
119
- expect(objectErrorFn()).toBe('handled');
134
+ };
135
+ const wrappedObjectFn = catcher(catchFn, objectErrorFn);
136
+ expect(wrappedObjectFn()).toBe('handled');
120
137
  expect(results[1]).toBe(objectError);
138
+ expect(functions[1]).toBe(objectErrorFn);
121
139
 
122
140
  // null error
123
- const nullErrorFn = catcher(catchFn, () => {
141
+ const nullErrorFn = () => {
124
142
  throw null;
125
- });
126
- expect(nullErrorFn()).toBe('handled');
143
+ };
144
+ const wrappedNullFn = catcher(catchFn, nullErrorFn);
145
+ expect(wrappedNullFn()).toBe('handled');
127
146
  expect(results[2]).toBe(null);
147
+ expect(functions[2]).toBe(nullErrorFn);
128
148
  });
129
149
 
130
- it('should preserve function parameters', () => {
150
+ it('should preserve function parameters and pass them to catchFn', () => {
131
151
  let caughtError: unknown;
132
- const catchFn = (error: unknown) => {
152
+ let caughtFn: unknown;
153
+ let caughtArgs: unknown[];
154
+ const catchFn = (error: unknown, fn: unknown, ...args: unknown[]) => {
133
155
  caughtError = error;
156
+ caughtFn = fn;
157
+ caughtArgs = args;
134
158
  return 'caught';
135
159
  };
136
160
 
@@ -151,12 +175,18 @@ describe('tryCatch', () => {
151
175
  expect(wrappedFn(10, 'error', false)).toBe('caught');
152
176
  expect(testArgs).toEqual([10, 'error', false]);
153
177
  expect(caughtError).toBeInstanceOf(Error);
178
+ expect(caughtFn).toBe(testFn);
179
+ expect(caughtArgs).toEqual([10, 'error', false]);
154
180
  });
155
181
 
156
182
  it('should handle functions with no parameters', () => {
157
183
  let caughtError: unknown;
158
- const catchFn = (error: unknown) => {
184
+ let caughtFn: unknown;
185
+ let caughtArgs: unknown[];
186
+ const catchFn = (error: unknown, fn: unknown, ...args: unknown[]) => {
159
187
  caughtError = error;
188
+ caughtFn = fn;
189
+ caughtArgs = args;
160
190
  return 'no params caught';
161
191
  };
162
192
 
@@ -172,6 +202,8 @@ describe('tryCatch', () => {
172
202
  expect(result).toBe('no params caught');
173
203
  expect(called).toBe(true);
174
204
  expect(caughtError).toBeInstanceOf(Error);
205
+ expect(caughtFn).toBe(noParamsFn);
206
+ expect(caughtArgs).toEqual([]);
175
207
  });
176
208
 
177
209
  it('should handle functions returning different types', () => {
@@ -194,7 +226,8 @@ describe('tryCatch', () => {
194
226
 
195
227
  describe('type safety', () => {
196
228
  it('should maintain function signature', () => {
197
- const catchFn = (error: unknown) => 'error';
229
+ const catchFn = (error: unknown, fn: unknown, ...args: unknown[]) =>
230
+ 'error';
198
231
  const originalFn = (a: number, b: string): string => `${a}-${b}`;
199
232
 
200
233
  const wrappedFn = catcher(catchFn, originalFn);
@@ -203,5 +236,25 @@ describe('tryCatch', () => {
203
236
  const result: string = wrappedFn(1, 'test');
204
237
  expect(result).toBe('1-test');
205
238
  });
239
+
240
+ it('should pass function reference and arguments to catchFn', () => {
241
+ let capturedFn: unknown;
242
+ let capturedArgs: unknown[];
243
+ const catchFn = (error: unknown, fn: unknown, ...args: unknown[]) => {
244
+ capturedFn = fn;
245
+ capturedArgs = args;
246
+ return 'handled';
247
+ };
248
+
249
+ const testFn = (x: number, y: string) => {
250
+ throw new Error('test');
251
+ };
252
+
253
+ const wrappedFn = catcher(catchFn, testFn);
254
+ wrappedFn(42, 'hello');
255
+
256
+ expect(capturedFn).toBe(testFn);
257
+ expect(capturedArgs).toEqual([42, 'hello']);
258
+ });
206
259
  });
207
260
  });
package/ts/catcher.ts ADDED
@@ -0,0 +1,35 @@
1
+ // curried overload
2
+ export function catcher<F extends (...args: any[]) => any, R>(
3
+ catchFn: (error: unknown, fn: F, ...args: Parameters<F>) => R,
4
+ ): (fn: F) => (...args: Parameters<F>) => ReturnType<F> | R;
5
+
6
+ // direct overload
7
+ export function catcher<F extends (...args: any[]) => any, R>(
8
+ catchFn: (error: unknown, fn: F, ...args: Parameters<F>) => R,
9
+ fn: F,
10
+ ): (...args: Parameters<F>) => ReturnType<F> | R;
11
+
12
+ /**
13
+ * A utility function to wrap another function with a try-catch block.
14
+ * If an error occurs during the execution of the function, the provided
15
+ * catchFn is called with the error, the original function, and its arguments.
16
+ *
17
+ * This function supports both direct invocation and curried usage.
18
+ *
19
+ * @param catchFn - The function to call when an error occurs.
20
+ * @param fn - The function to wrap (optional for curried usage).
21
+ * @returns A new function that wraps the original function with error handling.
22
+ */
23
+ export function catcher<F extends (...args: any[]) => any, R>(
24
+ catchFn: (error: unknown, fn: F, ...args: Parameters<F>) => R,
25
+ fn?: F,
26
+ ) {
27
+ if (!fn) return (fn: F) => catcher(catchFn, fn) as any;
28
+ return (...args: Parameters<F>) => {
29
+ try {
30
+ return fn(...args);
31
+ } catch (error) {
32
+ return catchFn(error, fn, ...args);
33
+ }
34
+ };
35
+ }
package/ts/cli.ts CHANGED
@@ -1,14 +1,34 @@
1
1
  #!/usr/bin/env node
2
2
  import DIE from 'phpdie';
3
- import cliYes, { parseCliArgs } from './';
3
+ import cliYesConfig from '../cli-yes.config';
4
4
 
5
- // if (!globalThis.Bun) // run with same arguments in Bun
5
+ // if node-pty is not installed, re-run with bun
6
+ const hasNodePty = !!(await import('node-pty').catch(() => null));
7
+ if (!globalThis.Bun && !hasNodePty) {
8
+ // run with same arguments in Bun if not already
9
+ console.log('No node-pty installed. Re-running with Bun...', process.argv);
10
+ (await import('child_process')).spawnSync(
11
+ 'node_modules/.bin/bun',
12
+ [process.argv[1]!, '--', ...process.argv.slice(2)],
13
+ { stdio: 'inherit' },
14
+ );
15
+ process.exit(0);
16
+ }
17
+ // check and fix bun-pty on some systems
18
+ if (globalThis.Bun) console.log('Bun detected, using bun-pty');
19
+ // await import("./fix-pty.js")
20
+
21
+ // console.log('Running', process.argv);
22
+
23
+ // Import the CLI module
24
+ const { default: cliYes, parseCliArgs } = await import('./');
6
25
 
7
26
  // Parse CLI arguments
8
27
  const config = parseCliArgs(process.argv);
9
28
 
10
29
  // Validate CLI name
11
- if (!config.cli) DIE('missing cli def');
30
+ if (!config.cli)
31
+ DIE`missing cli def, available clis: ${Object.keys((await cliYesConfig).clis).join(', ')}`;
12
32
 
13
33
  if (config.verbose) {
14
34
  process.env.VERBOSE = 'true'; // enable verbose logging in yesLog.ts
@@ -68,10 +68,6 @@ describe('Codex Session Restoration', () => {
68
68
  // Create test directories
69
69
  await mkdir(cwd1, { recursive: true });
70
70
  await mkdir(cwd2, { recursive: true });
71
-
72
- // Build the project first
73
- const buildResult = await runCodexYes(['--help'], process.cwd(), 10000);
74
- console.log('Build check:', buildResult.exitCode === 0 ? 'OK' : 'FAILED');
75
71
  });
76
72
 
77
73
  afterAll(async () => {
@@ -0,0 +1,259 @@
1
+ import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
2
+ import { mkdir, rm, writeFile } from 'fs/promises';
3
+ import { tmpdir } from 'os';
4
+ import { join } from 'path';
5
+ import {
6
+ type CodexSession,
7
+ extractSessionId,
8
+ extractSessionIdFromSessionMeta,
9
+ getAllWorkingDirectories,
10
+ getRecentSessionsForCwd,
11
+ getSessionForCwd,
12
+ storeSessionForCwd,
13
+ } from './codexSessionManager';
14
+
15
+ // Create a temporary test directory
16
+ const testDir = join(tmpdir(), 'claude-yes-test-' + Date.now());
17
+ const testCodexDir = join(testDir, '.codex', 'sessions');
18
+ const testConfigDir = join(testDir, '.config', 'cli-yes');
19
+
20
+ // Store original environment
21
+ const originalTestHome = process.env.CLI_YES_TEST_HOME;
22
+
23
+ beforeEach(async () => {
24
+ // Set up test directories
25
+ await mkdir(testCodexDir, { recursive: true });
26
+ await mkdir(testConfigDir, { recursive: true });
27
+
28
+ // Set test home directory
29
+ process.env.CLI_YES_TEST_HOME = testDir;
30
+ });
31
+
32
+ afterEach(async () => {
33
+ // Clean up
34
+ process.env.CLI_YES_TEST_HOME = originalTestHome;
35
+ await rm(testDir, { recursive: true, force: true });
36
+ });
37
+
38
+ // Helper function to create a mock codex session file
39
+ async function createMockSessionFile(sessionData: {
40
+ id: string;
41
+ timestamp: string;
42
+ cwd: string;
43
+ git?: any;
44
+ }) {
45
+ const year = new Date(sessionData.timestamp).getFullYear();
46
+ const month = String(new Date(sessionData.timestamp).getMonth() + 1).padStart(
47
+ 2,
48
+ '0',
49
+ );
50
+ const day = String(new Date(sessionData.timestamp).getDate()).padStart(
51
+ 2,
52
+ '0',
53
+ );
54
+
55
+ const sessionDir = join(testCodexDir, String(year), month, day);
56
+ await mkdir(sessionDir, { recursive: true });
57
+
58
+ const filename = `test-session-${sessionData.id}.jsonl`;
59
+ const filePath = join(sessionDir, filename);
60
+
61
+ const sessionMeta = {
62
+ timestamp: sessionData.timestamp,
63
+ type: 'session_meta',
64
+ payload: {
65
+ id: sessionData.id,
66
+ timestamp: sessionData.timestamp,
67
+ cwd: sessionData.cwd,
68
+ originator: 'codex_cli_rs',
69
+ cli_version: '0.42.0',
70
+ instructions: null,
71
+ git: sessionData.git,
72
+ },
73
+ };
74
+
75
+ const content = JSON.stringify(sessionMeta) + '\n';
76
+ await writeFile(filePath, content);
77
+
78
+ return filePath;
79
+ }
80
+
81
+ describe('codexSessionManager', () => {
82
+ describe('extractSessionId', () => {
83
+ it('should extract valid session IDs from output', () => {
84
+ const output1 = 'Session ID: 019a4877-5f3c-7763-b573-513cc2d5d291';
85
+ const output2 =
86
+ 'Starting session 019a4877-5f3c-7763-b573-513cc2d5d291 for user';
87
+ const output3 = 'No session ID here';
88
+
89
+ expect(extractSessionId(output1)).toBe(
90
+ '019a4877-5f3c-7763-b573-513cc2d5d291',
91
+ );
92
+ expect(extractSessionId(output2)).toBe(
93
+ '019a4877-5f3c-7763-b573-513cc2d5d291',
94
+ );
95
+ expect(extractSessionId(output3)).toBeNull();
96
+ });
97
+ });
98
+
99
+ describe('extractSessionIdFromSessionMeta', () => {
100
+ it('should extract session ID from valid session metadata', () => {
101
+ const sessionContent = JSON.stringify({
102
+ timestamp: '2025-11-03T06:46:14.123Z',
103
+ type: 'session_meta',
104
+ payload: {
105
+ id: '019a4877-5f3c-7763-b573-513cc2d5d291',
106
+ cwd: '/test/path',
107
+ },
108
+ });
109
+
110
+ expect(extractSessionIdFromSessionMeta(sessionContent)).toBe(
111
+ '019a4877-5f3c-7763-b573-513cc2d5d291',
112
+ );
113
+ });
114
+
115
+ it('should fall back to regex extraction for invalid JSON', () => {
116
+ const invalidContent =
117
+ 'Invalid JSON but contains 019a4877-5f3c-7763-b573-513cc2d5d291';
118
+
119
+ expect(extractSessionIdFromSessionMeta(invalidContent)).toBe(
120
+ '019a4877-5f3c-7763-b573-513cc2d5d291',
121
+ );
122
+ });
123
+ });
124
+
125
+ describe('session storage and retrieval', () => {
126
+ it('should store and retrieve session IDs for directories', async () => {
127
+ const cwd = '/test/project';
128
+ const sessionId = '019a4877-5f3c-7763-b573-513cc2d5d291';
129
+
130
+ await storeSessionForCwd(cwd, sessionId);
131
+ const retrieved = await getSessionForCwd(cwd);
132
+
133
+ expect(retrieved).toBe(sessionId);
134
+ });
135
+
136
+ it('should return null for non-existent directories', async () => {
137
+ const result = await getSessionForCwd('/non/existent');
138
+ expect(result).toBeNull();
139
+ });
140
+ });
141
+
142
+ describe('codex session file parsing', () => {
143
+ it('should read sessions from actual codex files', async () => {
144
+ const sessionData = {
145
+ id: '019a4877-5f3c-7763-b573-513cc2d5d291',
146
+ timestamp: '2025-11-03T06:46:14.123Z',
147
+ cwd: '/v1/code/snomiao/claude-yes/tree/main',
148
+ git: {
149
+ commit_hash: 'abc123',
150
+ branch: 'main',
151
+ repository_url: 'git@github.com:snomiao/claude-yes.git',
152
+ },
153
+ };
154
+
155
+ await createMockSessionFile(sessionData);
156
+
157
+ const retrieved = await getSessionForCwd(sessionData.cwd);
158
+ expect(retrieved).toBe(sessionData.id);
159
+ });
160
+
161
+ it('should get recent sessions for a directory', async () => {
162
+ const cwd = '/test/project';
163
+ const sessions = [
164
+ {
165
+ id: 'session-1',
166
+ timestamp: '2025-11-03T10:00:00.000Z',
167
+ cwd,
168
+ },
169
+ {
170
+ id: 'session-2',
171
+ timestamp: '2025-11-03T09:00:00.000Z',
172
+ cwd,
173
+ },
174
+ {
175
+ id: 'session-3',
176
+ timestamp: '2025-11-03T08:00:00.000Z',
177
+ cwd,
178
+ },
179
+ ];
180
+
181
+ for (const session of sessions) {
182
+ await createMockSessionFile(session);
183
+ }
184
+
185
+ const recent = await getRecentSessionsForCwd(cwd, 2);
186
+ expect(recent).toHaveLength(2);
187
+ expect(recent[0].id).toBe('session-1'); // Most recent first
188
+ expect(recent[1].id).toBe('session-2');
189
+ });
190
+
191
+ it('should get all working directories with counts', async () => {
192
+ const sessions = [
193
+ {
194
+ id: 'session-1',
195
+ timestamp: '2025-11-03T10:00:00.000Z',
196
+ cwd: '/project-a',
197
+ },
198
+ {
199
+ id: 'session-2',
200
+ timestamp: '2025-11-03T09:00:00.000Z',
201
+ cwd: '/project-a',
202
+ },
203
+ {
204
+ id: 'session-3',
205
+ timestamp: '2025-11-03T08:00:00.000Z',
206
+ cwd: '/project-b',
207
+ },
208
+ ];
209
+
210
+ for (const session of sessions) {
211
+ await createMockSessionFile(session);
212
+ }
213
+
214
+ const directories = await getAllWorkingDirectories();
215
+ expect(directories).toHaveLength(2);
216
+
217
+ const projectA = directories.find((d) => d.cwd === '/project-a');
218
+ const projectB = directories.find((d) => d.cwd === '/project-b');
219
+
220
+ expect(projectA?.count).toBe(2);
221
+ expect(projectB?.count).toBe(1);
222
+
223
+ // Should be sorted by last session time (most recent first)
224
+ expect(directories[0].cwd).toBe('/project-a');
225
+ });
226
+ });
227
+
228
+ describe('fallback behavior', () => {
229
+ it('should fall back to stored mapping when no codex files exist', async () => {
230
+ const cwd = '/fallback/test';
231
+ const sessionId = 'fallback-session-id';
232
+
233
+ // Store in mapping but don't create codex file
234
+ await storeSessionForCwd(cwd, sessionId);
235
+
236
+ const retrieved = await getSessionForCwd(cwd);
237
+ expect(retrieved).toBe(sessionId);
238
+ });
239
+
240
+ it('should prefer codex files over stored mapping', async () => {
241
+ const cwd = '/preference/test';
242
+ const storedSessionId = 'stored-session';
243
+ const codexSessionId = 'codex-session';
244
+
245
+ // Store in mapping first
246
+ await storeSessionForCwd(cwd, storedSessionId);
247
+
248
+ // Create codex file with different session ID
249
+ await createMockSessionFile({
250
+ id: codexSessionId,
251
+ timestamp: '2025-11-03T10:00:00.000Z',
252
+ cwd,
253
+ });
254
+
255
+ const retrieved = await getSessionForCwd(cwd);
256
+ expect(retrieved).toBe(codexSessionId); // Should prefer codex file
257
+ });
258
+ });
259
+ });