ai-cli-mcp 2.18.0 → 2.20.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 (101) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.ja.md +37 -11
  3. package/README.md +44 -11
  4. package/dist/app/cli.js +2 -1
  5. package/dist/app/mcp.js +65 -13
  6. package/dist/cli-builder.js +13 -6
  7. package/dist/cli-process-service.js +81 -95
  8. package/dist/cli-utils.js +6 -0
  9. package/dist/cli.js +1 -1
  10. package/dist/model-catalog.js +3 -2
  11. package/dist/parsers.js +111 -8
  12. package/dist/process-service.js +5 -4
  13. package/package.json +26 -2
  14. package/server.json +3 -3
  15. package/.gemini/settings.json +0 -11
  16. package/.github/dependabot.yml +0 -28
  17. package/.github/pull_request_template.md +0 -28
  18. package/.github/workflows/ci.yml +0 -34
  19. package/.github/workflows/dependency-review.yml +0 -22
  20. package/.github/workflows/publish.yml +0 -89
  21. package/.github/workflows/test.yml +0 -20
  22. package/.github/workflows/watch-session-prs.yml +0 -276
  23. package/.husky/pre-commit +0 -1
  24. package/.mcp.json +0 -11
  25. package/.releaserc.json +0 -18
  26. package/.vscode/settings.json +0 -3
  27. package/CONTRIBUTING.md +0 -81
  28. package/dist/__tests__/app-cli.test.js +0 -392
  29. package/dist/__tests__/cli-bin-smoke.test.js +0 -101
  30. package/dist/__tests__/cli-builder.test.js +0 -442
  31. package/dist/__tests__/cli-process-service.test.js +0 -655
  32. package/dist/__tests__/cli-utils.test.js +0 -171
  33. package/dist/__tests__/e2e.test.js +0 -256
  34. package/dist/__tests__/edge-cases.test.js +0 -130
  35. package/dist/__tests__/error-cases.test.js +0 -292
  36. package/dist/__tests__/mcp-contract.test.js +0 -636
  37. package/dist/__tests__/mocks.js +0 -32
  38. package/dist/__tests__/model-alias.test.js +0 -36
  39. package/dist/__tests__/parsers.test.js +0 -500
  40. package/dist/__tests__/peek.test.js +0 -36
  41. package/dist/__tests__/process-management.test.js +0 -871
  42. package/dist/__tests__/server.test.js +0 -809
  43. package/dist/__tests__/setup.js +0 -11
  44. package/dist/__tests__/utils/claude-mock.js +0 -80
  45. package/dist/__tests__/utils/mcp-client.js +0 -121
  46. package/dist/__tests__/utils/opencode-mock.js +0 -91
  47. package/dist/__tests__/utils/persistent-mock.js +0 -28
  48. package/dist/__tests__/utils/test-helpers.js +0 -11
  49. package/dist/__tests__/validation.test.js +0 -308
  50. package/dist/__tests__/version-print.test.js +0 -65
  51. package/dist/__tests__/wait.test.js +0 -260
  52. package/docs/RELEASE_CHECKLIST.md +0 -65
  53. package/docs/cli-architecture.md +0 -275
  54. package/docs/concept.md +0 -154
  55. package/docs/development.md +0 -156
  56. package/docs/e2e-testing.md +0 -148
  57. package/docs/prd.md +0 -146
  58. package/docs/session-stacking.md +0 -67
  59. package/src/__tests__/app-cli.test.ts +0 -495
  60. package/src/__tests__/cli-bin-smoke.test.ts +0 -136
  61. package/src/__tests__/cli-builder.test.ts +0 -549
  62. package/src/__tests__/cli-process-service.test.ts +0 -759
  63. package/src/__tests__/cli-utils.test.ts +0 -200
  64. package/src/__tests__/e2e.test.ts +0 -311
  65. package/src/__tests__/edge-cases.test.ts +0 -176
  66. package/src/__tests__/error-cases.test.ts +0 -370
  67. package/src/__tests__/mcp-contract.test.ts +0 -755
  68. package/src/__tests__/mocks.ts +0 -35
  69. package/src/__tests__/model-alias.test.ts +0 -44
  70. package/src/__tests__/parsers.test.ts +0 -564
  71. package/src/__tests__/peek.test.ts +0 -44
  72. package/src/__tests__/process-management.test.ts +0 -1043
  73. package/src/__tests__/server.test.ts +0 -1020
  74. package/src/__tests__/setup.ts +0 -13
  75. package/src/__tests__/utils/claude-mock.ts +0 -87
  76. package/src/__tests__/utils/mcp-client.ts +0 -159
  77. package/src/__tests__/utils/opencode-mock.ts +0 -108
  78. package/src/__tests__/utils/persistent-mock.ts +0 -33
  79. package/src/__tests__/utils/test-helpers.ts +0 -13
  80. package/src/__tests__/validation.test.ts +0 -369
  81. package/src/__tests__/version-print.test.ts +0 -81
  82. package/src/__tests__/wait.test.ts +0 -302
  83. package/src/app/cli.ts +0 -424
  84. package/src/app/mcp.ts +0 -466
  85. package/src/bin/ai-cli-mcp.ts +0 -7
  86. package/src/bin/ai-cli.ts +0 -11
  87. package/src/cli-builder.ts +0 -274
  88. package/src/cli-parse.ts +0 -105
  89. package/src/cli-process-service.ts +0 -708
  90. package/src/cli-utils.ts +0 -258
  91. package/src/cli.ts +0 -124
  92. package/src/model-catalog.ts +0 -87
  93. package/src/parsers.ts +0 -840
  94. package/src/peek.ts +0 -95
  95. package/src/process-result.ts +0 -88
  96. package/src/process-service.ts +0 -367
  97. package/src/server.ts +0 -10
  98. package/tsconfig.json +0 -16
  99. package/vitest.config.e2e.ts +0 -27
  100. package/vitest.config.ts +0 -22
  101. package/vitest.config.unit.ts +0 -28
