ai-cli-mcp 2.19.0 → 2.20.1

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 (100) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.ja.md +34 -8
  3. package/README.md +41 -8
  4. package/dist/app/cli.js +1 -0
  5. package/dist/app/mcp.js +64 -12
  6. package/dist/cli-builder.js +13 -6
  7. package/dist/cli-process-service.js +76 -91
  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 +8 -2
  12. package/package.json +27 -3
  13. package/server.json +3 -3
  14. package/.gemini/settings.json +0 -11
  15. package/.github/dependabot.yml +0 -28
  16. package/.github/pull_request_template.md +0 -28
  17. package/.github/workflows/ci.yml +0 -34
  18. package/.github/workflows/dependency-review.yml +0 -22
  19. package/.github/workflows/publish.yml +0 -89
  20. package/.github/workflows/test.yml +0 -20
  21. package/.github/workflows/watch-session-prs.yml +0 -276
  22. package/.husky/pre-commit +0 -1
  23. package/.mcp.json +0 -11
  24. package/.releaserc.json +0 -18
  25. package/.vscode/settings.json +0 -3
  26. package/CONTRIBUTING.md +0 -81
  27. package/dist/__tests__/app-cli.test.js +0 -392
  28. package/dist/__tests__/cli-bin-smoke.test.js +0 -101
  29. package/dist/__tests__/cli-builder.test.js +0 -442
  30. package/dist/__tests__/cli-process-service.test.js +0 -655
  31. package/dist/__tests__/cli-utils.test.js +0 -171
  32. package/dist/__tests__/e2e.test.js +0 -256
  33. package/dist/__tests__/edge-cases.test.js +0 -130
  34. package/dist/__tests__/error-cases.test.js +0 -292
  35. package/dist/__tests__/mcp-contract.test.js +0 -636
  36. package/dist/__tests__/mocks.js +0 -32
  37. package/dist/__tests__/model-alias.test.js +0 -36
  38. package/dist/__tests__/parsers.test.js +0 -646
  39. package/dist/__tests__/peek.test.js +0 -36
  40. package/dist/__tests__/process-management.test.js +0 -949
  41. package/dist/__tests__/server.test.js +0 -809
  42. package/dist/__tests__/setup.js +0 -11
  43. package/dist/__tests__/utils/claude-mock.js +0 -80
  44. package/dist/__tests__/utils/mcp-client.js +0 -121
  45. package/dist/__tests__/utils/opencode-mock.js +0 -91
  46. package/dist/__tests__/utils/persistent-mock.js +0 -28
  47. package/dist/__tests__/utils/test-helpers.js +0 -11
  48. package/dist/__tests__/validation.test.js +0 -308
  49. package/dist/__tests__/version-print.test.js +0 -65
  50. package/dist/__tests__/wait.test.js +0 -260
  51. package/docs/RELEASE_CHECKLIST.md +0 -65
  52. package/docs/cli-architecture.md +0 -275
  53. package/docs/concept.md +0 -154
  54. package/docs/development.md +0 -156
  55. package/docs/e2e-testing.md +0 -148
  56. package/docs/prd.md +0 -146
  57. package/docs/session-stacking.md +0 -67
  58. package/src/__tests__/app-cli.test.ts +0 -495
  59. package/src/__tests__/cli-bin-smoke.test.ts +0 -136
  60. package/src/__tests__/cli-builder.test.ts +0 -549
  61. package/src/__tests__/cli-process-service.test.ts +0 -759
  62. package/src/__tests__/cli-utils.test.ts +0 -200
  63. package/src/__tests__/e2e.test.ts +0 -311
  64. package/src/__tests__/edge-cases.test.ts +0 -176
  65. package/src/__tests__/error-cases.test.ts +0 -370
  66. package/src/__tests__/mcp-contract.test.ts +0 -755
  67. package/src/__tests__/mocks.ts +0 -35
  68. package/src/__tests__/model-alias.test.ts +0 -44
  69. package/src/__tests__/parsers.test.ts +0 -730
  70. package/src/__tests__/peek.test.ts +0 -44
  71. package/src/__tests__/process-management.test.ts +0 -1129
  72. package/src/__tests__/server.test.ts +0 -1020
  73. package/src/__tests__/setup.ts +0 -13
  74. package/src/__tests__/utils/claude-mock.ts +0 -87
  75. package/src/__tests__/utils/mcp-client.ts +0 -159
  76. package/src/__tests__/utils/opencode-mock.ts +0 -108
  77. package/src/__tests__/utils/persistent-mock.ts +0 -33
  78. package/src/__tests__/utils/test-helpers.ts +0 -13
  79. package/src/__tests__/validation.test.ts +0 -369
  80. package/src/__tests__/version-print.test.ts +0 -81
  81. package/src/__tests__/wait.test.ts +0 -302
  82. package/src/app/cli.ts +0 -424
  83. package/src/app/mcp.ts +0 -466
  84. package/src/bin/ai-cli-mcp.ts +0 -7
  85. package/src/bin/ai-cli.ts +0 -11
  86. package/src/cli-builder.ts +0 -274
  87. package/src/cli-parse.ts +0 -105
  88. package/src/cli-process-service.ts +0 -709
  89. package/src/cli-utils.ts +0 -258
  90. package/src/cli.ts +0 -124
  91. package/src/model-catalog.ts +0 -87
  92. package/src/parsers.ts +0 -965
  93. package/src/peek.ts +0 -95
  94. package/src/process-result.ts +0 -88
  95. package/src/process-service.ts +0 -368
  96. package/src/server.ts +0 -10
  97. package/tsconfig.json +0 -16
  98. package/vitest.config.e2e.ts +0 -27
  99. package/vitest.config.ts +0 -22
  100. package/vitest.config.unit.ts +0 -28
