@ai-devkit/agent-manager 0.13.0 → 0.15.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 (95) hide show
  1. package/.eslintrc.json +1 -1
  2. package/README.md +32 -0
  3. package/dist/AgentManager.d.ts +10 -12
  4. package/dist/AgentManager.d.ts.map +1 -1
  5. package/dist/AgentManager.js +6 -34
  6. package/dist/AgentManager.js.map +1 -1
  7. package/dist/adapters/AgentAdapter.js +2 -5
  8. package/dist/adapters/AgentAdapter.js.map +1 -1
  9. package/dist/adapters/ClaudeCodeAdapter.d.ts +1 -1
  10. package/dist/adapters/ClaudeCodeAdapter.d.ts.map +1 -1
  11. package/dist/adapters/ClaudeCodeAdapter.js +29 -63
  12. package/dist/adapters/ClaudeCodeAdapter.js.map +1 -1
  13. package/dist/adapters/CodexAdapter.d.ts +1 -1
  14. package/dist/adapters/CodexAdapter.d.ts.map +1 -1
  15. package/dist/adapters/CodexAdapter.js +32 -68
  16. package/dist/adapters/CodexAdapter.js.map +1 -1
  17. package/dist/adapters/GeminiCliAdapter.d.ts +1 -1
  18. package/dist/adapters/GeminiCliAdapter.d.ts.map +1 -1
  19. package/dist/adapters/GeminiCliAdapter.js +29 -65
  20. package/dist/adapters/GeminiCliAdapter.js.map +1 -1
  21. package/dist/adapters/OpenCodeAdapter.d.ts +1 -1
  22. package/dist/adapters/OpenCodeAdapter.d.ts.map +1 -1
  23. package/dist/adapters/OpenCodeAdapter.js +20 -59
  24. package/dist/adapters/OpenCodeAdapter.js.map +1 -1
  25. package/dist/adapters/index.d.ts +6 -6
  26. package/dist/adapters/index.d.ts.map +1 -1
  27. package/dist/adapters/index.js +5 -13
  28. package/dist/adapters/index.js.map +1 -1
  29. package/dist/index.d.ts +13 -11
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +9 -22
  32. package/dist/index.js.map +1 -1
  33. package/dist/terminal/TerminalFocusManager.js +13 -17
  34. package/dist/terminal/TerminalFocusManager.js.map +1 -1
  35. package/dist/terminal/TtyWriter.d.ts +1 -1
  36. package/dist/terminal/TtyWriter.d.ts.map +1 -1
  37. package/dist/terminal/TtyWriter.js +11 -15
  38. package/dist/terminal/TtyWriter.js.map +1 -1
  39. package/dist/terminal/index.d.ts +4 -4
  40. package/dist/terminal/index.d.ts.map +1 -1
  41. package/dist/terminal/index.js +3 -9
  42. package/dist/terminal/index.js.map +1 -1
  43. package/dist/utils/ClaudeSessionParser.d.ts +2 -2
  44. package/dist/utils/ClaudeSessionParser.d.ts.map +1 -1
  45. package/dist/utils/ClaudeSessionParser.js +11 -48
  46. package/dist/utils/ClaudeSessionParser.js.map +1 -1
  47. package/dist/utils/applescript.js +1 -4
  48. package/dist/utils/applescript.js.map +1 -1
  49. package/dist/utils/index.d.ts +6 -6
  50. package/dist/utils/index.d.ts.map +1 -1
  51. package/dist/utils/index.js +4 -15
  52. package/dist/utils/index.js.map +1 -1
  53. package/dist/utils/matching.d.ts +2 -2
  54. package/dist/utils/matching.d.ts.map +1 -1
  55. package/dist/utils/matching.js +3 -40
  56. package/dist/utils/matching.js.map +1 -1
  57. package/dist/utils/process.d.ts +1 -1
  58. package/dist/utils/process.d.ts.map +1 -1
  59. package/dist/utils/process.js +12 -52
  60. package/dist/utils/process.js.map +1 -1
  61. package/dist/utils/session.js +8 -49
  62. package/dist/utils/session.js.map +1 -1
  63. package/dist/utils/sortAgents.d.ts +4 -0
  64. package/dist/utils/sortAgents.d.ts.map +1 -0
  65. package/dist/utils/sortAgents.js +48 -0
  66. package/dist/utils/sortAgents.js.map +1 -0
  67. package/package.json +9 -8
  68. package/src/AgentManager.ts +13 -28
  69. package/src/__tests__/AgentManager.test.ts +5 -5
  70. package/src/__tests__/adapters/ClaudeCodeAdapter.test.ts +44 -42
  71. package/src/__tests__/adapters/CodexAdapter.test.ts +32 -30
  72. package/src/__tests__/adapters/GeminiCliAdapter.test.ts +19 -18
  73. package/src/__tests__/adapters/OpenCodeAdapter.test.ts +23 -21
  74. package/src/__tests__/terminal/TtyWriter.test.ts +10 -9
  75. package/src/__tests__/utils/ClaudeSessionParser.test.ts +2 -2
  76. package/src/__tests__/utils/matching.test.ts +4 -4
  77. package/src/__tests__/utils/process.test.ts +6 -5
  78. package/src/__tests__/utils/session.test.ts +8 -7
  79. package/src/adapters/ClaudeCodeAdapter.ts +8 -8
  80. package/src/adapters/CodexAdapter.ts +6 -6
  81. package/src/adapters/GeminiCliAdapter.ts +6 -6
  82. package/src/adapters/OpenCodeAdapter.ts +4 -4
  83. package/src/adapters/index.ts +6 -6
  84. package/src/index.ts +13 -11
  85. package/src/terminal/TerminalFocusManager.ts +2 -2
  86. package/src/terminal/TtyWriter.ts +3 -3
  87. package/src/terminal/index.ts +4 -4
  88. package/src/utils/ClaudeSessionParser.ts +2 -2
  89. package/src/utils/index.ts +6 -6
  90. package/src/utils/matching.ts +2 -2
  91. package/src/utils/process.ts +1 -1
  92. package/src/utils/sortAgents.ts +52 -0
  93. package/tsconfig.json +2 -2
  94. package/vitest.config.ts +20 -0
  95. package/jest.config.js +0 -21
