@ai-devkit/agent-manager 0.10.0 → 0.11.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.
Files changed (57) hide show
  1. package/dist/AgentManager.d.ts +14 -1
  2. package/dist/AgentManager.d.ts.map +1 -1
  3. package/dist/AgentManager.js +38 -0
  4. package/dist/AgentManager.js.map +1 -1
  5. package/dist/adapters/AgentAdapter.d.ts +66 -0
  6. package/dist/adapters/AgentAdapter.d.ts.map +1 -1
  7. package/dist/adapters/ClaudeCodeAdapter.d.ts +14 -1
  8. package/dist/adapters/ClaudeCodeAdapter.d.ts.map +1 -1
  9. package/dist/adapters/ClaudeCodeAdapter.js +60 -0
  10. package/dist/adapters/ClaudeCodeAdapter.js.map +1 -1
  11. package/dist/adapters/CodexAdapter.d.ts +14 -1
  12. package/dist/adapters/CodexAdapter.d.ts.map +1 -1
  13. package/dist/adapters/CodexAdapter.js +105 -6
  14. package/dist/adapters/CodexAdapter.js.map +1 -1
  15. package/dist/adapters/GeminiCliAdapter.d.ts +9 -1
  16. package/dist/adapters/GeminiCliAdapter.d.ts.map +1 -1
  17. package/dist/adapters/GeminiCliAdapter.js +77 -6
  18. package/dist/adapters/GeminiCliAdapter.js.map +1 -1
  19. package/dist/index.d.ts +1 -1
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/terminal/TerminalFocusManager.d.ts.map +1 -1
  23. package/dist/terminal/TerminalFocusManager.js +5 -7
  24. package/dist/terminal/TerminalFocusManager.js.map +1 -1
  25. package/dist/terminal/TtyWriter.d.ts.map +1 -1
  26. package/dist/terminal/TtyWriter.js +3 -12
  27. package/dist/terminal/TtyWriter.js.map +1 -1
  28. package/dist/utils/ClaudeSessionParser.d.ts +2 -0
  29. package/dist/utils/ClaudeSessionParser.d.ts.map +1 -1
  30. package/dist/utils/ClaudeSessionParser.js +48 -5
  31. package/dist/utils/ClaudeSessionParser.js.map +1 -1
  32. package/dist/utils/applescript.d.ts +6 -0
  33. package/dist/utils/applescript.d.ts.map +1 -0
  34. package/dist/utils/applescript.js +14 -0
  35. package/dist/utils/applescript.js.map +1 -0
  36. package/dist/utils/session.d.ts +34 -5
  37. package/dist/utils/session.d.ts.map +1 -1
  38. package/dist/utils/session.js +90 -44
  39. package/dist/utils/session.js.map +1 -1
  40. package/package.json +1 -1
  41. package/src/AgentManager.ts +55 -3
  42. package/src/__tests__/AgentManager.test.ts +134 -2
  43. package/src/__tests__/adapters/ClaudeCodeAdapter.test.ts +159 -3
  44. package/src/__tests__/adapters/CodexAdapter.test.ts +123 -3
  45. package/src/__tests__/adapters/GeminiCliAdapter.test.ts +133 -0
  46. package/src/__tests__/utils/ClaudeSessionParser.test.ts +195 -0
  47. package/src/__tests__/utils/session.test.ts +79 -43
  48. package/src/adapters/AgentAdapter.ts +76 -0
  49. package/src/adapters/ClaudeCodeAdapter.ts +76 -2
  50. package/src/adapters/CodexAdapter.ts +126 -8
  51. package/src/adapters/GeminiCliAdapter.ts +102 -7
  52. package/src/index.ts +9 -1
  53. package/src/terminal/TerminalFocusManager.ts +1 -4
  54. package/src/terminal/TtyWriter.ts +1 -11
  55. package/src/utils/ClaudeSessionParser.ts +59 -5
  56. package/src/utils/applescript.ts +10 -0
  57. package/src/utils/session.ts +86 -45
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Session File Utilities
3
3
  *
4
- * Shell command wrappers for discovering session files and their birth times.
5
- * Uses `stat` to get exact epoch-second birth timestamps without reading file contents.
4
+ * Utilities for discovering session files and their birth times.
5
+ * Uses Node.js fs APIs to get birth timestamps without reading file contents.
6
6
  */
7
7
 
8
+ import * as fs from 'fs';
8
9
  import * as path from 'path';
9
- import { execSync } from 'child_process';
10
10
 
11
11
  /**
12
12
  * Represents a session file with its birth time metadata.
@@ -29,63 +29,104 @@ export interface SessionFile {
29
29
  }
30
30
 
31
31
  /**
32
- * Get birth times for .jsonl session files across multiple directories in a single shell call.
33
- *
34
- * Combines all directory globs into one `stat` command to avoid per-directory exec overhead.
35
- * Returns empty array if no directories have .jsonl files or command fails.
36
- * resolvedCwd is left empty — the adapter must set it.
32
+ * Check whether a path exists and is a directory.
33
+ * Returns false on any error (missing path, permission denied, broken symlink, etc.).
37
34
  */