@@ -1,292 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
- import { spawn } from 'node:child_process';
3
- import { existsSync } from 'node:fs';
4
- import { homedir } from 'node:os';
5
- import { EventEmitter } from 'node:events';
6
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
7
- // Mock dependencies
8
- vi.mock('node:child_process');
9
- vi.mock('node:fs');
10
- vi.mock('node:os');
11
- vi.mock('node:path', () => ({
12
- resolve: vi.fn((path) => path),
13
- join: vi.fn((...args) => args.join('/')),
14
- isAbsolute: vi.fn((path) => path.startsWith('/'))
15
- }));
16
- vi.mock('@modelcontextprotocol/sdk/server/index.js', () => ({
17
- Server: vi.fn().mockImplementation(function () {
18
- this.setRequestHandler = vi.fn();
19
- this.connect = vi.fn();
20
- this.close = vi.fn();
21
- this.onerror = undefined;
22
- return this;
23
- }),
24
- }));
25
- vi.mock('@modelcontextprotocol/sdk/types.js', () => ({
26
- ListToolsRequestSchema: { name: 'listTools' },
27
- CallToolRequestSchema: { name: 'callTool' },
28
- ErrorCode: {
29
- InternalError: 'InternalError',
30
- MethodNotFound: 'MethodNotFound',
31
- InvalidParams: 'InvalidParams'
32
- },
33
- McpError: class extends Error {
34
- code;
35
- constructor(code, message) {
36
- super(message);
37
- this.code = code;
38
- }
39
- }
40
- }));
41
- const mockExistsSync = vi.mocked(existsSync);
42
- const mockSpawn = vi.mocked(spawn);
43
- const mockHomedir = vi.mocked(homedir);
44
- describe('Error Handling Tests', () => {
45
- let consoleErrorSpy;
46
- let originalEnv;
47
- let errorHandler = null;
48
- function setupServerMock() {
49
- errorHandler = null;
50
- vi.mocked(Server).mockImplementation(function () {
51
- this.setRequestHandler = vi.fn();
52
- this.connect = vi.fn();
53
- this.close = vi.fn();
54
- Object.defineProperty(this, 'onerror', {
55
- get() { return errorHandler; },
56
- set(handler) { errorHandler = handler; },
57
- enumerable: true,
58
- configurable: true
59
- });
60
- return this;
61
- });
62
- }
63
- beforeEach(() => {
64
- vi.clearAllMocks();
65
- vi.resetModules();
66
- consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
67
- originalEnv = { ...process.env };
68
- process.env = { ...originalEnv };
69
- });
70
- afterEach(() => {
71
- consoleErrorSpy.mockRestore();
72
- process.env = originalEnv;
73
- });
74
- describe('CallToolRequest Error Cases', () => {
75
- it('should throw error for unknown tool name', async () => {
76
- mockHomedir.mockReturnValue('/home/user');
77
- mockExistsSync.mockReturnValue(true);
78
- // Set up Server mock before importing the module
79
- setupServerMock();
80
- const module = await import('../server.js');
81
- // @ts-ignore
82
- const { ClaudeCodeServer } = module;
83
- const server = new ClaudeCodeServer();
84
- const mockServerInstance = vi.mocked(Server).mock.results[0].value;
85
- const callToolCall = mockServerInstance.setRequestHandler.mock.calls.find((call) => call[0].name === 'callTool');
86
- const handler = callToolCall[1];
87
- await expect(handler({
88
- params: {
89
- name: 'unknown_tool',
90
- arguments: {}
91
- }
92
- })).rejects.toThrow('Tool unknown_tool not found');
93
- });
94
- it('should handle timeout errors', async () => {
95
- mockHomedir.mockReturnValue('/home/user');
96
- mockExistsSync.mockReturnValue(true);
97
- setupServerMock();
98
- const module = await import('../server.js');
99
- // @ts-ignore
100
- const { ClaudeCodeServer } = module;
101
- const { McpError } = await import('@modelcontextprotocol/sdk/types.js');
102
- const server = new ClaudeCodeServer();
103
- const mockServerInstance = vi.mocked(Server).mock.results[0].value;
104
- // Find the callTool handler
105
- let callToolHandler;
106
- for (const call of mockServerInstance.setRequestHandler.mock.calls) {
107
- if (call[0].name === 'callTool') {
108
- callToolHandler = call[1];
109
- break;
110
- }
111
- }
112
- // Mock spawn to return process without PID
113
- mockSpawn.mockImplementation(() => {
114
- const mockProcess = new EventEmitter();
115
- mockProcess.stdout = new EventEmitter();
116
- mockProcess.stderr = new EventEmitter();
117
- mockProcess.stdout.on = vi.fn();
118
- mockProcess.stderr.on = vi.fn();
119
- mockProcess.pid = undefined; // No PID to simulate process start failure
120
- return mockProcess;
121
- });
122
- // Call handler
123
- await expect(callToolHandler({
124
- params: {
125
- name: 'run',
126
- arguments: {
127
- prompt: 'test',
128
- workFolder: '/tmp'
129
- }
130
- }
131
- })).rejects.toThrow('Failed to start claude CLI process');
132
- });
133
- it('should handle invalid argument types', async () => {
134
- mockHomedir.mockReturnValue('/home/user');
135
- mockExistsSync.mockReturnValue(true);
136
- setupServerMock();
137
- const module = await import('../server.js');
138
- // @ts-ignore
139
- const { ClaudeCodeServer } = module;
140
- const server = new ClaudeCodeServer();
141
- const mockServerInstance = vi.mocked(Server).mock.results[0].value;
142
- const callToolCall = mockServerInstance.setRequestHandler.mock.calls.find((call) => call[0].name === 'callTool');
143
- const handler = callToolCall[1];
144
- await expect(handler({
145
- params: {
146
- name: 'run',
147
- arguments: 'invalid-should-be-object'
148
- }
149
- })).rejects.toThrow();
150
- });
151
- it('should include CLI error details in error message', async () => {
152
- mockHomedir.mockReturnValue('/home/user');
153
- mockExistsSync.mockReturnValue(true);
154
- setupServerMock();
155
- const module = await import('../server.js');
156
- // @ts-ignore
157
- const { ClaudeCodeServer } = module;
158
- const server = new ClaudeCodeServer();
159
- const mockServerInstance = vi.mocked(Server).mock.results[0].value;
160
- const callToolCall = mockServerInstance.setRequestHandler.mock.calls.find((call) => call[0].name === 'callTool');
161
- const handler = callToolCall[1];
162
- // Create a simple mock process
163
- mockSpawn.mockImplementation(() => {
164
- const mockProcess = Object.create(EventEmitter.prototype);
165
- EventEmitter.call(mockProcess);
166
- mockProcess.stdout = Object.create(EventEmitter.prototype);
167
- EventEmitter.call(mockProcess.stdout);
168
- mockProcess.stderr = Object.create(EventEmitter.prototype);
169
- EventEmitter.call(mockProcess.stderr);
170
- mockProcess.stdout.on = vi.fn((event, callback) => {
171
- if (event === 'data') {
172
- // Send some stdout data
173
- process.nextTick(() => callback('stdout content'));
174
- }
175
- });
176
- mockProcess.stderr.on = vi.fn((event, callback) => {
177
- if (event === 'data') {
178
- // Send some stderr data
179
- process.nextTick(() => callback('stderr content'));
180
- }
181
- });
182
- // Emit error/close event after data is sent
183
- setTimeout(() => {
184
- mockProcess.emit('close', 1);
185
- }, 1);
186
- return mockProcess;
187
- });
188
- await expect(handler({
189
- params: {
190
- name: 'run',
191
- arguments: {
192
- prompt: 'test',
193
- workFolder: '/tmp'
194
- }
195
- }
196
- })).rejects.toThrow();
197
- });
198
- });
199
- describe('Process Spawn Error Cases', () => {
200
- it('should handle spawn ENOENT error', async () => {
201
- const module = await import('../server.js');
202
- // @ts-ignore
203
- const { spawnAsync } = module;
204
- const mockProcess = new EventEmitter();
205
- mockProcess.stdout = new EventEmitter();
206
- mockProcess.stderr = new EventEmitter();
207
- mockProcess.stdout.on = vi.fn();
208
- mockProcess.stderr.on = vi.fn();
209
- mockSpawn.mockReturnValue(mockProcess);
210
- const promise = spawnAsync('nonexistent-command', []);
211
- // Simulate ENOENT error
212
- setTimeout(() => {
213
- const error = new Error('spawn ENOENT');
214
- error.code = 'ENOENT';
215
- error.path = 'nonexistent-command';
216
- error.syscall = 'spawn';
217
- mockProcess.emit('error', error);
218
- }, 10);
219
- await expect(promise).rejects.toThrow('Spawn error');
220
- await expect(promise).rejects.toThrow('nonexistent-command');
221
- });
222
- it('should handle generic spawn errors', async () => {
223
- const module = await import('../server.js');
224
- // @ts-ignore
225
- const { spawnAsync } = module;
226
- const mockProcess = new EventEmitter();
227
- mockProcess.stdout = new EventEmitter();
228
- mockProcess.stderr = new EventEmitter();
229
- mockProcess.stdout.on = vi.fn();
230
- mockProcess.stderr.on = vi.fn();
231
- mockSpawn.mockReturnValue(mockProcess);
232
- const promise = spawnAsync('test', []);
233
- // Simulate generic error
234
- setTimeout(() => {
235
- mockProcess.emit('error', new Error('Generic spawn error'));
236
- }, 10);
237
- await expect(promise).rejects.toThrow('Generic spawn error');
238
- });
239
- it('should accumulate stderr output before error', async () => {
240
- const module = await import('../server.js');
241
- // @ts-ignore
242
- const { spawnAsync } = module;
243
- const mockProcess = new EventEmitter();
244
- mockProcess.stdout = new EventEmitter();
245
- mockProcess.stderr = new EventEmitter();
246
- let stderrHandler;
247
- mockProcess.stdout.on = vi.fn();
248
- mockProcess.stderr.on = vi.fn((event, handler) => {
249
- if (event === 'data')
250
- stderrHandler = handler;
251
- });
252
- mockSpawn.mockReturnValue(mockProcess);
253
- const promise = spawnAsync('test', []);
254
- // Simulate stderr data then error
255
- setTimeout(() => {
256
- stderrHandler('error line 1\n');
257
- stderrHandler('error line 2\n');
258
- mockProcess.emit('error', new Error('Command failed'));
259
- }, 10);
260
- await expect(promise).rejects.toThrow('error line 1\nerror line 2');
261
- });
262
- });
263
- describe('Server Initialization Errors', () => {
264
- it('should handle CLI path not found gracefully', async () => {
265
- // Mock no CLI found anywhere
266
- mockHomedir.mockReturnValue('/home/user');
267
- mockExistsSync.mockReturnValue(false);
268
- const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
269
- setupServerMock();
270
- const module = await import('../server.js');
271
- // @ts-ignore
272
- const { ClaudeCodeServer } = module;
273
- const server = new ClaudeCodeServer();
274
- expect(server).toBeDefined();
275
- expect(consoleWarnSpy).not.toHaveBeenCalled();
276
- consoleWarnSpy.mockRestore();
277
- });
278
- it('should handle server connection errors', async () => {
279
- mockHomedir.mockReturnValue('/home/user');
280
- mockExistsSync.mockReturnValue(true);
281
- setupServerMock();
282
- const module = await import('../server.js');
283
- // @ts-ignore
284
- const { ClaudeCodeServer } = module;
285
- const server = new ClaudeCodeServer();
286
- // Mock connection failure
287
- const mockServerInstance = vi.mocked(Server).mock.results[0].value;
288
- mockServerInstance.connect.mockRejectedValue(new Error('Connection failed'));
289
- await expect(server.run()).rejects.toThrow('Connection failed');
290
- });
291
- });
292
- });