claude-yes 1.31.2 → 1.32.2

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 +18342 -10955
  7. package/dist/codex-yes.js +2 -20432
  8. package/dist/copilot-yes.js +2 -20432
  9. package/dist/cursor-yes.js +2 -20432
  10. package/dist/gemini-yes.js +2 -20432
  11. package/dist/grok-yes.js +2 -20432
  12. package/dist/index.js +16258 -13586
  13. package/dist/qwen-yes.js +2 -20432
  14. package/package.json +93 -81
  15. package/ts/ReadyManager.spec.ts +10 -10
  16. package/ts/ReadyManager.ts +1 -1
  17. package/ts/SUPPORTED_CLIS.ts +4 -0
  18. package/ts/catcher.spec.ts +69 -70
  19. package/ts/cli-idle.spec.ts +8 -8
  20. package/ts/cli.ts +18 -26
  21. package/ts/defineConfig.ts +4 -4
  22. package/ts/idleWaiter.spec.ts +9 -9
  23. package/ts/index.ts +474 -233
  24. package/ts/logger.ts +22 -0
  25. package/ts/parseCliArgs.spec.ts +146 -147
  26. package/ts/parseCliArgs.ts +127 -59
  27. package/ts/postbuild.ts +29 -15
  28. package/ts/pty-fix.ts +155 -0
  29. package/ts/pty.ts +19 -0
  30. package/ts/removeControlCharacters.spec.ts +37 -38
  31. package/ts/removeControlCharacters.ts +2 -1
  32. package/ts/runningLock.spec.ts +119 -125
  33. package/ts/runningLock.ts +44 -55
  34. package/ts/session-integration.spec.ts +34 -42
  35. package/ts/utils.spec.ts +35 -35
  36. package/ts/utils.ts +7 -7
  37. package/dist/cli.js.map +0 -365
  38. package/dist/index.js.map +0 -323
  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,312 +0,0 @@