38
- export function batchGetSessionFileBirthtimes(dirs: string[]): SessionFile[] {
39
- if (dirs.length === 0) return [];
35
+ export function isDirectory(p: string): boolean {
36
+ return safeStat(p)?.isDirectory() ?? false;
37
+ }
40
38
 
39
+ /**
40
+ * `fs.statSync` that swallows errors and returns `undefined` on failure.
41
+ * Callers can pull whichever fields they need (mtime, birthtime, ...).
42
+ */
43
+ export function safeStat(filePath: string): fs.Stats | undefined {
41
44
  try {
42
- const isMacOS = process.platform === 'darwin';
43
- const globs = dirs.map((d) => `"${d}"/*.jsonl`).join(' ');
44
- // || true prevents non-zero exit when some globs have no .jsonl matches
45
- const command = isMacOS
46
- ? `stat -f '%B %N' ${globs} 2>/dev/null || true`
47
- : `stat --format='%W %n' ${globs} 2>/dev/null || true`;
45
+ return fs.statSync(filePath);
46
+ } catch {
47
+ return undefined;
48
+ }
49
+ }
48
50
 
49
- const output = execSync(command, { encoding: 'utf-8' });
51
+ /**
52
+ * `fs.readFileSync` (utf-8) that swallows errors and returns `undefined`
53
+ * on failure. Use when an unreadable file should be skipped rather than
54
+ * raised.
55
+ */
56
+ export function safeReadFile(filePath: string): string | undefined {
57
+ try {
58
+ return fs.readFileSync(filePath, 'utf-8');
59
+ } catch {
60
+ return undefined;
61
+ }
62
+ }
50
63
 
51
- return parseStatOutput(output);
64
+ /**
65
+ * `fs.readdirSync` that swallows errors and returns `[]` on failure.
66
+ * Useful when walking optional/transient directories where missing or
67
+ * unreadable entries should be skipped silently.
68
+ */
69
+ export function safeReaddir(dir: string): string[] {
70
+ try {
71
+ return fs.readdirSync(dir);
52
72
  } catch {
53
73
  return [];
54
74
  }
55
75
  }
56
76
 
57
77
  /**
58
- * Parse stat output lines into SessionFile entries.
78
+ * List entries in a directory that end with `.jsonl`. Returns `[]` on
79
+ * read errors. The result preserves directory order (no sorting).
59
80
  */
60
- function parseStatOutput(output: string): SessionFile[] {
61
- const results: SessionFile[] = [];
62
-
63
- for (const rawLine of output.trim().split('\n')) {
64
- const line = rawLine.trim();
65
- if (!line) continue;
66
-
67
- // Format: "<epoch_seconds> <filepath>"
68
- const spaceIdx = line.indexOf(' ');
69
- if (spaceIdx === -1) continue;
70
-
71
- const epochStr = line.slice(0, spaceIdx);
72
- const filePath = line.slice(spaceIdx + 1).trim();
73
-
74
- const epochSeconds = parseInt(epochStr, 10);
75
- if (!Number.isFinite(epochSeconds) || epochSeconds <= 0) continue;
81
+ export function listJsonl(dir: string): string[] {
82
+ return safeReaddir(dir).filter((name) => name.endsWith('.jsonl'));
83
+ }
76
84
 
77
- const fileName = path.basename(filePath);
78
- if (!fileName.endsWith('.jsonl')) continue;
85
+ /**
86
+ * Get birth times for .jsonl session files across multiple directories.
87
+ *
88
+ * Enumerates each directory with readdirSync and stats each .jsonl file
89
+ * to get its birth time. No shell commands are used.
90
+ * Returns empty array if no directories have .jsonl files or reads fail.
91
+ * resolvedCwd is left empty — the adapter must set it.
92
+ */
93
+ export function batchGetSessionFileBirthtimes(dirs: string[]): SessionFile[] {
94
+ if (dirs.length === 0) return [];
79
95
 
80
- const sessionId = fileName.replace(/\.jsonl$/, '');
96
+ const results: SessionFile[] = [];
81
97
 
82
- results.push({
83
- sessionId,
84
- filePath,
85
- projectDir: path.dirname(filePath),
86
- birthtimeMs: epochSeconds * 1000,
87
- resolvedCwd: '',
88
- });
98
+ for (const dir of dirs) {
99
+ let entries: string[];
100
+ try {
101
+ entries = fs.readdirSync(dir);
102
+ } catch {
103
+ continue;
104
+ }
105
+
106
+ for (const entry of entries) {
107
+ if (!entry.endsWith('.jsonl')) continue;
108
+
109
+ const filePath = path.join(dir, entry);
110
+
111
+ let birthtimeMs: number;
112
+ try {
113
+ birthtimeMs = fs.statSync(filePath).birthtimeMs;
114
+ } catch {
115
+ continue;
116
+ }
117
+
118
+ if (!Number.isFinite(birthtimeMs) || birthtimeMs <= 0) continue;
119
+
120
+ const sessionId = entry.replace(/\.jsonl$/, '');
121
+
122
+ results.push({
123
+ sessionId,
124
+ filePath,
125
+ projectDir: dir,
126
+ birthtimeMs,
127
+ resolvedCwd: '',
128
+ });
129
+ }
89
130
  }
90
131
 
91
132
  return results;