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.
- package/CHANGELOG.md +26 -0
- package/README.ja.md +34 -8
- package/README.md +41 -8
- package/dist/app/cli.js +1 -0
- package/dist/app/mcp.js +64 -12
- package/dist/cli-builder.js +13 -6
- package/dist/cli-process-service.js +76 -91
- package/dist/cli-utils.js +6 -0
- package/dist/cli.js +1 -1
- package/dist/model-catalog.js +3 -2
- package/dist/parsers.js +8 -2
- package/package.json +27 -3
- package/server.json +3 -3
- package/.gemini/settings.json +0 -11
- package/.github/dependabot.yml +0 -28
- package/.github/pull_request_template.md +0 -28
- package/.github/workflows/ci.yml +0 -34
- package/.github/workflows/dependency-review.yml +0 -22
- package/.github/workflows/publish.yml +0 -89
- package/.github/workflows/test.yml +0 -20
- package/.github/workflows/watch-session-prs.yml +0 -276
- package/.husky/pre-commit +0 -1
- package/.mcp.json +0 -11
- package/.releaserc.json +0 -18
- package/.vscode/settings.json +0 -3
- package/CONTRIBUTING.md +0 -81
- package/dist/__tests__/app-cli.test.js +0 -392
- package/dist/__tests__/cli-bin-smoke.test.js +0 -101
- package/dist/__tests__/cli-builder.test.js +0 -442
- package/dist/__tests__/cli-process-service.test.js +0 -655
- package/dist/__tests__/cli-utils.test.js +0 -171
- package/dist/__tests__/e2e.test.js +0 -256
- package/dist/__tests__/edge-cases.test.js +0 -130
- package/dist/__tests__/error-cases.test.js +0 -292
- package/dist/__tests__/mcp-contract.test.js +0 -636
- package/dist/__tests__/mocks.js +0 -32
- package/dist/__tests__/model-alias.test.js +0 -36
- package/dist/__tests__/parsers.test.js +0 -646
- package/dist/__tests__/peek.test.js +0 -36
- package/dist/__tests__/process-management.test.js +0 -949
- package/dist/__tests__/server.test.js +0 -809
- package/dist/__tests__/setup.js +0 -11
- package/dist/__tests__/utils/claude-mock.js +0 -80
- package/dist/__tests__/utils/mcp-client.js +0 -121
- package/dist/__tests__/utils/opencode-mock.js +0 -91
- package/dist/__tests__/utils/persistent-mock.js +0 -28
- package/dist/__tests__/utils/test-helpers.js +0 -11
- package/dist/__tests__/validation.test.js +0 -308
- package/dist/__tests__/version-print.test.js +0 -65
- package/dist/__tests__/wait.test.js +0 -260
- package/docs/RELEASE_CHECKLIST.md +0 -65
- package/docs/cli-architecture.md +0 -275
- package/docs/concept.md +0 -154
- package/docs/development.md +0 -156
- package/docs/e2e-testing.md +0 -148
- package/docs/prd.md +0 -146
- package/docs/session-stacking.md +0 -67
- package/src/__tests__/app-cli.test.ts +0 -495
- package/src/__tests__/cli-bin-smoke.test.ts +0 -136
- package/src/__tests__/cli-builder.test.ts +0 -549
- package/src/__tests__/cli-process-service.test.ts +0 -759
- package/src/__tests__/cli-utils.test.ts +0 -200
- package/src/__tests__/e2e.test.ts +0 -311
- package/src/__tests__/edge-cases.test.ts +0 -176
- package/src/__tests__/error-cases.test.ts +0 -370
- package/src/__tests__/mcp-contract.test.ts +0 -755
- package/src/__tests__/mocks.ts +0 -35
- package/src/__tests__/model-alias.test.ts +0 -44
- package/src/__tests__/parsers.test.ts +0 -730
- package/src/__tests__/peek.test.ts +0 -44
- package/src/__tests__/process-management.test.ts +0 -1129
- package/src/__tests__/server.test.ts +0 -1020
- package/src/__tests__/setup.ts +0 -13
- package/src/__tests__/utils/claude-mock.ts +0 -87
- package/src/__tests__/utils/mcp-client.ts +0 -159
- package/src/__tests__/utils/opencode-mock.ts +0 -108
- package/src/__tests__/utils/persistent-mock.ts +0 -33
- package/src/__tests__/utils/test-helpers.ts +0 -13
- package/src/__tests__/validation.test.ts +0 -369
- package/src/__tests__/version-print.test.ts +0 -81
- package/src/__tests__/wait.test.ts +0 -302
- package/src/app/cli.ts +0 -424
- package/src/app/mcp.ts +0 -466
- package/src/bin/ai-cli-mcp.ts +0 -7
- package/src/bin/ai-cli.ts +0 -11
- package/src/cli-builder.ts +0 -274
- package/src/cli-parse.ts +0 -105
- package/src/cli-process-service.ts +0 -709
- package/src/cli-utils.ts +0 -258
- package/src/cli.ts +0 -124
- package/src/model-catalog.ts +0 -87
- package/src/parsers.ts +0 -965
- package/src/peek.ts +0 -95
- package/src/process-result.ts +0 -88
- package/src/process-service.ts +0 -368
- package/src/server.ts +0 -10
- package/tsconfig.json +0 -16
- package/vitest.config.e2e.ts +0 -27
- package/vitest.config.ts +0 -22
- package/vitest.config.unit.ts +0 -28
package/src/__tests__/setup.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// Global test setup
|
|
2
|
-
import { beforeAll, afterAll } from 'vitest';
|
|
3
|
-
import { getSharedMock, cleanupSharedMock } from './utils/persistent-mock.js';
|
|
4
|
-
|
|
5
|
-
beforeAll(async () => {
|
|
6
|
-
console.error('[TEST SETUP] Creating shared mock for all tests...');
|
|
7
|
-
await getSharedMock();
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
afterAll(async () => {
|
|
11
|
-
console.error('[TEST SETUP] Cleaning up shared mock...');
|
|
12
|
-
await cleanupSharedMock();
|
|
13
|
-
});
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { join, dirname } from 'node:path';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Mock Claude CLI for testing
|
|
6
|
-
* This creates a fake Claude CLI that can be used during testing
|
|
7
|
-
*/
|
|
8
|
-
export class ClaudeMock {
|
|
9
|
-
private mockPath: string;
|
|
10
|
-
private responses = new Map<string, string>();
|
|
11
|
-
|
|
12
|
-
constructor(binaryName: string = 'claude') {
|
|
13
|
-
// Always use /tmp directory for mocks in tests
|
|
14
|
-
this.mockPath = join('/tmp', 'claude-code-test-mock', binaryName);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Setup the mock Claude CLI
|
|
19
|
-
*/
|
|
20
|
-
async setup(): Promise<void> {
|
|
21
|
-
const dir = dirname(this.mockPath);
|
|
22
|
-
if (!existsSync(dir)) {
|
|
23
|
-
mkdirSync(dir, { recursive: true });
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Create a simple bash script that echoes responses
|
|
27
|
-
const mockScript = `#!/bin/bash
|
|
28
|
-
# Mock Claude CLI for testing
|
|
29
|
-
|
|
30
|
-
# Extract the prompt from arguments
|
|
31
|
-
prompt=""
|
|
32
|
-
verbose=false
|
|
33
|
-
while [[ $# -gt 0 ]]; do
|
|
34
|
-
case $1 in
|
|
35
|
-
-p|--prompt)
|
|
36
|
-
prompt="$2"
|
|
37
|
-
shift 2
|
|
38
|
-
;;
|
|
39
|
-
--verbose)
|
|
40
|
-
verbose=true
|
|
41
|
-
shift
|
|
42
|
-
;;
|
|
43
|
-
--yes|-y|--dangerously-skip-permissions)
|
|
44
|
-
shift
|
|
45
|
-
;;
|
|
46
|
-
*)
|
|
47
|
-
shift
|
|
48
|
-
;;
|
|
49
|
-
esac
|
|
50
|
-
done
|
|
51
|
-
|
|
52
|
-
# Mock responses based on prompt
|
|
53
|
-
if [[ "$prompt" == *"create"* ]]; then
|
|
54
|
-
echo "Created file successfully"
|
|
55
|
-
elif [[ "$prompt" == *"Create"* ]]; then
|
|
56
|
-
echo "Created file successfully"
|
|
57
|
-
elif [[ "$prompt" == *"git"* ]] && [[ "$prompt" == *"commit"* ]]; then
|
|
58
|
-
echo "Committed changes successfully"
|
|
59
|
-
elif [[ "$prompt" == *"error"* ]]; then
|
|
60
|
-
echo "Error: Mock error response" >&2
|
|
61
|
-
exit 1
|
|
62
|
-
else
|
|
63
|
-
echo "Command executed successfully"
|
|
64
|
-
fi
|
|
65
|
-
`;
|
|
66
|
-
|
|
67
|
-
writeFileSync(this.mockPath, mockScript);
|
|
68
|
-
// Make executable
|
|
69
|
-
const { chmod } = await import('node:fs/promises');
|
|
70
|
-
await chmod(this.mockPath, 0o755);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Cleanup the mock Claude CLI
|
|
75
|
-
*/
|
|
76
|
-
async cleanup(): Promise<void> {
|
|
77
|
-
const { rm } = await import('node:fs/promises');
|
|
78
|
-
await rm(this.mockPath, { force: true });
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Add a mock response for a specific prompt pattern
|
|
83
|
-
*/
|
|
84
|
-
addResponse(pattern: string, response: string): void {
|
|
85
|
-
this.responses.set(pattern, response);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import { spawn, ChildProcess } from 'node:child_process';
|
|
2
|
-
import { EventEmitter } from 'node:events';
|
|
3
|
-
|
|
4
|
-
export interface MCPResponse {
|
|
5
|
-
jsonrpc: string;
|
|
6
|
-
id: number;
|
|
7
|
-
result?: any;
|
|
8
|
-
error?: {
|
|
9
|
-
code: number;
|
|
10
|
-
message: string;
|
|
11
|
-
data?: any;
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Mock MCP client for testing the server
|
|
17
|
-
*/
|
|
18
|
-
export class MCPTestClient extends EventEmitter {
|
|
19
|
-
private server: ChildProcess | null = null;
|
|
20
|
-
private requestId = 0;
|
|
21
|
-
private pendingRequests = new Map<number, {
|
|
22
|
-
resolve: (response: MCPResponse) => void;
|
|
23
|
-
reject: (error: Error) => void;
|
|
24
|
-
}>();
|
|
25
|
-
private buffer = '';
|
|
26
|
-
|
|
27
|
-
constructor(private serverPath: string, private env: Record<string, string> = {}) {
|
|
28
|
-
super();
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async connect(): Promise<void> {
|
|
32
|
-
return new Promise((resolve, reject) => {
|
|
33
|
-
this.server = spawn('node', [this.serverPath], {
|
|
34
|
-
env: { ...process.env, ...this.env },
|
|
35
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
this.server.stdout?.on('data', (data) => {
|
|
39
|
-
this.handleData(data.toString());
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
this.server.stderr?.on('data', (data) => {
|
|
43
|
-
console.error('Server stderr:', data.toString());
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
this.server.on('error', (error) => {
|
|
47
|
-
reject(error);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
this.server.on('spawn', () => {
|
|
51
|
-
resolve();
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async disconnect(): Promise<void> {
|
|
57
|
-
if (this.server) {
|
|
58
|
-
this.server.kill();
|
|
59
|
-
await new Promise((resolve) => {
|
|
60
|
-
this.server!.on('exit', resolve);
|
|
61
|
-
});
|
|
62
|
-
this.server = null;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
private handleData(data: string): void {
|
|
67
|
-
this.buffer += data;
|
|
68
|
-
const lines = this.buffer.split('\n');
|
|
69
|
-
this.buffer = lines.pop() || '';
|
|
70
|
-
|
|
71
|
-
for (const line of lines) {
|
|
72
|
-
if (!line.trim()) continue;
|
|
73
|
-
try {
|
|
74
|
-
const response = JSON.parse(line);
|
|
75
|
-
if (response.id && this.pendingRequests.has(response.id)) {
|
|
76
|
-
const pending = this.pendingRequests.get(response.id)!;
|
|
77
|
-
this.pendingRequests.delete(response.id);
|
|
78
|
-
pending.resolve(response);
|
|
79
|
-
} else {
|
|
80
|
-
this.emit('notification', response);
|
|
81
|
-
}
|
|
82
|
-
} catch (error) {
|
|
83
|
-
console.error('Failed to parse response:', line, error);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async sendRequest(method: string, params?: any): Promise<any> {
|
|
89
|
-
const id = ++this.requestId;
|
|
90
|
-
const request = {
|
|
91
|
-
jsonrpc: '2.0',
|
|
92
|
-
method,
|
|
93
|
-
params,
|
|
94
|
-
id,
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
return new Promise((resolve, reject) => {
|
|
98
|
-
this.pendingRequests.set(id, { resolve, reject });
|
|
99
|
-
|
|
100
|
-
this.server?.stdin?.write(JSON.stringify(request) + '\n');
|
|
101
|
-
|
|
102
|
-
// Timeout after 30 seconds
|
|
103
|
-
setTimeout(() => {
|
|
104
|
-
if (this.pendingRequests.has(id)) {
|
|
105
|
-
this.pendingRequests.delete(id);
|
|
106
|
-
reject(new Error(`Request ${id} timed out`));
|
|
107
|
-
}
|
|
108
|
-
}, 30000);
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
async callTool(name: string, args: any): Promise<any> {
|
|
113
|
-
const response = await this.sendRequest('tools/call', {
|
|
114
|
-
name,
|
|
115
|
-
arguments: args,
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
if (response.error) {
|
|
119
|
-
throw new Error(`Tool call failed: ${response.error.message}`);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return response.result?.content;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
async listTools(): Promise<any> {
|
|
126
|
-
const response = await this.sendRequest('tools/list');
|
|
127
|
-
return response.result?.tools || [];
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Default server path
|
|
133
|
-
*/
|
|
134
|
-
const DEFAULT_SERVER_PATH = 'dist/server.js';
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Create a test client with standard configuration
|
|
138
|
-
* Automatically unsets VITEST env so the server actually starts
|
|
139
|
-
*/
|
|
140
|
-
export function createTestClient(options: {
|
|
141
|
-
serverPath?: string;
|
|
142
|
-
claudeCliName?: string;
|
|
143
|
-
debug?: boolean;
|
|
144
|
-
env?: Record<string, string>;
|
|
145
|
-
} = {}): MCPTestClient {
|
|
146
|
-
const {
|
|
147
|
-
serverPath = DEFAULT_SERVER_PATH,
|
|
148
|
-
claudeCliName = process.env.TEST_CLAUDE_CLI_NAME || '/tmp/claude-code-test-mock/claudeMocked',
|
|
149
|
-
debug = true,
|
|
150
|
-
env = {},
|
|
151
|
-
} = options;
|
|
152
|
-
|
|
153
|
-
return new MCPTestClient(serverPath, {
|
|
154
|
-
VITEST: '', // Unset so server starts
|
|
155
|
-
MCP_CLAUDE_DEBUG: debug ? 'true' : '',
|
|
156
|
-
CLAUDE_CLI_NAME: claudeCliName,
|
|
157
|
-
...env,
|
|
158
|
-
});
|
|
159
|
-
}
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { chmodSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
|
|
4
|
-
export interface OpenCodeMockOptions {
|
|
5
|
-
argsLogPath?: string;
|
|
6
|
-
defaultSessionId?: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface OpenCodeMockResult {
|
|
10
|
-
scriptPath: string;
|
|
11
|
-
argsLogPath?: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function createOpenCodeMock(dir: string, options: OpenCodeMockOptions = {}): OpenCodeMockResult {
|
|
15
|
-
const scriptPath = join(dir, 'mock-opencode');
|
|
16
|
-
const defaultSessionId = options.defaultSessionId || 'ses-opencode-default';
|
|
17
|
-
const argsLogPath = options.argsLogPath;
|
|
18
|
-
const argsLogSection = argsLogPath
|
|
19
|
-
? `printf '%s\n' "$*" >> "${argsLogPath}"\n`
|
|
20
|
-
: '';
|
|
21
|
-
|
|
22
|
-
writeFileSync(
|
|
23
|
-
scriptPath,
|
|
24
|
-
`#!/bin/bash
|
|
25
|
-
set -euo pipefail
|
|
26
|
-
|
|
27
|
-
prompt=""
|
|
28
|
-
session_id=""
|
|
29
|
-
session_provided=0
|
|
30
|
-
model=""
|
|
31
|
-
work_dir=""
|
|
32
|
-
|
|
33
|
-
${argsLogSection}if [[ "\${1:-}" == "run" ]]; then
|
|
34
|
-
shift
|
|
35
|
-
fi
|
|
36
|
-
|
|
37
|
-
while [[ $# -gt 0 ]]; do
|
|
38
|
-
case "$1" in
|
|
39
|
-
--format)
|
|
40
|
-
shift 2
|
|
41
|
-
;;
|
|
42
|
-
--dir)
|
|
43
|
-
work_dir="$2"
|
|
44
|
-
shift 2
|
|
45
|
-
;;
|
|
46
|
-
--session)
|
|
47
|
-
session_id="$2"
|
|
48
|
-
session_provided=1
|
|
49
|
-
shift 2
|
|
50
|
-
;;
|
|
51
|
-
--model)
|
|
52
|
-
model="$2"
|
|
53
|
-
shift 2
|
|
54
|
-
;;
|
|
55
|
-
*)
|
|
56
|
-
prompt="$1"
|
|
57
|
-
shift
|
|
58
|
-
;;
|
|
59
|
-
esac
|
|
60
|
-
done
|
|
61
|
-
|
|
62
|
-
if [[ -z "$session_id" ]]; then
|
|
63
|
-
session_id="${defaultSessionId}"
|
|
64
|
-
fi
|
|
65
|
-
|
|
66
|
-
if [[ "$prompt" == *"sleep"* ]]; then
|
|
67
|
-
sleep 5
|
|
68
|
-
fi
|
|
69
|
-
|
|
70
|
-
if [[ "$prompt" == *"fail"* ]]; then
|
|
71
|
-
printf '{"type":"step_start","sessionID":"%s"}\n' "$session_id"
|
|
72
|
-
printf '{"type":"text","sessionID":"%s","part":{"type":"text","text":"Partial failure output"}}\n' "$session_id"
|
|
73
|
-
printf '{"type":"step_finish","sessionID":"%s","part":{"type":"step-finish","tokens":{"total":42},"cost":0}}\n' "$session_id"
|
|
74
|
-
printf 'OpenCode failed for %s in %s\n' "$model" "$work_dir" >&2
|
|
75
|
-
exit 7
|
|
76
|
-
fi
|
|
77
|
-
|
|
78
|
-
if [[ "$prompt" == *"multi-step"* ]]; then
|
|
79
|
-
printf '{"type":"step_start","sessionID":"%s"}\n' "$session_id"
|
|
80
|
-
printf '{"type":"text","sessionID":"%s","part":{"type":"text","text":"First step"}}\n' "$session_id"
|
|
81
|
-
printf '{"type":"step_finish","sessionID":"%s","part":{"type":"step-finish","tokens":{"total":11},"cost":0}}\n' "$session_id"
|
|
82
|
-
printf '{"type":"step_start","sessionID":"%s"}\n' "$session_id"
|
|
83
|
-
printf '{"type":"text","sessionID":"%s","part":{"type":"text","text":"Second step"}}\n' "$session_id"
|
|
84
|
-
printf '{"type":"step_finish","sessionID":"%s","part":{"type":"step-finish","tokens":{"total":22},"cost":1}}\n' "$session_id"
|
|
85
|
-
exit 0
|
|
86
|
-
fi
|
|
87
|
-
|
|
88
|
-
message_prefix="Initial"
|
|
89
|
-
if [[ $session_provided -eq 1 ]]; then
|
|
90
|
-
message_prefix="Resumed"
|
|
91
|
-
fi
|
|
92
|
-
if [[ -n "$model" ]]; then
|
|
93
|
-
message_prefix="Model $model"
|
|
94
|
-
if [[ $session_provided -eq 1 ]]; then
|
|
95
|
-
message_prefix="Resumed model $model"
|
|
96
|
-
fi
|
|
97
|
-
fi
|
|
98
|
-
|
|
99
|
-
printf '{"type":"step_start","sessionID":"%s"}\n' "$session_id"
|
|
100
|
-
printf '{"type":"text","sessionID":"%s","part":{"type":"text","text":"%s: %s"}}\n' "$session_id" "$message_prefix" "$prompt"
|
|
101
|
-
printf '{"type":"step_finish","sessionID":"%s","part":{"type":"step-finish","tokens":{"total":11833},"cost":0}}\n' "$session_id"
|
|
102
|
-
`,
|
|
103
|
-
'utf8',
|
|
104
|
-
);
|
|
105
|
-
chmodSync(scriptPath, 0o755);
|
|
106
|
-
|
|
107
|
-
return { scriptPath, argsLogPath };
|
|
108
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { ClaudeMock } from './claude-mock.js';
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
|
|
5
|
-
let sharedMock: ClaudeMock | null = null;
|
|
6
|
-
const workerId = process.env.VITEST_WORKER_ID || process.env.VITEST_POOL_ID || process.pid.toString();
|
|
7
|
-
const mockName = `claudeMocked-${workerId}`;
|
|
8
|
-
const mockPath = join('/tmp', 'claude-code-test-mock', mockName);
|
|
9
|
-
|
|
10
|
-
export async function getSharedMock(): Promise<ClaudeMock> {
|
|
11
|
-
if (!sharedMock) {
|
|
12
|
-
sharedMock = new ClaudeMock(mockName);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// Always ensure mock exists
|
|
16
|
-
if (!existsSync(mockPath)) {
|
|
17
|
-
console.error(`[DEBUG] Mock not found at ${mockPath}, creating it...`);
|
|
18
|
-
await sharedMock.setup();
|
|
19
|
-
} else {
|
|
20
|
-
console.error(`[DEBUG] Mock already exists at ${mockPath}`);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
process.env.TEST_CLAUDE_CLI_NAME = mockPath;
|
|
24
|
-
|
|
25
|
-
return sharedMock;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export async function cleanupSharedMock(): Promise<void> {
|
|
29
|
-
if (sharedMock) {
|
|
30
|
-
await sharedMock.cleanup();
|
|
31
|
-
sharedMock = null;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
|
|
4
|
-
export function verifyMockExists(binaryName: string): boolean {
|
|
5
|
-
const mockPath = join('/tmp', 'claude-code-test-mock', binaryName);
|
|
6
|
-
return existsSync(mockPath);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export async function ensureMockExists(mock: any): Promise<void> {
|
|
10
|
-
if (!verifyMockExists('claudeMocked')) {
|
|
11
|
-
await mock.setup();
|
|
12
|
-
}
|
|
13
|
-
}
|