@@ -1,302 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
- import { EventEmitter } from 'node:events';
3
- import { spawn } from 'node:child_process';
4
- import { homedir } from 'node:os';
5
- import { existsSync } from 'node:fs';
6
- import { resolve as pathResolve } from 'node:path';
7
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
8
-
9
- // Mock dependencies
10
- vi.mock('node:child_process');
11
- vi.mock('node:fs');
12
- vi.mock('node:os');
13
- vi.mock('node:path', () => ({
14
- resolve: vi.fn((path) => path),
15
- join: vi.fn((...args) => args.join('/')),
16
- isAbsolute: vi.fn((path) => path.startsWith('/')),
17
- dirname: vi.fn((path) => '/tmp')
18
- }));
19
- vi.mock('@modelcontextprotocol/sdk/server/stdio.js');
20
- vi.mock('@modelcontextprotocol/sdk/types.js', () => ({
21
- ListToolsRequestSchema: { name: 'listTools' },
22
- CallToolRequestSchema: { name: 'callTool' },
23
- ErrorCode: {
24
- InternalError: 'InternalError',
25
- MethodNotFound: 'MethodNotFound',
26
- InvalidParams: 'InvalidParams'
27
- },
28
- McpError: class extends Error {
29
- code: any;
30
- constructor(code: any, message: string) {
31
- super(message);
32
- this.code = code;
33
- }
34
- }
35
- }));
36
- vi.mock('@modelcontextprotocol/sdk/server/index.js', () => ({
37
- Server: vi.fn().mockImplementation(function(this: any) {
38
- this.setRequestHandler = vi.fn();
39
- this.connect = vi.fn();
40
- this.close = vi.fn();
41
- this.onerror = undefined;
42
- return this;
43
- }),
44
- }));
45
-
46
- // Mock package.json
47
- vi.mock('../../package.json', () => ({
48
- default: { version: '1.0.0-test' }
49
- }));
50
-
51
- // Re-import after mocks
52
- const mockSpawn = vi.mocked(spawn);
53
- const mockHomedir = vi.mocked(homedir);
54
- const mockExistsSync = vi.mocked(existsSync);
55
-
56
- describe('Wait Tool Tests', () => {
57
- let handlers: Map<string, Function>;
58
- let mockServerInstance: any;
59
- let server: any;
60
-
61
- // Setup function to initialize server with mocks
62
- const setupServer = async () => {
63
- vi.resetModules();
64
- handlers = new Map();
65
-
66
- // Mock Server implementation to capture handlers
67
- vi.mocked(Server).mockImplementation(function(this: any) {
68
- this.setRequestHandler = vi.fn((schema, handler) => {
69
- handlers.set(schema.name, handler);
70
- });
71
- this.connect = vi.fn();
72
- this.close = vi.fn();
73
- return this;
74
- });
75
-
76
- const module = await import('../server.js');
77
- // @ts-ignore
78
- const { ClaudeCodeServer } = module;
79
- server = new ClaudeCodeServer();
80
- mockServerInstance = vi.mocked(Server).mock.results[0].value;
81
- };
82
-
83
- beforeEach(async () => {
84
- mockHomedir.mockReturnValue('/home/user');
85
- mockExistsSync.mockReturnValue(true);
86
- await setupServer();
87
- });
88
-
89
- afterEach(() => {
90
- vi.clearAllMocks();
91
- vi.useRealTimers();
92
- });
93
-
94
- const createMockProcess = (pid: number) => {
95
- const mockProcess = new EventEmitter() as any;
96
- mockProcess.pid = pid;
97
- mockProcess.stdout = new EventEmitter();
98
- mockProcess.stderr = new EventEmitter();
99
- mockProcess.stdout.on = vi.fn();
100
- mockProcess.stderr.on = vi.fn();
101
- mockProcess.kill = vi.fn();
102
- return mockProcess;
103
- };
104
-
105
- it('should wait for a single running process', async () => {
106
- const callToolHandler = handlers.get('callTool')!;
107
- const mockProcess = createMockProcess(12345);
108
- mockSpawn.mockReturnValue(mockProcess);
109
-
110
- // Start a process first
111
- await callToolHandler({
112
- params: {
113
- name: 'run',
114
- arguments: {
115
- prompt: 'test prompt',
116
- workFolder: '/tmp'
117
- }
118
- }
119
- });
120
-
121
- // Mock process output accumulation (simulated internally by server)
122
- // We need to access the process manager or simulate events
123
-
124
- // Call wait
125
- const waitPromise = callToolHandler({
126
- params: {
127
- name: 'wait',
128
- arguments: {
129
- pids: [12345]
130
- }
131
- }
132
- });
133
-
134
- // Simulate process completion after a delay
135
- setTimeout(() => {
136
- mockProcess.stdout.emit('data', 'Process output');
137
- mockProcess.emit('close', 0);
138
- }, 10);
139
-
140
- const result = await waitPromise;
141
- const response = JSON.parse(result.content[0].text);
142
-
143
- expect(response).toHaveLength(1);
144
- expect(response[0].pid).toBe(12345);
145
- expect(response[0].status).toBe('completed');
146
- // expect(response[0].stdout).toBe('Process output'); // Flaky test
147
- });
148
-
149
- it('should return immediately if process is already completed', async () => {
150
- const callToolHandler = handlers.get('callTool')!;
151
- const mockProcess = createMockProcess(12346);
152
- mockSpawn.mockReturnValue(mockProcess);
153
-
154
- // Start process
155
- await callToolHandler({
156
- params: {
157
- name: 'run',
158
- arguments: {
159
- prompt: 'test',
160
- workFolder: '/tmp'
161
- }
162
- }
163
- });
164
-
165
- // Complete immediately
166
- mockProcess.emit('close', 0);
167
-
168
- // Call wait
169
- const result = await callToolHandler({
170
- params: {
171
- name: 'wait',
172
- arguments: {
173
- pids: [12346]
174
- }
175
- }
176
- });
177
-
178
- const response = JSON.parse(result.content[0].text);
179
- expect(response[0].status).toBe('completed');
180
- });
181
-
182
- it('should wait for multiple processes', async () => {
183
- const callToolHandler = handlers.get('callTool')!;
184
-
185
- // Process 1
186
- const p1 = createMockProcess(101);
187
- mockSpawn.mockReturnValueOnce(p1);
188
- await callToolHandler({
189
- params: { name: 'run', arguments: { prompt: 'p1', workFolder: '/tmp' } }
190
- });
191
-
192
- // Process 2
193
- const p2 = createMockProcess(102);
194
- mockSpawn.mockReturnValueOnce(p2);
195
- await callToolHandler({
196
- params: { name: 'run', arguments: { prompt: 'p2', workFolder: '/tmp' } }
197
- });
198
-
199
- // Wait for both
200
- const waitPromise = callToolHandler({
201
- params: {
202
- name: 'wait',
203
- arguments: { pids: [101, 102] }
204
- }
205
- });
206
-
207
- // Finish p1
208
- setTimeout(() => { p1.emit('close', 0); }, 10);
209
- // Finish p2 later
210
- setTimeout(() => { p2.emit('close', 0); }, 30);
211
-
212
- const result = await waitPromise;
213
- const response = JSON.parse(result.content[0].text);
214
-
215
- expect(response).toHaveLength(2);
216
- expect(response.find((r: any) => r.pid === 101).status).toBe('completed');
217
- expect(response.find((r: any) => r.pid === 102).status).toBe('completed');
218
- });
219
-
220
- it('should clear timeout timers after wait resolves', async () => {
221
- vi.useFakeTimers();
222
-
223
- const callToolHandler = handlers.get('callTool')!;
224
- const mockProcess = createMockProcess(12348);
225
- mockSpawn.mockReturnValue(mockProcess);
226
-
227
- await callToolHandler({
228
- params: {
229
- name: 'run',
230
- arguments: {
231
- prompt: 'test prompt',
232
- workFolder: '/tmp'
233
- }
234
- }
235
- });
236
-
237
- const waitPromise = callToolHandler({
238
- params: {
239
- name: 'wait',
240
- arguments: {
241
- pids: [12348],
242
- timeout: 180
243
- }
244
- }
245
- });
246
-
247
- mockProcess.emit('close', 0);
248
- await vi.runAllTicks();
249
-
250
- const result = await waitPromise;
251
- const response = JSON.parse(result.content[0].text);
252
-
253
- expect(response[0].status).toBe('completed');
254
- expect(vi.getTimerCount()).toBe(0);
255
- });
256
-
257
- it('should throw error for non-existent PID', async () => {
258
- const callToolHandler = handlers.get('callTool')!;
259
-
260
- try {
261
- await callToolHandler({
262
- params: {
263
- name: 'wait',
264
- arguments: { pids: [99999] }
265
- }
266
- });
267
- expect.fail('Should have thrown');
268
- } catch (error: any) {
269
- expect(error.message).toContain('Process with PID 99999 not found');
270
- }
271
- });
272
-
273
- it('should handle timeout', async () => {
274
- const callToolHandler = handlers.get('callTool')!;
275
- const mockProcess = createMockProcess(12347);
276
- mockSpawn.mockReturnValue(mockProcess);
277
-
278
- await callToolHandler({
279
- params: { name: 'run', arguments: { prompt: 'test', workFolder: '/tmp' } }
280
- });
281
-
282
- // Call wait with short timeout
283
- const waitPromise = callToolHandler({
284
- params: {
285
- name: 'wait',
286
- arguments: {
287
- pids: [12347],
288
- timeout: 0.1 // 100ms
289
- }
290
- }
291
- });
292
-
293
- // Don't emit close event
294
-
295
- try {
296
- await waitPromise;
297
- expect.fail('Should have thrown');
298
- } catch (error: any) {
299
- expect(error.message).toContain('Timed out');
300
- }
301
- });
302
- });