@@ -2,28 +2,30 @@
2
2
  * Tests for OpenCodeAdapter
3
3
  */
4
4
 
5
+ import type { MockedFunction } from 'vitest';
5
6
  import * as fs from 'fs';
6
7
  import * as path from 'path';
7
- import { beforeEach, afterEach, describe, expect, it, jest } from '@jest/globals';
8
- import { OpenCodeAdapter } from '../../adapters/OpenCodeAdapter';
9
- import type { ProcessInfo } from '../../adapters/AgentAdapter';
10
- import { AgentStatus } from '../../adapters/AgentAdapter';
11
- import { listAgentProcesses, enrichProcesses } from '../../utils/process';
12
- import { generateAgentName } from '../../utils/matching';
13
-
14
- jest.mock('../../utils/process', () => ({
15
- listAgentProcesses: jest.fn(),
16
- enrichProcesses: jest.fn(),
8
+
9
+ import { OpenCodeAdapter } from '../../adapters/OpenCodeAdapter.js';
10
+ import type { ProcessInfo } from '../../adapters/AgentAdapter.js';
11
+ import { AgentStatus } from '../../adapters/AgentAdapter.js';
12
+ import { listAgentProcesses, enrichProcesses } from '../../utils/process.js';
13
+ import { generateAgentName } from '../../utils/matching.js';
14
+ import * as os from 'os';
15
+
16
+ vi.mock('../../utils/process.js', () => ({
17
+ listAgentProcesses: vi.fn(),
18
+ enrichProcesses: vi.fn(),
17
19
  }));
18
20
 
19
- jest.mock('../../utils/matching', () => ({
20
- generateAgentName: jest.fn(),
21
- matchProcessesToSessions: jest.fn(),
21
+ vi.mock('../../utils/matching.js', () => ({
22
+ generateAgentName: vi.fn(),
23
+ matchProcessesToSessions: vi.fn(),
22
24
  }));
23
25
 
24
- const mockedListAgentProcesses = listAgentProcesses as jest.MockedFunction<typeof listAgentProcesses>;
25
- const mockedEnrichProcesses = enrichProcesses as jest.MockedFunction<typeof enrichProcesses>;
26
- const mockedGenerateAgentName = generateAgentName as jest.MockedFunction<typeof generateAgentName>;
26
+ const mockedListAgentProcesses = listAgentProcesses as MockedFunction<typeof listAgentProcesses>;
27
+ const mockedEnrichProcesses = enrichProcesses as MockedFunction<typeof enrichProcesses>;
28
+ const mockedGenerateAgentName = generateAgentName as MockedFunction<typeof generateAgentName>;
27
29
 
28
30
  function makeDb(queries: {
29
31
  session?: Array<{ id: string; directory: string; time_created: number }>;
@@ -85,11 +87,11 @@ function makeDb(queries: {
85
87
  return { all: () => [], get: () => undefined };
86
88
  };
87
89
 
88
- return { prepare: prepareImpl, close: jest.fn() };
90
+ return { prepare: prepareImpl, close: vi.fn() };
89
91
  }
90
92
 
91
93
  function makeDbConstructor(db: ReturnType<typeof makeDb>) {
92
- return jest.fn().mockReturnValue(db);
94
+ return vi.fn().mockReturnValue(db);
93
95
  }
94
96
 
95
97
  describe('OpenCodeAdapter', () => {
@@ -110,7 +112,7 @@ describe('OpenCodeAdapter', () => {
110
112
  return `${folder}-${pid}`;
111
113
  });
112
114
 
113
- tmpDir = fs.mkdtempSync(path.join(require('os').tmpdir(), 'opencode-test-'));
115
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'opencode-test-'));
114
116
  dbPath = path.join(tmpDir, 'opencode.db');
115
117
  (adapter as any).dbPath = dbPath;
116
118
  (adapter as any).db = null;
@@ -118,7 +120,7 @@ describe('OpenCodeAdapter', () => {
118
120
 
119
121
  afterEach(() => {
120
122
  fs.rmSync(tmpDir, { recursive: true, force: true });
121
- jest.restoreAllMocks();
123
+ vi.restoreAllMocks();
122
124
  });
123
125
 
124
126
  describe('type', () => {
@@ -193,7 +195,7 @@ describe('OpenCodeAdapter', () => {
193
195
 
194
196
  fs.writeFileSync(dbPath, ''); // file exists but empty → sqlite throws
195
197
  const db = makeDb({ session: [] }); // no matching session
196
- jest.mock('better-sqlite3', () => makeDbConstructor(db));
198
+ vi.doMock('better-sqlite3', () => makeDbConstructor(db));
197
199
  (adapter as any).db = db;
198
200
 
199
201
  const agents = await adapter.detectAgents();
@@ -1,18 +1,19 @@
1
- import { describe, it, expect, jest, beforeEach } from '@jest/globals';
2
- import { TtyWriter } from '../../terminal/TtyWriter';
3
- import { TerminalType } from '../../terminal/TerminalFocusManager';
4
- import type { TerminalLocation } from '../../terminal/TerminalFocusManager';
1
+ import type { Mock } from 'vitest';
2
+
3
+ import { TtyWriter } from '../../terminal/TtyWriter.js';
4
+ import { TerminalType } from '../../terminal/TerminalFocusManager.js';
5
+ import type { TerminalLocation } from '../../terminal/TerminalFocusManager.js';
5
6
  import { execFile } from 'child_process';
6
7
 
7
- jest.mock('child_process', () => {
8
- const actual = jest.requireActual<typeof import('child_process')>('child_process');
8
+ vi.mock('child_process', async () => {
9
+ const actual = await vi.importActual<typeof import('child_process')>('child_process');
9
10
  return {
10
11
  ...actual,
11
- execFile: jest.fn(),
12
+ execFile: vi.fn(),
12
13
  };
13
14
  });
14
15
 
15
- const mockedExecFile = execFile as unknown as jest.Mock;
16
+ const mockedExecFile = execFile as unknown as Mock;
16
17
 
17
18
  function mockExecFileSuccess(stdout = '') {
18
19
  mockedExecFile.mockImplementation((...args: unknown[]) => {
@@ -30,7 +31,7 @@ function mockExecFileError(message: string) {
30
31
 
31
32
  describe('TtyWriter', () => {
32
33
  beforeEach(() => {
33
- jest.clearAllMocks();
34
+ vi.clearAllMocks();
34
35
  });
35
36
 
36
37
  describe('tmux', () => {
@@ -3,11 +3,11 @@
3
3
  * harness-injected XML tags from conversation content.
4
4
  */
5
5
 
6
- import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
6
+
7
7
  import * as fs from 'fs';
8
8
  import * as os from 'os';
9
9
  import * as path from 'path';
10
- import { ClaudeSessionParser } from '../../utils/ClaudeSessionParser';
10
+ import { ClaudeSessionParser } from '../../utils/ClaudeSessionParser.js';
11
11
 
12
12
  interface JsonlEntry {
13
13
  type: 'user' | 'assistant' | 'system';
@@ -2,10 +2,10 @@
2
2
  * Tests for utils/matching.ts
3
3
  */
4
4
 
5
- import { describe, it, expect } from '@jest/globals';
6
- import { matchProcessesToSessions, generateAgentName } from '../../utils/matching';
7
- import type { ProcessInfo } from '../../adapters/AgentAdapter';
8
- import type { SessionFile } from '../../utils/session';
5
+
6
+ import { matchProcessesToSessions, generateAgentName } from '../../utils/matching.js';
7
+ import type { ProcessInfo } from '../../adapters/AgentAdapter.js';
8
+ import type { SessionFile } from '../../utils/session.js';
9
9
 
10
10
  function makeProcess(overrides: Partial<ProcessInfo> & { pid: number }): ProcessInfo {
11
11
  return {
@@ -2,20 +2,21 @@
2
2
  * Tests for new functions in utils/process.ts
3
3
  */
4
4
 
5
- import { describe, it, expect, jest, beforeEach } from '@jest/globals';
5
+ import type { MockedFunction } from 'vitest';
6
+
6
7
  import { execFileSync } from 'child_process';
7
8
  import {
8
9
  listAgentProcesses,
9
10
  batchGetProcessCwds,
10
11
  batchGetProcessStartTimes,
11
12
  enrichProcesses,
12
- } from '../../utils/process';
13
+ } from '../../utils/process.js';
13
14
 
14
- jest.mock('child_process', () => ({
15
- execFileSync: jest.fn(),
15
+ vi.mock('child_process', () => ({
16
+ execFileSync: vi.fn(),
16
17
  }));
17
18
 
18
- const mockedExecFileSync = execFileSync as jest.MockedFunction<typeof execFileSync>;
19
+ const mockedExecFileSync = execFileSync as MockedFunction<typeof execFileSync>;
19
20
 
20
21
  describe('listAgentProcesses', () => {
21
22
  beforeEach(() => {
@@ -2,17 +2,18 @@
2
2
  * Tests for utils/session.ts
3
3
  */
4
4
 
5
- import { describe, it, expect, jest, beforeEach } from '@jest/globals';
5
+ import type { MockedFunction } from 'vitest';
6
+
6
7
  import * as fs from 'fs';
7
- import { batchGetSessionFileBirthtimes } from '../../utils/session';
8
+ import { batchGetSessionFileBirthtimes } from '../../utils/session.js';
8
9
 
9
- jest.mock('fs', () => ({
10
- readdirSync: jest.fn(),
11
- statSync: jest.fn(),
10
+ vi.mock('fs', () => ({
11
+ readdirSync: vi.fn(),
12
+ statSync: vi.fn(),
12
13
  }));
13
14
 
14
- const mockedReaddirSync = fs.readdirSync as jest.MockedFunction<typeof fs.readdirSync>;
15
- const mockedStatSync = fs.statSync as jest.MockedFunction<typeof fs.statSync>;
15
+ const mockedReaddirSync = fs.readdirSync as MockedFunction<typeof fs.readdirSync>;
16
+ const mockedStatSync = fs.statSync as MockedFunction<typeof fs.statSync>;
16
17
 
17
18
  describe('batchGetSessionFileBirthtimes', () => {
18
19
  beforeEach(() => {
@@ -7,14 +7,14 @@ import type {
7
7
  ConversationMessage,
8
8
  SessionSummary,
9
9
  ListSessionsOptions,
10
- } from './AgentAdapter';
11
- import { AgentStatus } from './AgentAdapter';
12
- import { listAgentProcesses, enrichProcesses } from '../utils/process';
13
- import { batchGetSessionFileBirthtimes, isDirectory, listJsonl, safeReaddir, safeStat } from '../utils/session';
14
- import type { SessionFile } from '../utils/session';
15
- import { matchProcessesToSessions, generateAgentName } from '../utils/matching';
16
- import { ClaudeSessionParser } from '../utils/ClaudeSessionParser';
17
- import type { ClaudeSession } from '../utils/ClaudeSessionParser';
10
+ } from './AgentAdapter.js';
11
+ import { AgentStatus } from './AgentAdapter.js';
12
+ import { listAgentProcesses, enrichProcesses } from '../utils/process.js';
13
+ import { batchGetSessionFileBirthtimes, isDirectory, listJsonl, safeReaddir, safeStat } from '../utils/session.js';
14
+ import type { SessionFile } from '../utils/session.js';
15
+ import { matchProcessesToSessions, generateAgentName } from '../utils/matching.js';
16
+ import { ClaudeSessionParser } from '../utils/ClaudeSessionParser.js';
17
+ import type { ClaudeSession } from '../utils/ClaudeSessionParser.js';
18
18
 
19
19
  /**
20
20
  * Entry in ~/.claude/sessions/<pid>.json written by Claude Code.
@@ -19,12 +19,12 @@ import type {
19
19
  ConversationMessage,
20
20
  SessionSummary,
21
21
  ListSessionsOptions,
22
- } from './AgentAdapter';
23
- import { AgentStatus } from './AgentAdapter';
24
- import { listAgentProcesses, enrichProcesses } from '../utils/process';
25
- import { batchGetSessionFileBirthtimes, isDirectory, safeReadFile, safeReaddir, safeStat } from '../utils/session';
26
- import type { SessionFile } from '../utils/session';
27
- import { matchProcessesToSessions, generateAgentName } from '../utils/matching';
22
+ } from './AgentAdapter.js';
23
+ import { AgentStatus } from './AgentAdapter.js';
24
+ import { listAgentProcesses, enrichProcesses } from '../utils/process.js';
25
+ import { batchGetSessionFileBirthtimes, isDirectory, safeReadFile, safeReaddir, safeStat } from '../utils/session.js';
26
+ import type { SessionFile } from '../utils/session.js';
27
+ import { matchProcessesToSessions, generateAgentName } from '../utils/matching.js';
28
28
 
29
29
  interface CodexEventEntry {
30
30
  timestamp?: string;
@@ -20,12 +20,12 @@ import type {
20
20
  ConversationMessage,
21
21
  SessionSummary,
22
22
  ListSessionsOptions,
23
- } from './AgentAdapter';
24
- import { AgentStatus } from './AgentAdapter';
25
- import { listAgentProcesses, enrichProcesses } from '../utils/process';
26
- import { isDirectory, safeReadFile, safeReaddir, safeStat } from '../utils/session';
27
- import type { SessionFile } from '../utils/session';
28
- import { matchProcessesToSessions, generateAgentName } from '../utils/matching';
23
+ } from './AgentAdapter.js';
24
+ import { AgentStatus } from './AgentAdapter.js';
25
+ import { listAgentProcesses, enrichProcesses } from '../utils/process.js';
26
+ import { isDirectory, safeReadFile, safeReaddir, safeStat } from '../utils/session.js';
27
+ import type { SessionFile } from '../utils/session.js';
28
+ import { matchProcessesToSessions, generateAgentName } from '../utils/matching.js';
29
29
 
30
30
  /**
31
31
  * A single Gemini CLI message content part. Mirrors the `{text?: string}`
@@ -21,10 +21,10 @@ import type {
21
21
  ConversationMessage,
22
22
  SessionSummary,
23
23
  ListSessionsOptions,
24
- } from './AgentAdapter';
25
- import { AgentStatus } from './AgentAdapter';
26
- import { listAgentProcesses, enrichProcesses } from '../utils/process';
27
- import { generateAgentName } from '../utils/matching';
24
+ } from './AgentAdapter.js';
25
+ import { AgentStatus } from './AgentAdapter.js';
26
+ import { listAgentProcesses, enrichProcesses } from '../utils/process.js';
27
+ import { generateAgentName } from '../utils/matching.js';
28
28
 
29
29
  const SESSION_REF_SEP = '::';
30
30
 
@@ -1,6 +1,6 @@
1
- export { ClaudeCodeAdapter } from './ClaudeCodeAdapter';
2
- export { CodexAdapter } from './CodexAdapter';
3
- export { GeminiCliAdapter } from './GeminiCliAdapter';
4
- export { OpenCodeAdapter } from './OpenCodeAdapter';
5
- export { AgentStatus } from './AgentAdapter';
6
- export type { AgentAdapter, AgentType, AgentInfo, ProcessInfo } from './AgentAdapter';
1
+ export { ClaudeCodeAdapter } from './ClaudeCodeAdapter.js';
2
+ export { CodexAdapter } from './CodexAdapter.js';
3
+ export { GeminiCliAdapter } from './GeminiCliAdapter.js';
4
+ export { OpenCodeAdapter } from './OpenCodeAdapter.js';
5
+ export { AgentStatus } from './AgentAdapter.js';
6
+ export type { AgentAdapter, AgentType, AgentInfo, ProcessInfo } from './AgentAdapter.js';
package/src/index.ts CHANGED
@@ -1,10 +1,10 @@
1
- export { AgentManager } from './AgentManager';
1
+ export { AgentManager } from './AgentManager.js';
2
2
 
3
- export { ClaudeCodeAdapter } from './adapters/ClaudeCodeAdapter';
4
- export { CodexAdapter } from './adapters/CodexAdapter';
5
- export { GeminiCliAdapter } from './adapters/GeminiCliAdapter';
6
- export { OpenCodeAdapter } from './adapters/OpenCodeAdapter';
7
- export { AgentStatus } from './adapters/AgentAdapter';
3
+ export { ClaudeCodeAdapter } from './adapters/ClaudeCodeAdapter.js';
4
+ export { CodexAdapter } from './adapters/CodexAdapter.js';
5
+ export { GeminiCliAdapter } from './adapters/GeminiCliAdapter.js';
6
+ export { OpenCodeAdapter } from './adapters/OpenCodeAdapter.js';
7
+ export { AgentStatus } from './adapters/AgentAdapter.js';
8
8
  export type {
9
9
  AgentAdapter,
10
10
  AgentType,
@@ -13,10 +13,12 @@ export type {
13
13
  ConversationMessage,
14
14
  SessionSummary,
15
15
  ListSessionsOptions,
16
- } from './adapters/AgentAdapter';
16
+ } from './adapters/AgentAdapter.js';
17
17
 
18
- export { TerminalFocusManager, TerminalType } from './terminal/TerminalFocusManager';
19
- export type { TerminalLocation } from './terminal/TerminalFocusManager';
20
- export { TtyWriter } from './terminal/TtyWriter';
18
+ export { TerminalFocusManager, TerminalType } from './terminal/TerminalFocusManager.js';
19
+ export type { TerminalLocation } from './terminal/TerminalFocusManager.js';
20
+ export { TtyWriter } from './terminal/TtyWriter.js';
21
21
 
22
- export { getProcessTty } from './utils/process';
22
+ export { getProcessTty } from './utils/process.js';
23
+ export type { AgentSortKey } from './utils/sortAgents.js';
24
+ export type { ListAgentsOptions } from './AgentManager.js';
@@ -1,7 +1,7 @@
1
1
  import { execFile } from 'child_process';
2
2
  import { promisify } from 'util';
3
- import { getProcessTty } from '../utils/process';
4
- import { escapeAppleScript } from '../utils/applescript';
3
+ import { getProcessTty } from '../utils/process.js';
4
+ import { escapeAppleScript } from '../utils/applescript.js';
5
5
 
6
6
  const execFileAsync = promisify(execFile);
7
7
 
@@ -1,8 +1,8 @@
1
1
  import { execFile } from 'child_process';
2
2
  import { promisify } from 'util';
3
- import type { TerminalLocation } from './TerminalFocusManager';
4
- import { TerminalType } from './TerminalFocusManager';
5
- import { escapeAppleScript } from '../utils/applescript';
3
+ import type { TerminalLocation } from './TerminalFocusManager.js';
4
+ import { TerminalType } from './TerminalFocusManager.js';
5
+ import { escapeAppleScript } from '../utils/applescript.js';
6
6
 
7
7
  const execFileAsync = promisify(execFile);
8
8
 
@@ -1,4 +1,4 @@
1
- export { TerminalFocusManager } from './TerminalFocusManager';
2
- export { TerminalType } from './TerminalFocusManager';
3
- export type { TerminalLocation } from './TerminalFocusManager';
4
- export { TtyWriter } from './TtyWriter';
1
+ export { TerminalFocusManager } from './TerminalFocusManager.js';
2
+ export { TerminalType } from './TerminalFocusManager.js';
3
+ export type { TerminalLocation } from './TerminalFocusManager.js';
4
+ export { TtyWriter } from './TtyWriter.js';
@@ -1,7 +1,7 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
- import type { ConversationMessage } from '../adapters/AgentAdapter';
4
- import { AgentStatus } from '../adapters/AgentAdapter';
3
+ import type { ConversationMessage } from '../adapters/AgentAdapter.js';
4
+ import { AgentStatus } from '../adapters/AgentAdapter.js';
5
5
 
6
6
  /**
7
7
  * Content block within a Claude Code JSONL message entry.
@@ -1,6 +1,6 @@
1
- export { listAgentProcesses, batchGetProcessCwds, batchGetProcessStartTimes, enrichProcesses } from './process';
2
- export { getProcessTty } from './process';
3
- export { batchGetSessionFileBirthtimes } from './session';
4
- export type { SessionFile } from './session';
5
- export { matchProcessesToSessions, generateAgentName } from './matching';
6
- export type { MatchResult } from './matching';
1
+ export { listAgentProcesses, batchGetProcessCwds, batchGetProcessStartTimes, enrichProcesses } from './process.js';
2
+ export { getProcessTty } from './process.js';
3
+ export { batchGetSessionFileBirthtimes } from './session.js';
4
+ export type { SessionFile } from './session.js';
5
+ export { matchProcessesToSessions, generateAgentName } from './matching.js';
6
+ export type { MatchResult } from './matching.js';
@@ -6,8 +6,8 @@
6
6
  */
7
7
 
8
8
  import * as path from 'path';
9
- import type { ProcessInfo } from '../adapters/AgentAdapter';
10
- import type { SessionFile } from './session';
9
+ import type { ProcessInfo } from '../adapters/AgentAdapter.js';
10
+ import type { SessionFile } from './session.js';
11
11
 
12
12
  /** Maximum allowed delta between process start time and session file birth time. */
13
13
  const TOLERANCE_MS = 3 * 60 * 1000; // 3 minutes
@@ -7,7 +7,7 @@
7
7
 
8
8
  import * as path from 'path';
9
9
  import { execFileSync } from 'child_process';
10
- import type { ProcessInfo } from '../adapters/AgentAdapter';
10
+ import type { ProcessInfo } from '../adapters/AgentAdapter.js';
11
11
 
12
12
  /**
13
13
  * List running processes matching an agent executable name.
@@ -0,0 +1,52 @@
1
+ import { AgentStatus, type AgentInfo } from '../adapters/AgentAdapter.js';
2
+
3
+ export type AgentSortKey = 'name' | 'status' | 'pid' | 'lastActive';
4
+
5
+ const STATUS_PRIORITY: Record<AgentStatus, number> = {
6
+ [AgentStatus.WAITING]: 0,
7
+ [AgentStatus.RUNNING]: 1,
8
+ [AgentStatus.IDLE]: 2,
9
+ [AgentStatus.UNKNOWN]: 3,
10
+ };
11
+
12
+ function compareByName(a: AgentInfo, b: AgentInfo): number {
13
+ return a.name.localeCompare(b.name);
14
+ }
15
+
16
+ function compareByStatus(a: AgentInfo, b: AgentInfo): number {
17
+ const pa = STATUS_PRIORITY[a.status] ?? 999;
18
+ const pb = STATUS_PRIORITY[b.status] ?? 999;
19
+ if (pa !== pb) return pa - pb;
20
+ return compareByName(a, b);
21
+ }
22
+
23
+ function compareByPid(a: AgentInfo, b: AgentInfo): number {
24
+ if (a.pid !== b.pid) return a.pid - b.pid;
25
+ return compareByName(a, b);
26
+ }
27
+
28
+ function compareByLastActive(a: AgentInfo, b: AgentInfo): number {
29
+ const ta = a.lastActive instanceof Date ? a.lastActive.getTime() : new Date(a.lastActive).getTime();
30
+ const tb = b.lastActive instanceof Date ? b.lastActive.getTime() : new Date(b.lastActive).getTime();
31
+ if (tb !== ta) return tb - ta; // most recent first
32
+ return compareByName(a, b);
33
+ }
34
+
35
+ export function sortAgents(agents: AgentInfo[], by: AgentSortKey): AgentInfo[] {
36
+ const copy = agents.slice();
37
+ switch (by) {
38
+ case 'name':
39
+ copy.sort(compareByName);
40
+ break;
41
+ case 'status':
42
+ copy.sort(compareByStatus);
43
+ break;
44
+ case 'pid':
45
+ copy.sort(compareByPid);
46
+ break;
47
+ case 'lastActive':
48
+ copy.sort(compareByLastActive);
49
+ break;
50
+ }
51
+ return copy;
52
+ }
package/tsconfig.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "extends": "../../tsconfig.base.json",
3
3
  "compilerOptions": {
4
- "module": "commonjs",
5
- "moduleResolution": "node",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
6
  "rootDir": "./src",
7
7
  "outDir": "./dist"
8
8
  },
@@ -0,0 +1,20 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ environment: 'node',
7
+ include: ['src/**/__tests__/**/*.test.ts'],
8
+ coverage: {
9
+ provider: 'v8',
10
+ include: ['src/**/*.ts'],
11
+ exclude: ['src/index.ts', 'src/**/*.d.ts'],
12
+ thresholds: {
13
+ branches: 70,
14
+ functions: 70,
15
+ lines: 70,
16
+ statements: 70,
17
+ },
18
+ },
19
+ },
20
+ });
package/jest.config.js DELETED
@@ -1,21 +0,0 @@
1
- module.exports = {
2
- preset: 'ts-jest',
3
- testEnvironment: 'node',
4
- roots: ['<rootDir>/src'],
5
- testMatch: ['**/__tests__/**/*.test.ts', '**/?(*.)+(spec|test).ts'],
6
- collectCoverageFrom: [
7
- 'src/**/*.{ts,js}',
8
- '!src/**/*.d.ts',
9
- '!src/index.ts'
10
- ],
11
- coverageDirectory: 'coverage',
12
- coverageReporters: ['text', 'lcov', 'html'],
13
- coverageThreshold: {
14
- global: {
15
- branches: 80,
16
- functions: 80,
17
- lines: 80,
18
- statements: 80
19
- }
20
- }
21
- };