ccmanager 2.6.1 → 2.8.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.
|
@@ -14,6 +14,10 @@ const createStrategyItems = () => {
|
|
|
14
14
|
gemini: { label: 'Gemini', value: 'gemini' },
|
|
15
15
|
codex: { label: 'Codex', value: 'codex' },
|
|
16
16
|
cursor: { label: 'Cursor Agent', value: 'cursor' },
|
|
17
|
+
'github-copilot': {
|
|
18
|
+
label: 'GitHub Copilot CLI',
|
|
19
|
+
value: 'github-copilot',
|
|
20
|
+
},
|
|
17
21
|
};
|
|
18
22
|
return Object.values(strategies);
|
|
19
23
|
};
|
|
@@ -28,6 +32,8 @@ const formatDetectionStrategy = (strategy) => {
|
|
|
28
32
|
return 'Codex';
|
|
29
33
|
case 'cursor':
|
|
30
34
|
return 'Cursor';
|
|
35
|
+
case 'github-copilot':
|
|
36
|
+
return 'GitHub Copilot CLI';
|
|
31
37
|
default:
|
|
32
38
|
return 'Claude';
|
|
33
39
|
}
|
|
@@ -20,3 +20,6 @@ export declare class CodexStateDetector extends BaseStateDetector {
|
|
|
20
20
|
export declare class CursorStateDetector extends BaseStateDetector {
|
|
21
21
|
detectState(terminal: Terminal, _currentState: SessionState): SessionState;
|
|
22
22
|
}
|
|
23
|
+
export declare class GitHubCopilotStateDetector extends BaseStateDetector {
|
|
24
|
+
detectState(terminal: Terminal, _currentState: SessionState): SessionState;
|
|
25
|
+
}
|
|
@@ -8,6 +8,8 @@ export function createStateDetector(strategy = 'claude') {
|
|
|
8
8
|
return new CodexStateDetector();
|
|
9
9
|
case 'cursor':
|
|
10
10
|
return new CursorStateDetector();
|
|
11
|
+
case 'github-copilot':
|
|
12
|
+
return new GitHubCopilotStateDetector();
|
|
11
13
|
default:
|
|
12
14
|
return new ClaudeStateDetector();
|
|
13
15
|
}
|
|
@@ -109,3 +111,19 @@ export class CursorStateDetector extends BaseStateDetector {
|
|
|
109
111
|
return 'idle';
|
|
110
112
|
}
|
|
111
113
|
}
|
|
114
|
+
export class GitHubCopilotStateDetector extends BaseStateDetector {
|
|
115
|
+
detectState(terminal, _currentState) {
|
|
116
|
+
const content = this.getTerminalContent(terminal);
|
|
117
|
+
const lowerContent = content.toLowerCase();
|
|
118
|
+
// Waiting prompt has priority 1
|
|
119
|
+
if (lowerContent.includes('│ do you want')) {
|
|
120
|
+
return 'waiting_input';
|
|
121
|
+
}
|
|
122
|
+
// Busy state detection has priority 2
|
|
123
|
+
if (lowerContent.includes('esc to cancel')) {
|
|
124
|
+
return 'busy';
|
|
125
|
+
}
|
|
126
|
+
// Otherwise idle as priority 3
|
|
127
|
+
return 'idle';
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
-
import { ClaudeStateDetector, GeminiStateDetector, CodexStateDetector, CursorStateDetector, } from './stateDetector.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const buffer = {
|
|
2
|
+
import { ClaudeStateDetector, GeminiStateDetector, CodexStateDetector, CursorStateDetector, GitHubCopilotStateDetector, } from './stateDetector.js';
|
|
3
|
+
const createMockTerminal = (lines) => {
|
|
4
|
+
const buffer = {
|
|
5
|
+
length: lines.length,
|
|
6
|
+
active: {
|
|
8
7
|
length: lines.length,
|
|
9
8
|
getLine: (index) => {
|
|
10
9
|
if (index >= 0 && index < lines.length) {
|
|
@@ -14,13 +13,13 @@ describe('ClaudeStateDetector', () => {
|
|
|
14
13
|
}
|
|
15
14
|
return null;
|
|
16
15
|
},
|
|
17
|
-
}
|
|
18
|
-
return {
|
|
19
|
-
buffer: {
|
|
20
|
-
active: buffer,
|
|
21
|
-
},
|
|
22
|
-
};
|
|
16
|
+
},
|
|
23
17
|
};
|
|
18
|
+
return { buffer };
|
|
19
|
+
};
|
|
20
|
+
describe('ClaudeStateDetector', () => {
|
|
21
|
+
let detector;
|
|
22
|
+
let terminal;
|
|
24
23
|
beforeEach(() => {
|
|
25
24
|
detector = new ClaudeStateDetector();
|
|
26
25
|
});
|
|
@@ -159,24 +158,6 @@ describe('ClaudeStateDetector', () => {
|
|
|
159
158
|
describe('GeminiStateDetector', () => {
|
|
160
159
|
let detector;
|
|
161
160
|
let terminal;
|
|
162
|
-
const createMockTerminal = (lines) => {
|
|
163
|
-
const buffer = {
|
|
164
|
-
length: lines.length,
|
|
165
|
-
getLine: (index) => {
|
|
166
|
-
if (index >= 0 && index < lines.length) {
|
|
167
|
-
return {
|
|
168
|
-
translateToString: () => lines[index],
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
return null;
|
|
172
|
-
},
|
|
173
|
-
};
|
|
174
|
-
return {
|
|
175
|
-
buffer: {
|
|
176
|
-
active: buffer,
|
|
177
|
-
},
|
|
178
|
-
};
|
|
179
|
-
};
|
|
180
161
|
beforeEach(() => {
|
|
181
162
|
detector = new GeminiStateDetector();
|
|
182
163
|
});
|
|
@@ -275,23 +256,6 @@ describe('GeminiStateDetector', () => {
|
|
|
275
256
|
describe('CodexStateDetector', () => {
|
|
276
257
|
let detector;
|
|
277
258
|
let terminal;
|
|
278
|
-
const createMockTerminal = (lines) => {
|
|
279
|
-
const buffer = {
|
|
280
|
-
length: lines.length,
|
|
281
|
-
active: {
|
|
282
|
-
length: lines.length,
|
|
283
|
-
getLine: (index) => {
|
|
284
|
-
if (index >= 0 && index < lines.length) {
|
|
285
|
-
return {
|
|
286
|
-
translateToString: () => lines[index],
|
|
287
|
-
};
|
|
288
|
-
}
|
|
289
|
-
return null;
|
|
290
|
-
},
|
|
291
|
-
},
|
|
292
|
-
};
|
|
293
|
-
return { buffer };
|
|
294
|
-
};
|
|
295
259
|
beforeEach(() => {
|
|
296
260
|
detector = new CodexStateDetector();
|
|
297
261
|
});
|
|
@@ -366,23 +330,6 @@ describe('CodexStateDetector', () => {
|
|
|
366
330
|
describe('CursorStateDetector', () => {
|
|
367
331
|
let detector;
|
|
368
332
|
let terminal;
|
|
369
|
-
const createMockTerminal = (lines) => {
|
|
370
|
-
const buffer = {
|
|
371
|
-
length: lines.length,
|
|
372
|
-
active: {
|
|
373
|
-
length: lines.length,
|
|
374
|
-
getLine: (index) => {
|
|
375
|
-
if (index >= 0 && index < lines.length) {
|
|
376
|
-
return {
|
|
377
|
-
translateToString: () => lines[index],
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
return null;
|
|
381
|
-
},
|
|
382
|
-
},
|
|
383
|
-
};
|
|
384
|
-
return { buffer };
|
|
385
|
-
};
|
|
386
333
|
beforeEach(() => {
|
|
387
334
|
detector = new CursorStateDetector();
|
|
388
335
|
});
|
|
@@ -507,3 +454,55 @@ describe('CursorStateDetector', () => {
|
|
|
507
454
|
expect(state).toBe('idle');
|
|
508
455
|
});
|
|
509
456
|
});
|
|
457
|
+
describe('GitHubCopilotStateDetector', () => {
|
|
458
|
+
let detector;
|
|
459
|
+
let terminal;
|
|
460
|
+
beforeEach(() => {
|
|
461
|
+
detector = new GitHubCopilotStateDetector();
|
|
462
|
+
});
|
|
463
|
+
it('detects waiting_input when prompt asks "Do you want" (case insensitive)', () => {
|
|
464
|
+
// Arrange
|
|
465
|
+
terminal = createMockTerminal([
|
|
466
|
+
'Running GitHub Copilot CLI...',
|
|
467
|
+
'│ DO YOU WANT to run this command?',
|
|
468
|
+
'│ > ',
|
|
469
|
+
]);
|
|
470
|
+
// Act
|
|
471
|
+
const state = detector.detectState(terminal, 'idle');
|
|
472
|
+
// Assert
|
|
473
|
+
expect(state).toBe('waiting_input');
|
|
474
|
+
});
|
|
475
|
+
it('detects busy when "Esc to cancel" is present', () => {
|
|
476
|
+
// Arrange
|
|
477
|
+
terminal = createMockTerminal([
|
|
478
|
+
'Executing request...',
|
|
479
|
+
'Press Esc to cancel',
|
|
480
|
+
]);
|
|
481
|
+
// Act
|
|
482
|
+
const state = detector.detectState(terminal, 'idle');
|
|
483
|
+
// Assert
|
|
484
|
+
expect(state).toBe('busy');
|
|
485
|
+
});
|
|
486
|
+
it('prioritizes waiting_input over busy when both patterns exist', () => {
|
|
487
|
+
// Arrange
|
|
488
|
+
terminal = createMockTerminal([
|
|
489
|
+
'Press Esc to cancel',
|
|
490
|
+
'│ Do you want to continue?',
|
|
491
|
+
]);
|
|
492
|
+
// Act
|
|
493
|
+
const state = detector.detectState(terminal, 'idle');
|
|
494
|
+
// Assert
|
|
495
|
+
expect(state).toBe('waiting_input');
|
|
496
|
+
});
|
|
497
|
+
it('returns idle when no patterns match', () => {
|
|
498
|
+
// Arrange
|
|
499
|
+
terminal = createMockTerminal([
|
|
500
|
+
'GitHub Copilot CLI ready.',
|
|
501
|
+
'Type a command to begin.',
|
|
502
|
+
]);
|
|
503
|
+
// Act
|
|
504
|
+
const state = detector.detectState(terminal, 'idle');
|
|
505
|
+
// Assert
|
|
506
|
+
expect(state).toBe('idle');
|
|
507
|
+
});
|
|
508
|
+
});
|
package/dist/types/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type pkg from '@xterm/headless';
|
|
|
3
3
|
import { GitStatus } from '../utils/gitStatus.js';
|
|
4
4
|
export type Terminal = InstanceType<typeof pkg.Terminal>;
|
|
5
5
|
export type SessionState = 'idle' | 'busy' | 'waiting_input';
|
|
6
|
-
export type StateDetectionStrategy = 'claude' | 'gemini' | 'codex' | 'cursor';
|
|
6
|
+
export type StateDetectionStrategy = 'claude' | 'gemini' | 'codex' | 'cursor' | 'github-copilot';
|
|
7
7
|
export interface Worktree {
|
|
8
8
|
path: string;
|
|
9
9
|
branch?: string;
|