@mcpeak/cli 0.10.0 → 0.12.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.
- package/LICENSE +1 -1
- package/README.md +5 -0
- package/dist/cli.cjs +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/commands.cjs +2 -3
- package/dist/commands.d.cts +28 -6
- package/dist/commands.d.mts +28 -6
- package/dist/commands.mjs +2 -2
- package/dist/index.cjs +219 -5
- package/dist/index.d.cts +3 -14
- package/dist/index.d.mts +3 -14
- package/dist/index.mjs +217 -2
- package/dist/{replay-command-BAtSzf8R.d.mts → repair-command-8GUlJJ47.d.mts} +91 -49
- package/dist/{replay-command-V0ZSJPiD.d.cts → repair-command-CVFqxU6V.d.cts} +91 -49
- package/dist/{test-command-BbjJIX7j.cjs → test-command-1m3myzTS.cjs} +2516 -1151
- package/dist/{test-command-CtQbeyhy.mjs → test-command-P8_uaAIy.mjs} +2509 -1138
- package/package.json +7 -6
- package/dist/src-BzVS8KXQ.mjs +0 -459
- package/dist/src-CwhDFSWk.cjs +0 -482
package/dist/src-CwhDFSWk.cjs
DELETED
|
@@ -1,482 +0,0 @@
|
|
|
1
|
-
const require_test_command = require("./test-command-BbjJIX7j.cjs");
|
|
2
|
-
let node_fs_promises = require("node:fs/promises");
|
|
3
|
-
//#region src/verify-command.ts
|
|
4
|
-
/**
|
|
5
|
-
* 런타임 모듈을 못 불러 fallback 의존성이 쓰일 때 던진다.
|
|
6
|
-
*
|
|
7
|
-
* 타입을 따로 두는 이유는 이 실패가 **카세트 손상과 구분돼야** 하기 때문이다. 그냥 던지면
|
|
8
|
-
* `CASSETTE_READ_FAILED` 로 잡혀 "카세트 파일이 손상되지 않았는지 확인하세요" 가 나가고,
|
|
9
|
-
* 사용자는 멀쩡한 파일을 들여다보게 된다. 고칠 곳은 설치다.
|
|
10
|
-
*/
|
|
11
|
-
var VerifyRuntimeUnavailableError = class extends Error {
|
|
12
|
-
constructor() {
|
|
13
|
-
super("verify 실행에 필요한 모듈을 로드하지 못했습니다.");
|
|
14
|
-
this.name = "VerifyRuntimeUnavailableError";
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
const dictionary = {
|
|
18
|
-
VERIFY_RUNTIME_UNAVAILABLE: {
|
|
19
|
-
message: "verify 에 필요한 @mcpeak/record 를 로드하지 못했습니다.",
|
|
20
|
-
hint: "의존성을 설치한 뒤 다시 실행하세요. 카세트 파일의 문제가 아닙니다."
|
|
21
|
-
},
|
|
22
|
-
CASSETTE_NOT_FOUND: {
|
|
23
|
-
message: "카세트 파일이 없습니다.",
|
|
24
|
-
hint: "`mcpeak generate --cassette <path> --record` 로 먼저 녹화하세요."
|
|
25
|
-
},
|
|
26
|
-
CASSETTE_READ_FAILED: {
|
|
27
|
-
message: "카세트를 읽지 못했습니다.",
|
|
28
|
-
hint: "카세트 파일이 손상되지 않았는지 확인하세요."
|
|
29
|
-
},
|
|
30
|
-
SERVER_CONNECT_FAILED: {
|
|
31
|
-
message: "MCP 서버에 연결하지 못했습니다.",
|
|
32
|
-
hint: "--command 와 --arg 가 카세트를 녹화할 때 쓴 서버와 같은지 확인하세요."
|
|
33
|
-
},
|
|
34
|
-
CASSETTE_DRIFTED: {
|
|
35
|
-
message: "카세트가 실서버 응답과 다릅니다.",
|
|
36
|
-
hint: "서버가 바뀐 것이라면 `--record` 로 카세트를 다시 만드세요."
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
var VerifyCommandError = class extends Error {
|
|
40
|
-
failure;
|
|
41
|
-
constructor(failure) {
|
|
42
|
-
super(failure.message);
|
|
43
|
-
this.failure = failure;
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
const usage = (message) => {
|
|
47
|
-
throw new VerifyCommandError({
|
|
48
|
-
code: "CLI_USAGE",
|
|
49
|
-
message,
|
|
50
|
-
hint: require_test_command.VERIFY_USAGE_HINT
|
|
51
|
-
});
|
|
52
|
-
};
|
|
53
|
-
/**
|
|
54
|
-
* 값을 하나 읽는다. `--opt value` 와 `--opt=value` 를 모두 받는다.
|
|
55
|
-
*
|
|
56
|
-
* `--arg` 만 값의 모양을 검사하지 않는다. 서버 인자는 대부분 플래그 모양이고(`-y`, `--with`,
|
|
57
|
-
* `--db-path`) 빈 문자열도 정상적인 인자다. `generate` 와 `test` 가 이미 `--arg` 를 그렇게
|
|
58
|
-
* 받으므로, 여기서 거절하면 **`generate --record` 로 녹화한 바로 그 서버를 `verify` 로는
|
|
59
|
-
* 부를 수 없다.** 같은 명령줄을 못 받는 verify 는 그 카세트를 확인할 방법이 아예 없다.
|
|
60
|
-
*
|
|
61
|
-
* `--command` 는 그대로 검사한다. 실행 파일 자리에 들어온 플래그는 값을 빠뜨린 오타다.
|
|
62
|
-
*/
|
|
63
|
-
function optionValue(argv, index, name) {
|
|
64
|
-
const anyShape = name === "--arg";
|
|
65
|
-
const token = argv[index] ?? "";
|
|
66
|
-
if (token.startsWith(`${name}=`)) {
|
|
67
|
-
const value = token.slice(name.length + 1);
|
|
68
|
-
if (value === "" && !anyShape) usage(`${name} 옵션 값이 필요합니다.`);
|
|
69
|
-
return [value, index];
|
|
70
|
-
}
|
|
71
|
-
const next = argv[index + 1];
|
|
72
|
-
if (next === void 0 || !anyShape && (next === "" || next.startsWith("--"))) usage(`${name} 옵션 값이 필요합니다.`);
|
|
73
|
-
return [next, index + 1];
|
|
74
|
-
}
|
|
75
|
-
function parseVerifyCommand(argv) {
|
|
76
|
-
let cassettePath;
|
|
77
|
-
let command;
|
|
78
|
-
const args = [];
|
|
79
|
-
for (let index = 0; index < argv.length; index++) {
|
|
80
|
-
const token = argv[index] ?? "";
|
|
81
|
-
const [name] = token.startsWith("--") ? token.split("=", 1) : [token];
|
|
82
|
-
if (name === "--command") {
|
|
83
|
-
if (command !== void 0) usage("--command 는 한 번만 사용할 수 있습니다.");
|
|
84
|
-
[command, index] = optionValue(argv, index, "--command");
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
if (name === "--arg") {
|
|
88
|
-
let value;
|
|
89
|
-
[value, index] = optionValue(argv, index, "--arg");
|
|
90
|
-
args.push(value);
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
if (name === "--record") usage("verify 는 카세트를 고치지 않습니다. 다시 녹화하려면 generate --record 를 쓰세요.");
|
|
94
|
-
if (token.startsWith("--")) usage(`알 수 없는 옵션입니다: ${token}`);
|
|
95
|
-
if (cassettePath !== void 0) usage(`카세트는 하나만 받습니다: ${token}`);
|
|
96
|
-
cassettePath = token;
|
|
97
|
-
}
|
|
98
|
-
if (cassettePath === void 0 || cassettePath === "") usage("카세트 JSON 경로가 필요합니다.");
|
|
99
|
-
if (command === void 0) usage("--command 에 MCP 서버 실행 명령이 필요합니다.");
|
|
100
|
-
return Object.freeze({
|
|
101
|
-
cassettePath,
|
|
102
|
-
command,
|
|
103
|
-
args: Object.freeze([...args])
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
const format = (failure) => `오류 [${failure.code}]: ${failure.message}\n해결: ${failure.hint}\n`;
|
|
107
|
-
const writeFailure = (dependencies, failure) => {
|
|
108
|
-
dependencies.writeStderr(format(failure));
|
|
109
|
-
return 1;
|
|
110
|
-
};
|
|
111
|
-
/**
|
|
112
|
-
* 결과 요약. 숫자만 찍고 끝내지 않는다 — 무엇이 어떻게 다른지가 이 명령의 산출물이다.
|
|
113
|
-
* `record` 가 만든 문장을 그대로 싣는다. 여기서 다시 쓰면 두 곳이 갈린다.
|
|
114
|
-
*/
|
|
115
|
-
function formatVerifyResult(result, cassettePath) {
|
|
116
|
-
const lines = [];
|
|
117
|
-
const total = result.matched + result.mismatched.length + result.failed.length + result.skipped.length;
|
|
118
|
-
for (const item of [
|
|
119
|
-
...result.mismatched,
|
|
120
|
-
...result.failed,
|
|
121
|
-
...result.skipped
|
|
122
|
-
]) lines.push(item.message, "");
|
|
123
|
-
lines.push(`카세트: ${cassettePath}`);
|
|
124
|
-
lines.push(` 일치 ${result.matched} · 불일치 ${result.mismatched.length} · 실패 ${result.failed.length} · 확인불가 ${result.skipped.length} (총 ${total})`);
|
|
125
|
-
if (result.skipped.length > 0) lines.push(" 확인불가는 args 에 마스킹된 비밀값이 있어 실서버에 그대로 보낼 수 없는 요청입니다.");
|
|
126
|
-
if (result.mismatched.length === 0 && result.failed.length === 0) lines.push(result.skipped.length === 0 ? " 카세트가 실서버와 일치합니다." : ` 확인한 ${result.matched}개는 실서버와 일치합니다. ${result.skipped.length}개는 확인하지 못했습니다.`);
|
|
127
|
-
return `${lines.join("\n")}\n`;
|
|
128
|
-
}
|
|
129
|
-
async function runVerifyCommand(argv, dependencies) {
|
|
130
|
-
let input;
|
|
131
|
-
try {
|
|
132
|
-
input = parseVerifyCommand(argv);
|
|
133
|
-
} catch (error) {
|
|
134
|
-
if (error instanceof VerifyCommandError) return writeFailure(dependencies, error.failure);
|
|
135
|
-
throw error;
|
|
136
|
-
}
|
|
137
|
-
let cassette;
|
|
138
|
-
try {
|
|
139
|
-
cassette = await dependencies.loadCassette(input.cassettePath);
|
|
140
|
-
} catch (error) {
|
|
141
|
-
const code = error instanceof VerifyRuntimeUnavailableError ? "VERIFY_RUNTIME_UNAVAILABLE" : "CASSETTE_READ_FAILED";
|
|
142
|
-
return writeFailure(dependencies, {
|
|
143
|
-
code,
|
|
144
|
-
...dictionary[code]
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
if (cassette === null) return writeFailure(dependencies, {
|
|
148
|
-
code: "CASSETTE_NOT_FOUND",
|
|
149
|
-
...dictionary.CASSETTE_NOT_FOUND
|
|
150
|
-
});
|
|
151
|
-
let client;
|
|
152
|
-
try {
|
|
153
|
-
client = await dependencies.connect({
|
|
154
|
-
command: input.command,
|
|
155
|
-
args: input.args
|
|
156
|
-
});
|
|
157
|
-
} catch {
|
|
158
|
-
return writeFailure(dependencies, {
|
|
159
|
-
code: "SERVER_CONNECT_FAILED",
|
|
160
|
-
...dictionary.SERVER_CONNECT_FAILED
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
let result;
|
|
164
|
-
try {
|
|
165
|
-
result = await dependencies.verifyCassette(client, cassette, { cassettePath: input.cassettePath });
|
|
166
|
-
} finally {
|
|
167
|
-
await client.close().catch(() => {});
|
|
168
|
-
}
|
|
169
|
-
dependencies.writeStdout(formatVerifyResult(result, input.cassettePath));
|
|
170
|
-
if (result.mismatched.length === 0 && result.failed.length === 0) return 0;
|
|
171
|
-
dependencies.writeStderr(format({
|
|
172
|
-
code: "CASSETTE_DRIFTED",
|
|
173
|
-
...dictionary.CASSETTE_DRIFTED
|
|
174
|
-
}));
|
|
175
|
-
return 1;
|
|
176
|
-
}
|
|
177
|
-
//#endregion
|
|
178
|
-
//#region src/index.ts
|
|
179
|
-
const COMMANDS = [
|
|
180
|
-
"test",
|
|
181
|
-
"generate",
|
|
182
|
-
"repair",
|
|
183
|
-
"record",
|
|
184
|
-
"replay",
|
|
185
|
-
"verify",
|
|
186
|
-
"mock"
|
|
187
|
-
];
|
|
188
|
-
const unavailableDependencies = {
|
|
189
|
-
readFile: async () => {
|
|
190
|
-
throw new Error("runtime dependencies unavailable");
|
|
191
|
-
},
|
|
192
|
-
validateSuite: () => {
|
|
193
|
-
throw new Error("runtime dependencies unavailable");
|
|
194
|
-
},
|
|
195
|
-
connect: async () => {
|
|
196
|
-
throw new Error("runtime dependencies unavailable");
|
|
197
|
-
},
|
|
198
|
-
startRunner: () => {
|
|
199
|
-
throw new Error("runtime dependencies unavailable");
|
|
200
|
-
},
|
|
201
|
-
finalize: async () => {
|
|
202
|
-
throw new Error("runtime dependencies unavailable");
|
|
203
|
-
},
|
|
204
|
-
renderReport: () => {
|
|
205
|
-
throw new Error("runtime dependencies unavailable");
|
|
206
|
-
},
|
|
207
|
-
renderJUnit: () => {
|
|
208
|
-
throw new Error("runtime dependencies unavailable");
|
|
209
|
-
},
|
|
210
|
-
writeFile: async () => {
|
|
211
|
-
throw new Error("runtime dependencies unavailable");
|
|
212
|
-
},
|
|
213
|
-
colorEnabled: false,
|
|
214
|
-
writeStdout: (text) => process.stdout.write(text),
|
|
215
|
-
writeStderr: (text) => process.stderr.write(text)
|
|
216
|
-
};
|
|
217
|
-
const unavailableRuntimeDependencies = {
|
|
218
|
-
...unavailableDependencies,
|
|
219
|
-
readFile: node_fs_promises.readFile
|
|
220
|
-
};
|
|
221
|
-
/**
|
|
222
|
-
* `repair` 실행 의존성. 함수로 빼 둔 이유는 **주입 자체를 테스트가 단언할 수 있게** 하기
|
|
223
|
-
* 위해서다. 분기 안에 리터럴로 두면 `reviewIO` 를 빠뜨려도 아무 테스트도 안 깨진다.
|
|
224
|
-
* 실제로 그렇게 한 번 빠뜨렸다(T10 보고서).
|
|
225
|
-
*
|
|
226
|
-
* 대화형 판정은 `generate` 와 같은 기준이다. 같은 `nodeReviewIO()` 를 쓰고, 그 구현이
|
|
227
|
-
* stdin·stdout 이 둘 다 TTY 일 때만 `interactive` 를 참으로 만든다.
|
|
228
|
-
*/
|
|
229
|
-
function nodeRepairDependencies(generate) {
|
|
230
|
-
return {
|
|
231
|
-
readFile: (path) => (0, node_fs_promises.readFile)(path, "utf8"),
|
|
232
|
-
writeStdout: (text) => void process.stdout.write(text),
|
|
233
|
-
writeStderr: (text) => void process.stderr.write(text),
|
|
234
|
-
reviewIO: require_test_command.nodeReviewIO(),
|
|
235
|
-
diagnosis: {
|
|
236
|
-
prepare: generate.prepareDiagnosisRequest,
|
|
237
|
-
dispatch: generate.dispatchDiagnosisRequest,
|
|
238
|
-
providers: {
|
|
239
|
-
codex: (model) => generate.createCodexProvider({ model }),
|
|
240
|
-
claude: (model) => generate.createClaudeProvider({ model })
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
|
-
* replay 는 `connect` 를 쓰지 않는다. 대신 카세트 로더가 필요하다. 런타임 의존성을 못 불러도
|
|
247
|
-
* 사용 오류는 정상적으로 내야 하므로, 실제로 쓰이기 전에 끝나는 경로를 위해 자리만 채운다.
|
|
248
|
-
*
|
|
249
|
-
* **테스트가 배선을 직접 단언할 수 있도록 내보낸다.** 여기서 평범한 Error 로 되돌아가면
|
|
250
|
-
* 사용자는 "이슈를 보고하세요" 를 보게 되는데, 모듈 모킹으로는 이 경로를 재현할 수 없다 —
|
|
251
|
-
* `record` 와 `runner` 가 `generate-command` 를 통해 정적 import 체인에 있어서, 그것을
|
|
252
|
-
* 모킹하면 `index.ts` 로드 자체가 깨진다. `nodeRepairDependencies` 를 함수로 뺀 것과 같은
|
|
253
|
-
* 이유다(주입을 빠뜨려도 아무 테스트가 안 깨지는 상황을 막는다).
|
|
254
|
-
*/
|
|
255
|
-
const unavailableReplayDependencies = {
|
|
256
|
-
...unavailableRuntimeDependencies,
|
|
257
|
-
/**
|
|
258
|
-
* 런타임에서 오는 의존성은 전용 오류 타입을 던진다. 평범한 Error 로 두면 `validateSuite`
|
|
259
|
-
* 자리에서 `CLI_INTERNAL_ERROR` 로 잡혀 "이슈를 보고하세요" 가 나가고, 사용자는 자기
|
|
260
|
-
* 설치 문제로 버그 리포트를 쓰게 된다. 실제로 가장 먼저 걸리는 것이 `validateSuite` 다.
|
|
261
|
-
*
|
|
262
|
-
* `unavailableRuntimeDependencies` 자체는 `test` 경로와 공유하므로 여기서만 덮는다.
|
|
263
|
-
*/
|
|
264
|
-
validateSuite: () => {
|
|
265
|
-
throw new require_test_command.ReplayRuntimeUnavailableError();
|
|
266
|
-
},
|
|
267
|
-
loadCassette: async () => {
|
|
268
|
-
throw new require_test_command.ReplayRuntimeUnavailableError();
|
|
269
|
-
},
|
|
270
|
-
startRunner: () => {
|
|
271
|
-
throw new require_test_command.ReplayRuntimeUnavailableError();
|
|
272
|
-
},
|
|
273
|
-
finalize: async () => {
|
|
274
|
-
throw new require_test_command.ReplayRuntimeUnavailableError();
|
|
275
|
-
},
|
|
276
|
-
renderReport: () => {
|
|
277
|
-
throw new require_test_command.ReplayRuntimeUnavailableError();
|
|
278
|
-
}
|
|
279
|
-
};
|
|
280
|
-
/**
|
|
281
|
-
* verify 도 런타임을 못 불러도 사용 오류는 정상적으로 내야 한다. 파싱은 의존성 없이 끝나므로
|
|
282
|
-
* `--command` 누락 같은 오류는 여기까지 오지 않는다.
|
|
283
|
-
*/
|
|
284
|
-
const unavailableVerifyDependencies = {
|
|
285
|
-
loadCassette: async () => {
|
|
286
|
-
throw new VerifyRuntimeUnavailableError();
|
|
287
|
-
},
|
|
288
|
-
connect: async () => {
|
|
289
|
-
throw new VerifyRuntimeUnavailableError();
|
|
290
|
-
},
|
|
291
|
-
verifyCassette: async () => {
|
|
292
|
-
throw new VerifyRuntimeUnavailableError();
|
|
293
|
-
},
|
|
294
|
-
writeStdout: (text) => void process.stdout.write(text),
|
|
295
|
-
writeStderr: (text) => void process.stderr.write(text)
|
|
296
|
-
};
|
|
297
|
-
async function run(argv) {
|
|
298
|
-
if (argv.length === 0 || argv.length === 1 && [
|
|
299
|
-
"--help",
|
|
300
|
-
"-h",
|
|
301
|
-
"help"
|
|
302
|
-
].includes(argv[0] ?? "")) {
|
|
303
|
-
process.stdout.write(require_test_command.GLOBAL_HELP);
|
|
304
|
-
return 0;
|
|
305
|
-
}
|
|
306
|
-
if (argv.length === 2) {
|
|
307
|
-
const command = argv[0] === "help" ? argv[1] : argv[1] === "--help" ? argv[0] : void 0;
|
|
308
|
-
if (command === "test" || command === "generate" || command === "repair" || command === "replay" || command === "verify") {
|
|
309
|
-
process.stdout.write(require_test_command.commandHelp(command));
|
|
310
|
-
return 0;
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
if (argv.length === 1 && argv[0] === "--version") {
|
|
314
|
-
process.stdout.write(`mcpeak ${require_test_command.version}\n`);
|
|
315
|
-
return 0;
|
|
316
|
-
}
|
|
317
|
-
if (argv[0] === "generate") {
|
|
318
|
-
let core;
|
|
319
|
-
let runner;
|
|
320
|
-
let generate;
|
|
321
|
-
try {
|
|
322
|
-
[core, runner, generate] = await Promise.all([
|
|
323
|
-
import("@mcpeak/core"),
|
|
324
|
-
import("@mcpeak/runner"),
|
|
325
|
-
import("@mcpeak/generate")
|
|
326
|
-
]);
|
|
327
|
-
} catch {
|
|
328
|
-
return require_test_command.runGenerateCommand(argv, {
|
|
329
|
-
...require_test_command.nodeGenerateDependencies(),
|
|
330
|
-
connect: unavailableDependencies.connect,
|
|
331
|
-
createBaselineSuite: unavailableDependencies.validateSuite,
|
|
332
|
-
createAuthoringSession: unavailableDependencies.validateSuite,
|
|
333
|
-
finalizeAuthoringDraft: unavailableDependencies.validateSuite,
|
|
334
|
-
getAuthoringExecutionSuite: unavailableDependencies.validateSuite,
|
|
335
|
-
validateSuite: unavailableDependencies.validateSuite
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
return require_test_command.runGenerateCommand(argv, {
|
|
339
|
-
...require_test_command.nodeGenerateDependencies(),
|
|
340
|
-
connect: core.connectStdio,
|
|
341
|
-
createBaselineSuite: generate.createBaselineSuite,
|
|
342
|
-
createAuthoringSession: generate.createAuthoringSession,
|
|
343
|
-
finalizeAuthoringDraft: generate.finalizeAuthoringDraft,
|
|
344
|
-
getAuthoringExecutionSuite: generate.getAuthoringExecutionSuite,
|
|
345
|
-
validateSuite: runner.validateMcpSuite,
|
|
346
|
-
reviewIO: require_test_command.nodeReviewIO(),
|
|
347
|
-
providers: {
|
|
348
|
-
codex: (model) => generate.createCodexAuthoringProvider({ model }),
|
|
349
|
-
claude: (model) => generate.createClaudeAuthoringProvider({ model })
|
|
350
|
-
},
|
|
351
|
-
prepareAuthoringRequest: generate.prepareAuthoringRequest,
|
|
352
|
-
dispatchAuthoringRequest: generate.dispatchAuthoringRequest,
|
|
353
|
-
createAuthoringDiff: generate.createAuthoringDiff,
|
|
354
|
-
applyAuthoringChanges: generate.applyAuthoringChanges,
|
|
355
|
-
reviewLocalAuthoringCandidate: generate.reviewLocalAuthoringCandidate,
|
|
356
|
-
computeCoverage: generate.computeCoverage,
|
|
357
|
-
preparePreFillRequest: generate.preparePreFillRequest,
|
|
358
|
-
previewPreFillRequest: generate.previewPreFillRequest,
|
|
359
|
-
dispatchPreFillRequest: generate.dispatchPreFillRequest,
|
|
360
|
-
preFillProviders: {
|
|
361
|
-
codex: (model) => generate.createCodexProvider({ model }),
|
|
362
|
-
claude: (model) => generate.createClaudeProvider({ model })
|
|
363
|
-
},
|
|
364
|
-
prepareRejectionDiagnosisRequests: generate.prepareRejectionDiagnosisRequests,
|
|
365
|
-
dispatchRejectionDiagnosis: generate.dispatchRejectionDiagnosis,
|
|
366
|
-
rejectionProviders: {
|
|
367
|
-
codex: (model) => generate.createCodexProvider({ model }),
|
|
368
|
-
claude: (model) => generate.createClaudeProvider({ model })
|
|
369
|
-
},
|
|
370
|
-
GenerateTestsError: generate.GenerateTestsError
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
if (argv[0] === "repair") {
|
|
374
|
-
/**
|
|
375
|
-
* `generate` 분기와 같은 모양으로 동적 import 한다. `test` 경로는 이 분기를 지나지 않으므로
|
|
376
|
-
* 여전히 `core` 와 `runner` 만 로드한다. 계획서 §8 위험표 첫 줄.
|
|
377
|
-
*/
|
|
378
|
-
let generate;
|
|
379
|
-
try {
|
|
380
|
-
generate = await import("@mcpeak/generate");
|
|
381
|
-
} catch {
|
|
382
|
-
process.stderr.write("오류 [REPAIR_RUNTIME_UNAVAILABLE]: 진단에 필요한 @mcpeak/generate 를 로드하지 못했습니다.\n해결: 의존성을 설치한 뒤 다시 실행하세요.\n");
|
|
383
|
-
return 1;
|
|
384
|
-
}
|
|
385
|
-
const dependencies = nodeRepairDependencies(generate);
|
|
386
|
-
try {
|
|
387
|
-
return await require_test_command.runRepairCommand(argv, dependencies);
|
|
388
|
-
} finally {
|
|
389
|
-
dependencies.reviewIO?.close?.();
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
if (argv[0] === "replay") {
|
|
393
|
-
let runner;
|
|
394
|
-
let record;
|
|
395
|
-
try {
|
|
396
|
-
[runner, record] = await Promise.all([import("@mcpeak/runner"), import("@mcpeak/record")]);
|
|
397
|
-
} catch {
|
|
398
|
-
return require_test_command.runReplayCommand(argv.slice(1), unavailableReplayDependencies);
|
|
399
|
-
}
|
|
400
|
-
return require_test_command.runReplayCommand(argv.slice(1), {
|
|
401
|
-
readFile: node_fs_promises.readFile,
|
|
402
|
-
validateSuite: runner.validateMcpSuite,
|
|
403
|
-
loadCassette: record.loadCassette,
|
|
404
|
-
startRunner: runner.runSuite,
|
|
405
|
-
finalize: runner.finalizeRunnerExecution,
|
|
406
|
-
renderReport: runner.renderReport,
|
|
407
|
-
colorEnabled: process.stdout.isTTY === true && process.env.NO_COLOR === void 0,
|
|
408
|
-
writeStdout: (text) => process.stdout.write(text),
|
|
409
|
-
writeStderr: (text) => process.stderr.write(text)
|
|
410
|
-
});
|
|
411
|
-
}
|
|
412
|
-
if (argv[0] === "verify") {
|
|
413
|
-
let core;
|
|
414
|
-
let record;
|
|
415
|
-
try {
|
|
416
|
-
[core, record] = await Promise.all([import("@mcpeak/core"), import("@mcpeak/record")]);
|
|
417
|
-
} catch {
|
|
418
|
-
return runVerifyCommand(argv.slice(1), unavailableVerifyDependencies);
|
|
419
|
-
}
|
|
420
|
-
return runVerifyCommand(argv.slice(1), {
|
|
421
|
-
loadCassette: record.loadCassette,
|
|
422
|
-
connect: (options) => core.connect({
|
|
423
|
-
command: options.command,
|
|
424
|
-
args: options.args
|
|
425
|
-
}),
|
|
426
|
-
verifyCassette: record.verifyCassette,
|
|
427
|
-
writeStdout: (text) => void process.stdout.write(text),
|
|
428
|
-
writeStderr: (text) => void process.stderr.write(text)
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
if (argv[0] !== "test") return require_test_command.runCli(argv, unavailableDependencies);
|
|
432
|
-
try {
|
|
433
|
-
if (!require_test_command.parseTestCommand(argv.slice(1)).suitePath.toLowerCase().endsWith(".json")) return require_test_command.runCli(argv, unavailableDependencies);
|
|
434
|
-
} catch {
|
|
435
|
-
return require_test_command.runCli(argv, unavailableDependencies);
|
|
436
|
-
}
|
|
437
|
-
let core;
|
|
438
|
-
let runner;
|
|
439
|
-
try {
|
|
440
|
-
[core, runner] = await Promise.all([import("@mcpeak/core"), import("@mcpeak/runner")]);
|
|
441
|
-
} catch {
|
|
442
|
-
return require_test_command.runCli(argv, unavailableRuntimeDependencies);
|
|
443
|
-
}
|
|
444
|
-
return require_test_command.runCli(argv, {
|
|
445
|
-
readFile: node_fs_promises.readFile,
|
|
446
|
-
validateSuite: runner.validateMcpSuite,
|
|
447
|
-
connect: core.connectStdio,
|
|
448
|
-
startRunner: runner.runSuite,
|
|
449
|
-
finalize: runner.finalizeRunnerExecution,
|
|
450
|
-
renderReport: runner.renderReport,
|
|
451
|
-
renderJUnit: runner.renderJUnit,
|
|
452
|
-
writeFile: (path, text) => (0, node_fs_promises.writeFile)(path, text, "utf8"),
|
|
453
|
-
colorEnabled: process.stdout.isTTY === true && process.env.NO_COLOR === void 0,
|
|
454
|
-
writeStdout: (text) => process.stdout.write(text),
|
|
455
|
-
writeStderr: (text) => process.stderr.write(text)
|
|
456
|
-
});
|
|
457
|
-
}
|
|
458
|
-
//#endregion
|
|
459
|
-
Object.defineProperty(exports, "COMMANDS", {
|
|
460
|
-
enumerable: true,
|
|
461
|
-
get: function() {
|
|
462
|
-
return COMMANDS;
|
|
463
|
-
}
|
|
464
|
-
});
|
|
465
|
-
Object.defineProperty(exports, "nodeRepairDependencies", {
|
|
466
|
-
enumerable: true,
|
|
467
|
-
get: function() {
|
|
468
|
-
return nodeRepairDependencies;
|
|
469
|
-
}
|
|
470
|
-
});
|
|
471
|
-
Object.defineProperty(exports, "run", {
|
|
472
|
-
enumerable: true,
|
|
473
|
-
get: function() {
|
|
474
|
-
return run;
|
|
475
|
-
}
|
|
476
|
-
});
|
|
477
|
-
Object.defineProperty(exports, "unavailableReplayDependencies", {
|
|
478
|
-
enumerable: true,
|
|
479
|
-
get: function() {
|
|
480
|
-
return unavailableReplayDependencies;
|
|
481
|
-
}
|
|
482
|
-
});
|