1
- import { mkdir, readdir, readFile, writeFile } from 'fs/promises';
2
- import { homedir } from 'os';
3
- import path from 'path';
4
-
5
- // Allow overriding for testing
6
- export const getSessionsFile = () =>
7
- process.env.CLI_YES_TEST_HOME
8
- ? path.join(
9
- process.env.CLI_YES_TEST_HOME,
10
- '.config',
11
- 'cli-yes',
12
- 'codex-sessions.json',
13
- )
14
- : path.join(homedir(), '.config', 'cli-yes', 'codex-sessions.json');
15
-
16
- export const getCodexSessionsDir = () =>
17
- process.env.CLI_YES_TEST_HOME
18
- ? path.join(process.env.CLI_YES_TEST_HOME, '.codex', 'sessions')
19
- : path.join(homedir(), '.codex', 'sessions');
20
-
21
- export interface CodexSessionMap {
22
- [cwd: string]: {
23
- sessionId: string;
24
- lastUsed: string; // ISO timestamp
25
- };
26
- }
27
-
28
- export interface CodexSession {
29
- id: string;
30
- timestamp: string;
31
- cwd: string;
32
- filePath: string;
33
- git?: {
34
- commit_hash: string;
35
- branch: string;
36
- repository_url: string;
37
- };
38
- }
39
-
40
- /**
41
- * Load the session map from the config file
42
- */
43
- export async function loadSessionMap(): Promise<CodexSessionMap> {
44
- try {
45
- const content = await readFile(getSessionsFile(), 'utf-8');
46
- return JSON.parse(content);
47
- } catch (error) {
48
- // File doesn't exist or is invalid, return empty map
49
- return {};
50
- }
51
- }
52
-
53
- /**
54
- * Save the session map to the config file
55
- */
56
- export async function saveSessionMap(
57
- sessionMap: CodexSessionMap,
58
- ): Promise<void> {
59
- try {
60
- const sessionsFile = getSessionsFile();
61
- // Ensure the directory exists
62
- await mkdir(path.dirname(sessionsFile), { recursive: true });
63
- await writeFile(sessionsFile, JSON.stringify(sessionMap, null, 2));
64
- } catch (error) {
65
- console.warn('Failed to save codex session map:', error);
66
- }
67
- }
68
-
69
- /**
70
- * Store a session ID for a specific working directory
71
- */
72
- export async function storeSessionForCwd(
73
- cwd: string,
74
- sessionId: string,
75
- ): Promise<void> {
76
- const sessionMap = await loadSessionMap();
77
- sessionMap[cwd] = {
78
- sessionId,
79
- lastUsed: new Date().toISOString(),
80
- };
81
- await saveSessionMap(sessionMap);
82
- }
83
-
84
- /**
85
- * Parse a codex session file to extract session metadata
86
- */
87
- async function parseCodexSessionFile(
88
- filePath: string,
89
- ): Promise<CodexSession | null> {
90
- try {
91
- const content = await readFile(filePath, 'utf-8');
92
- const lines = content.trim().split('\n');
93
-
94
- // Find the session_meta line
95
- for (const line of lines) {
96
- if (!line.trim()) continue;
97
-
98
- const data = JSON.parse(line);
99
- if (data.type === 'session_meta' && data.payload) {
100
- const payload = data.payload;
101
- return {
102
- id: payload.id,
103
- timestamp: payload.timestamp || data.timestamp,
104
- cwd: payload.cwd,
105
- filePath,
106
- git: payload.git,
107
- };
108
- }
109
- }
110
-
111
- return null;
112
- } catch (error) {
113
- // Ignore files that can't be parsed
114
- return null;
115
- }
116
- }
117
-
118
- /**
119
- * Get all codex sessions from the .codex/sessions directory
120
- */
121
- async function getAllCodexSessions(): Promise<CodexSession[]> {
122
- const sessions: CodexSession[] = [];
123
- const codexSessionsDir = getCodexSessionsDir();
124
-
125
- try {
126
- // Walk through year/month/day structure
127
- const years = await readdir(codexSessionsDir);
128
-
129
- for (const year of years) {
130
- const yearPath = path.join(codexSessionsDir, year);
131
- try {
132
- const months = await readdir(yearPath);
133
-
134
- for (const month of months) {
135
- const monthPath = path.join(yearPath, month);
136
- try {
137
- const days = await readdir(monthPath);
138
-
139
- for (const day of days) {
140
- const dayPath = path.join(monthPath, day);
141
- try {
142
- const files = await readdir(dayPath);
143
-
144
- for (const file of files) {
145
- if (file.endsWith('.jsonl')) {
146
- const sessionPath = path.join(dayPath, file);
147
- const session = await parseCodexSessionFile(sessionPath);
148
- if (session) {
149
- sessions.push(session);
150
- }
151
- }
152
- }
153
- } catch (error) {
154
- // Skip directories we can't read
155
- }
156
- }
157
- } catch (error) {
158
- // Skip directories we can't read
159
- }
160
- }
161
- } catch (error) {
162
- // Skip directories we can't read
163
- }
164
- }
165
- } catch (error) {
166
- // .codex/sessions directory doesn't exist or can't be read
167
- return [];
168
- }
169
-
170
- return sessions.sort(
171
- (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime(),
172
- );
173
- }
174
-
175
- /**
176
- * Get the most recent session for a specific working directory from actual codex files
177
- */
178
- async function getMostRecentCodexSessionForCwd(
179
- targetCwd: string,
180
- ): Promise<CodexSession | null> {
181
- const allSessions = await getAllCodexSessions();
182
- const sessionsForCwd = allSessions.filter(
183
- (session) => session.cwd === targetCwd,
184
- );
185
- return sessionsForCwd[0] || null;
186
- }
187
-
188
- /**
189
- * Get the last session ID for a specific working directory
190
- * Now checks actual codex session files first, falls back to stored mapping
191
- */
192
- export async function getSessionForCwd(cwd: string): Promise<string | null> {
193
- // First try to get the most recent session from actual codex files
194
- const recentSession = await getMostRecentCodexSessionForCwd(cwd);
195
- if (recentSession) {
196
- return recentSession.id;
197
- }
198
-
199
- // Fall back to stored mapping
200
- const sessionMap = await loadSessionMap();
201
- return sessionMap[cwd]?.sessionId || null;
202
- }
203
-
204
- /**
205
- * Extract session ID from codex output
206
- * Session IDs are UUIDs in the format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
207
- */
208
- export function extractSessionId(output: string): string | null {
209
- // Look for session ID in various contexts where it might appear
210
- const sessionIdRegex =
211
- /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/i;
212
- const match = output.match(sessionIdRegex);
213
- return match ? match[0] : null;
214
- }
215
-
216
- /**
217
- * Extract session ID from codex session file content
218
- * More reliable method that parses the session metadata
219
- */
220
- export function extractSessionIdFromSessionMeta(
221
- sessionContent: string,
222
- ): string | null {
223
- try {
224
- // Parse the first line which should contain session metadata
225
- const firstLine = sessionContent.split('\n')[0];
226
- const sessionMeta = JSON.parse(firstLine);
227
-
228
- if (sessionMeta.type === 'session_meta' && sessionMeta.payload?.id) {
229
- return sessionMeta.payload.id;
230
- }
231
- } catch (error) {
232
- // If parsing fails, fall back to regex extraction
233
- }
234
-
235
- return extractSessionId(sessionContent);
236
- }
237
-
238
- /**
239
- * Get recent sessions for a specific working directory from actual codex files
240
- */
241
- export async function getRecentSessionsForCwd(
242
- targetCwd: string,
243
- limit = 5,
244
- ): Promise<CodexSession[]> {
245
- const allSessions = await getAllCodexSessions();
246
- const sessionsForCwd = allSessions.filter(
247
- (session) => session.cwd === targetCwd,
248
- );
249
- return sessionsForCwd.slice(0, limit);
250
- }
251
-
252
- /**
253
- * Get all working directories with session counts from actual codex files
254
- */
255
- export async function getAllWorkingDirectories(): Promise<
256
- { cwd: string; count: number; lastSession: string }[]
257
- > {
258
- const allSessions = await getAllCodexSessions();
259
- const cwdMap = new Map<string, { count: number; lastSession: string }>();
260
-
261
- for (const session of allSessions) {
262
- const existing = cwdMap.get(session.cwd);
263
- if (existing) {
264
- existing.count++;
265
- if (new Date(session.timestamp) > new Date(existing.lastSession)) {
266
- existing.lastSession = session.timestamp;
267
- }
268
- } else {
269
- cwdMap.set(session.cwd, {
270
- count: 1,
271
- lastSession: session.timestamp,
272
- });
273
- }
274
- }
275
-
276
- return Array.from(cwdMap.entries())
277
- .map(([cwd, data]) => ({ cwd, ...data }))
278
- .sort(
279
- (a, b) =>
280
- new Date(b.lastSession).getTime() - new Date(a.lastSession).getTime(),
281
- );
282
- }
283
-
284
- /**
285
- * Clean up old sessions (keep only the most recent 10 per directory)
286
- */
287
- export async function cleanupOldSessions(): Promise<void> {
288
- const sessionMap = await loadSessionMap();
289
-
290
- // Group sessions by directory and keep only the most recent ones
291
- const cleaned: CodexSessionMap = {};
292
-
293
- // Sort all sessions by lastUsed date (most recent first)
294
- const sortedEntries = Object.entries(sessionMap).sort(
295
- ([, a], [, b]) =>
296
- new Date(b.lastUsed).getTime() - new Date(a.lastUsed).getTime(),
297
- );
298
-
299
- // Keep track of how many sessions we've kept per directory
300
- const dirCounts: { [dir: string]: number } = {};
301
-
302
- for (const [cwd, session] of sortedEntries) {
303
- const count = dirCounts[cwd] || 0;
304
- if (count < 5) {
305
- // Keep up to 5 sessions per directory
306
- cleaned[cwd] = session;
307
- dirCounts[cwd] = count + 1;
308
- }
309
- }
310
-
311
- await saveSessionMap(cleaned);
312
- }
package/ts/yesLog.spec.ts DELETED
@@ -1,74 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
2
-
3
- describe('yesLog', () => {
4
- const originalVerbose = process.env.VERBOSE;
5
-
6
- beforeEach(() => {
7
- // Reset modules to ensure fresh state
8
- delete require.cache[require.resolve('./yesLog')];
9
- });
10
-
11
- afterEach(() => {
12
- // Restore original VERBOSE setting
13
- if (originalVerbose !== undefined) {
14
- process.env.VERBOSE = originalVerbose;
15
- } else {
16
- delete process.env.VERBOSE;
17
- }
18
- });
19
-
20
- it('should not crash when VERBOSE is not set', async () => {
21
- delete process.env.VERBOSE;
22
-
23
- const { yesLog } = await import('./yesLog');
24
-
25
- // Should not throw and returns undefined
26
- const result = yesLog`Test message`;
27
- expect(result).toBeUndefined();
28
- });
29
-
30
- it('should be callable with template literals', async () => {
31
- delete process.env.VERBOSE;
32
-
33
- const { yesLog } = await import('./yesLog');
34
-
35
- // Should not throw with variables
36
- const variable = 'test value';
37
- const result = yesLog`Message with ${variable}`;
38
- expect(result).toBeUndefined();
39
- });
40
-
41
- it('should handle multiple calls', async () => {
42
- delete process.env.VERBOSE;
43
-
44
- const { yesLog } = await import('./yesLog');
45
-
46
- // Multiple calls should not throw
47
- expect(yesLog`First message`).toBeUndefined();
48
- expect(yesLog`Second message`).toBeUndefined();
49
- expect(yesLog`Third message`).toBeUndefined();
50
- });
51
-
52
- it('should work when VERBOSE is set', async () => {
53
- process.env.VERBOSE = '1';
54
-
55
- const { yesLog } = await import('./yesLog');
56
-
57
- // Should not throw even when verbose
58
- expect(yesLog`Verbose message`).toBeUndefined();
59
- });
60
-
61
- it('should handle template literals with different types', async () => {
62
- delete process.env.VERBOSE;
63
-
64
- const { yesLog } = await import('./yesLog');
65
-
66
- const number = 42;
67
- const object = { key: 'value' };
68
- const array = [1, 2, 3];
69
-
70
- expect(yesLog`Number: ${number}`).toBeUndefined();
71
- expect(yesLog`Object: ${object}`).toBeUndefined();
72
- expect(yesLog`Array: ${array}`).toBeUndefined();
73
- });
74
- });
package/ts/yesLog.ts DELETED
@@ -1,27 +0,0 @@
1
- import { appendFileSync, rmSync } from 'node:fs';
2
- import tsaComposer from 'tsa-composer';
3
- import { catcher } from './catcher';
4
-
5
- let initial = true;
6
-
7
- /**
8
- * Log messages to agent-yes.log file
9
- * Each message is appended as a new line
10
- * The log file is cleared on the first call
11
- *
12
- * use only for debug, enabled when process.env.VERBOSE is set
13
- */
14
- export const yesLog = tsaComposer()(
15
- catcher(
16
- (error) => {
17
- console.error('yesLog error:', error);
18
- },
19
- function yesLog(msg: string) {
20
- // process.stdout.write(`${msg}\r`); // touch process to avoid "The process is not running a TTY." error
21
- if (!process.env.VERBOSE) return; // no-op if not verbose
22
- if (initial) rmSync('./agent-yes.log'); // ignore error if file doesn't exist
23
- initial = false;
24
- appendFileSync('./agent-yes.log', `${msg}\n`);
25
- },
26
- ),
27
- );