claude-yes 1.30.0 → 1.31.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.
- package/dist/claude-yes.js +82 -11
- package/dist/cli.js +82 -11
- package/dist/cli.js.map +4 -4
- package/dist/codex-yes.js +82 -11
- package/dist/copilot-yes.js +82 -11
- package/dist/cursor-yes.js +82 -11
- package/dist/gemini-yes.js +82 -11
- package/dist/grok-yes.js +82 -11
- package/dist/index.js +79 -6
- package/dist/index.js.map +3 -3
- package/dist/qwen-yes.js +82 -11
- package/package.json +9 -4
- package/ts/cli.ts +3 -3
- package/ts/codex-resume.spec.ts +0 -4
- package/ts/codexSessionManager.test.ts +259 -0
- package/ts/codexSessionManager.ts +190 -10
package/dist/qwen-yes.js
CHANGED
|
@@ -14017,12 +14017,12 @@ function catcher(catchFn, fn) {
|
|
|
14017
14017
|
}
|
|
14018
14018
|
|
|
14019
14019
|
// ts/codexSessionManager.ts
|
|
14020
|
-
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
14020
|
+
import { mkdir, readdir, readFile, writeFile } from "fs/promises";
|
|
14021
14021
|
import { homedir } from "os";
|
|
14022
14022
|
import path7 from "path";
|
|
14023
14023
|
async function loadSessionMap() {
|
|
14024
14024
|
try {
|
|
14025
|
-
const content = await readFile(
|
|
14025
|
+
const content = await readFile(getSessionsFile(), "utf-8");
|
|
14026
14026
|
return JSON.parse(content);
|
|
14027
14027
|
} catch (error) {
|
|
14028
14028
|
return {};
|
|
@@ -14030,8 +14030,9 @@ async function loadSessionMap() {
|
|
|
14030
14030
|
}
|
|
14031
14031
|
async function saveSessionMap(sessionMap) {
|
|
14032
14032
|
try {
|
|
14033
|
-
|
|
14034
|
-
await
|
|
14033
|
+
const sessionsFile = getSessionsFile();
|
|
14034
|
+
await mkdir(path7.dirname(sessionsFile), { recursive: true });
|
|
14035
|
+
await writeFile(sessionsFile, JSON.stringify(sessionMap, null, 2));
|
|
14035
14036
|
} catch (error) {
|
|
14036
14037
|
console.warn("Failed to save codex session map:", error);
|
|
14037
14038
|
}
|
|
@@ -14044,7 +14045,78 @@ async function storeSessionForCwd(cwd, sessionId) {
|
|
|
14044
14045
|
};
|
|
14045
14046
|
await saveSessionMap(sessionMap);
|
|
14046
14047
|
}
|
|
14048
|
+
async function parseCodexSessionFile(filePath) {
|
|
14049
|
+
try {
|
|
14050
|
+
const content = await readFile(filePath, "utf-8");
|
|
14051
|
+
const lines2 = content.trim().split(`
|
|
14052
|
+
`);
|
|
14053
|
+
for (const line of lines2) {
|
|
14054
|
+
if (!line.trim())
|
|
14055
|
+
continue;
|
|
14056
|
+
const data = JSON.parse(line);
|
|
14057
|
+
if (data.type === "session_meta" && data.payload) {
|
|
14058
|
+
const payload = data.payload;
|
|
14059
|
+
return {
|
|
14060
|
+
id: payload.id,
|
|
14061
|
+
timestamp: payload.timestamp || data.timestamp,
|
|
14062
|
+
cwd: payload.cwd,
|
|
14063
|
+
filePath,
|
|
14064
|
+
git: payload.git
|
|
14065
|
+
};
|
|
14066
|
+
}
|
|
14067
|
+
}
|
|
14068
|
+
return null;
|
|
14069
|
+
} catch (error) {
|
|
14070
|
+
return null;
|
|
14071
|
+
}
|
|
14072
|
+
}
|
|
14073
|
+
async function getAllCodexSessions() {
|
|
14074
|
+
const sessions = [];
|
|
14075
|
+
const codexSessionsDir = getCodexSessionsDir();
|
|
14076
|
+
try {
|
|
14077
|
+
const years = await readdir(codexSessionsDir);
|
|
14078
|
+
for (const year of years) {
|
|
14079
|
+
const yearPath = path7.join(codexSessionsDir, year);
|
|
14080
|
+
try {
|
|
14081
|
+
const months = await readdir(yearPath);
|
|
14082
|
+
for (const month of months) {
|
|
14083
|
+
const monthPath = path7.join(yearPath, month);
|
|
14084
|
+
try {
|
|
14085
|
+
const days = await readdir(monthPath);
|
|
14086
|
+
for (const day of days) {
|
|
14087
|
+
const dayPath = path7.join(monthPath, day);
|
|
14088
|
+
try {
|
|
14089
|
+
const files = await readdir(dayPath);
|
|
14090
|
+
for (const file of files) {
|
|
14091
|
+
if (file.endsWith(".jsonl")) {
|
|
14092
|
+
const sessionPath = path7.join(dayPath, file);
|
|
14093
|
+
const session = await parseCodexSessionFile(sessionPath);
|
|
14094
|
+
if (session) {
|
|
14095
|
+
sessions.push(session);
|
|
14096
|
+
}
|
|
14097
|
+
}
|
|
14098
|
+
}
|
|
14099
|
+
} catch (error) {}
|
|
14100
|
+
}
|
|
14101
|
+
} catch (error) {}
|
|
14102
|
+
}
|
|
14103
|
+
} catch (error) {}
|
|
14104
|
+
}
|
|
14105
|
+
} catch (error) {
|
|
14106
|
+
return [];
|
|
14107
|
+
}
|
|
14108
|
+
return sessions.sort((a2, b) => new Date(b.timestamp).getTime() - new Date(a2.timestamp).getTime());
|
|
14109
|
+
}
|
|
14110
|
+
async function getMostRecentCodexSessionForCwd(targetCwd) {
|
|
14111
|
+
const allSessions = await getAllCodexSessions();
|
|
14112
|
+
const sessionsForCwd = allSessions.filter((session) => session.cwd === targetCwd);
|
|
14113
|
+
return sessionsForCwd[0] || null;
|
|
14114
|
+
}
|
|
14047
14115
|
async function getSessionForCwd(cwd) {
|
|
14116
|
+
const recentSession = await getMostRecentCodexSessionForCwd(cwd);
|
|
14117
|
+
if (recentSession) {
|
|
14118
|
+
return recentSession.id;
|
|
14119
|
+
}
|
|
14048
14120
|
const sessionMap = await loadSessionMap();
|
|
14049
14121
|
return sessionMap[cwd]?.sessionId || null;
|
|
14050
14122
|
}
|
|
@@ -14053,10 +14125,8 @@ function extractSessionId(output) {
|
|
|
14053
14125
|
const match = output.match(sessionIdRegex);
|
|
14054
14126
|
return match ? match[0] : null;
|
|
14055
14127
|
}
|
|
14056
|
-
var
|
|
14057
|
-
var init_codexSessionManager =
|
|
14058
|
-
SESSIONS_FILE = path7.join(homedir(), ".config", "cli-yes", "codex-sessions.json");
|
|
14059
|
-
});
|
|
14128
|
+
var getSessionsFile = () => process.env.CLI_YES_TEST_HOME ? path7.join(process.env.CLI_YES_TEST_HOME, ".config", "cli-yes", "codex-sessions.json") : path7.join(homedir(), ".config", "cli-yes", "codex-sessions.json"), getCodexSessionsDir = () => process.env.CLI_YES_TEST_HOME ? path7.join(process.env.CLI_YES_TEST_HOME, ".codex", "sessions") : path7.join(homedir(), ".codex", "sessions");
|
|
14129
|
+
var init_codexSessionManager = () => {};
|
|
14060
14130
|
|
|
14061
14131
|
// ts/idleWaiter.ts
|
|
14062
14132
|
class IdleWaiter {
|
|
@@ -20339,8 +20409,9 @@ var init_ts = __esm(async () => {
|
|
|
20339
20409
|
// ts/cli.ts
|
|
20340
20410
|
init_dist();
|
|
20341
20411
|
init_cli_yes_config();
|
|
20342
|
-
|
|
20343
|
-
|
|
20412
|
+
var hasNodePty = !!await import("node-pty").catch(() => null);
|
|
20413
|
+
if (!globalThis.Bun && !hasNodePty) {
|
|
20414
|
+
console.log("No node-pty installed. Re-running with Bun...", process.argv);
|
|
20344
20415
|
(await import("child_process")).spawnSync("node_modules/.bin/bun", [process.argv[1], "--", ...process.argv.slice(2)], { stdio: "inherit" });
|
|
20345
20416
|
process.exit(0);
|
|
20346
20417
|
}
|
|
@@ -20357,5 +20428,5 @@ if (config2.verbose) {
|
|
|
20357
20428
|
var { exitCode } = await cliYes2(config2);
|
|
20358
20429
|
process.exit(exitCode ?? 1);
|
|
20359
20430
|
|
|
20360
|
-
//# debugId=
|
|
20431
|
+
//# debugId=229819D0379CAA1264756E2164756E21
|
|
20361
20432
|
//# sourceMappingURL=cli.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-yes",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.31.1",
|
|
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",
|
|
@@ -91,11 +91,9 @@
|
|
|
91
91
|
]
|
|
92
92
|
},
|
|
93
93
|
"dependencies": {
|
|
94
|
-
"@types/ms": "^2.1.0",
|
|
95
94
|
"bun": "^1.3.1",
|
|
96
95
|
"bun-pty": "^0.3.2",
|
|
97
|
-
"from-node-stream": "^0.0
|
|
98
|
-
"ms": "^2.1.3"
|
|
96
|
+
"from-node-stream": "^0.1.0"
|
|
99
97
|
},
|
|
100
98
|
"devDependencies": {
|
|
101
99
|
"@biomejs/biome": "^2.2.5",
|
|
@@ -105,12 +103,14 @@
|
|
|
105
103
|
"@semantic-release/release-notes-generator": "^14.1.0",
|
|
106
104
|
"@types/bun": "^1.2.18",
|
|
107
105
|
"@types/jest": "^30.0.0",
|
|
106
|
+
"@types/ms": "^2.1.0",
|
|
108
107
|
"@types/node": "^24.0.10",
|
|
109
108
|
"@types/yargs": "^17.0.33",
|
|
110
109
|
"cpu-wait": "^0.0.10",
|
|
111
110
|
"execa": "^9.6.0",
|
|
112
111
|
"husky": "^9.1.7",
|
|
113
112
|
"lint-staged": "^16.1.4",
|
|
113
|
+
"ms": "^2.1.3",
|
|
114
114
|
"p-map": "^7.0.3",
|
|
115
115
|
"phpdie": "^1.7.0",
|
|
116
116
|
"rambda": "^10.3.2",
|
|
@@ -125,5 +125,10 @@
|
|
|
125
125
|
"peerDependencies": {
|
|
126
126
|
"node-pty": "^1.1.0-beta38",
|
|
127
127
|
"typescript": "^5.8.3"
|
|
128
|
+
},
|
|
129
|
+
"peerDependenciesMeta": {
|
|
130
|
+
"node-pty": {
|
|
131
|
+
"optional": true
|
|
132
|
+
}
|
|
128
133
|
}
|
|
129
134
|
}
|
package/ts/cli.ts
CHANGED
|
@@ -3,10 +3,10 @@ import DIE from 'phpdie';
|
|
|
3
3
|
import cliYesConfig from '../cli-yes.config';
|
|
4
4
|
|
|
5
5
|
// if node-pty is not installed, re-run with bun
|
|
6
|
-
|
|
7
|
-
if (!globalThis.Bun) {
|
|
6
|
+
const hasNodePty = !!(await import('node-pty').catch(() => null));
|
|
7
|
+
if (!globalThis.Bun && !hasNodePty) {
|
|
8
8
|
// run with same arguments in Bun if not already
|
|
9
|
-
console.log('Re-running with Bun...', process.argv);
|
|
9
|
+
console.log('No node-pty installed. Re-running with Bun...', process.argv);
|
|
10
10
|
(await import('child_process')).spawnSync(
|
|
11
11
|
'node_modules/.bin/bun',
|
|
12
12
|
[process.argv[1]!, '--', ...process.argv.slice(2)],
|
package/ts/codex-resume.spec.ts
CHANGED
|
@@ -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
|
+
});
|