@mcpeak/cli 0.12.0 → 0.14.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/README.ko.md ADDED
@@ -0,0 +1,120 @@
1
+ [English](./README.md) · **한국어**
2
+
3
+ # MCPeak CLI
4
+
5
+ `mcpeak test`는 JSON 테스트 명세로 로컬 stdio MCP 서버를 직접 시작하고 종료합니다.
6
+
7
+ 처음 실행하거나 사용 가능한 명령을 확인할 때는 전체 도움말을 표시합니다. 인자 없이 실행해도
8
+ 같은 도움말을 stdout에 쓰고 종료 코드 0을 반환합니다.
9
+
10
+ ```bash
11
+ mcpeak --help
12
+ mcpeak -h
13
+ mcpeak help
14
+ mcpeak --version
15
+ ```
16
+
17
+ `mcpeak help test`와 `mcpeak test --help`는 `test` 도움말을, `mcpeak help generate`와
18
+ `mcpeak generate --help`는 `generate` 도움말을 표시합니다. 도움말과 버전은 오류가 아니므로
19
+ stderr가 아니라 stdout으로 출력하고 종료 코드 0을 반환합니다.
20
+
21
+ ```bash
22
+ mcpeak test packages/cli/tests/fixtures/weather-suite.json \
23
+ --command node \
24
+ --arg examples/weather-server/server.mjs
25
+ ```
26
+
27
+ 문법은 `mcpeak test <suite.json> --command <executable> [--arg <value> ...] [--json] [--junit <path>] [--stderr-lines <N>] [--record-session <path> | --session <path>]`입니다. 위 예시의 command와 arg는 `node examples/weather-server/server.mjs`로 실행됩니다. `--arg`는 반복할 수 있고, 하이픈으로 시작하는 값은 `--arg=-m`, 빈 값은 `--arg=`로 전달합니다.
28
+
29
+ stdout에는 보고서만 나갑니다. 기본은 사람이 읽는 보고서이고, `--json`을 주면 `RunnerReport` JSON이 나갑니다. CLI 오류와 서버 프로세스 진단은 stderr로만 나가므로 `--json > report.json`이 깨지지 않습니다. 모든 테스트가 통과하면 종료 코드 0을, failed 또는 aborted report와 입력, 연결, 종료 오류에는 1을 반환합니다.
30
+
31
+ `--junit <path>`는 CI 도구가 읽는 JUnit XML 리포트를 그 경로에 씁니다.
32
+
33
+ ```bash
34
+ mcpeak test weather.json \
35
+ --command node --arg examples/weather-server/server.mjs \
36
+ --junit reports/junit.xml
37
+ ```
38
+
39
+ stdout은 그대로 두고 파일만 더하므로 `--json`과 함께 쓸 수 있습니다. 둘의 역할이 다릅니다 — `--json`은 stdout 형식을, `--junit`은 별도 산출물을 정합니다. 경로의 디렉터리는 미리 있어야 하며, 파일을 쓰지 못하면 모든 테스트가 통과했더라도 `JUNIT_WRITE_FAILED`와 함께 종료 코드 1을 냅니다. 리포트 없이 CI가 초록이 되지 않게 하려는 것입니다. XML은 stdout보다 먼저 쓰므로 stdout이 파이프에서 끊겨도 파일은 남습니다.
40
+
41
+ XML을 만드는 단계에서 실패하면 `CLI_INTERNAL_ERROR`와 함께 종료 코드 1을 냅니다. 이때는 파일 쓰기에 도달하기 전이므로 **파일을 만들지도, 기존 파일을 덮어쓰지도 않습니다.** 직전 실행의 리포트가 그대로 남으므로, CI에서 이 경로를 읽는 도구가 낡은 리포트를 최신 결과로 오해할 수 있습니다. 종료 코드로 판정하세요.
42
+
43
+ `RunnerReport`에는 시간 정보가 없어 모든 `time` 속성은 `0`입니다. "0초 걸렸다"가 아니라 "시간 정보를 갖고 있지 않다"는 뜻입니다. 근거는 [ADR-0016](../../docs/adr/0016-junit-time-속성-고정.md), 플래그 설계는 [ADR-0019](../../docs/adr/0019-junit-리포터-cli-노출-방식.md)에 있습니다.
44
+
45
+ `--record-session <path>`는 서버가 `globalThis.fetch`로 호출한 외부 HTTP 응답을 녹화하고,
46
+ `--session <path>`는 그 녹화본을 재생합니다. 서버는 재생 때도 실제로 실행됩니다. `node:http`와
47
+ `node:https` 계층 호출은 범위 밖이라 실제 네트워크로 나갈 수 있으며, CLI는 녹화 0건이나 재생
48
+ 0건처럼 범위 밖 호출이 의심되는 실행을 stderr 알림으로 드러냅니다.
49
+
50
+ `--stderr-lines <N>`은 실패했거나 서버가 비정상 종료·중단했을 때, 진단 내용이 있으면 stderr에 붙는 서버 프로세스 진단 블록의 stderr 표시 줄 수입니다. 기본값은 20이고, `0`을 주면 블록을 완전히 끕니다(그때 출력 바이트는 이 기능이 없던 때와 같습니다). 블록에는 종료 코드와 시그널, 서버가 남긴 stderr의 마지막 N줄이 담기며 잘린 사실은 헤더에 적힙니다. 서버가 정상 종료했고 stderr도 비어 있으면 보여줄 근거가 없으므로 블록을 쓰지 않습니다.
51
+
52
+ ### 승인 지문 대조
53
+
54
+ `test`는 실행할 명세의 승인 지문을 계산해 파일에 적힌 `approval.fingerprint`와 대조하고, 그 결과를 보고서에 적습니다. **판정은 바꾸지 않습니다.** 종료 코드는 케이스 결과로만 정해지므로 지문이 달라도 전부 통과하면 0입니다. 명세를 고치는 것은 정상 작업이고, 그때마다 테스트가 막히면 사용자는 확인 절차를 우회하는 방법부터 찾게 됩니다.
55
+
56
+ 표시 여부는 다음과 같습니다. 매 실행 한 줄을 무조건 찍으면 손으로 명세를 쓰는 사용자에게는 영구적인 소음이고, 그러면 정작 필요할 때 그 줄을 읽지 않습니다.
57
+
58
+ | 지문 상태 | 전부 통과 | 실패·타임아웃 등이 있음 |
59
+ |---|---|---|
60
+ | 일치 | 침묵 | 표시 |
61
+ | 불일치 | **표시** | 표시 |
62
+ | 없음(미고정) | 침묵 | 표시 |
63
+
64
+ 전부 통과인데 불일치일 때만 예외를 두는 이유는 승인받지 않은 명세로 초록불이 뜬 상태이기 때문입니다. 그 사실은 실패보다 오히려 조용히 지나가기 쉽습니다.
65
+
66
+ 현재 명세에서 계산한 지문과 저장된 `approval.fingerprint`가 불일치하면 전부 통과했는지 실패가
67
+ 있는지에 맞춰 상황을 구분해 알립니다. 지문 두 개만으로는 구체적인 변경 내용을 복원할 수 없으므로
68
+ 버전 관리에서 명세를 비교하도록 안내하고, 의도한 변경이면 같은 설정의 `mcpeak generate`에
69
+ `--force`를 붙여 다시 생성·승인하도록 안내합니다.
70
+
71
+ 명세 줄은 보고서 본문 뒤에 빈 줄 하나를 두고 stdout으로 나갑니다. `--json`에는 위 억제 규칙을 적용하지 않고 `spec` 키를 항상 넣습니다(`approval`은 `matched` · `mismatched` · `absent` 중 하나, `fingerprint`는 실행 시점 계산값, `approvedFingerprint`는 파일에 적힌 값이며 `absent`면 키가 없습니다). 기계가 읽는 출력에서 키가 조건부로 사라지면 소비자가 분기를 하나 더 써야 합니다. 기존 보고서 키는 그대로이므로 기존 소비자는 깨지지 않습니다.
72
+
73
+ 지문이 없는 명세도 정상입니다. 손으로 쓴 명세와 이 기능 이전에 만든 명세가 여기에 해당하며 실패로 취급하지 않습니다.
74
+
75
+ 현재는 UTF-8 JSON 단일 명세와 stdio 서버만 지원합니다. shell 문법, 여러 명세, TypeScript 모듈 명세는 지원하지 않습니다. `record`, `mock` 명령은 아직 구현되지 않았습니다.
76
+
77
+ ## generate
78
+
79
+ `mcpeak generate`는 서버의 `tools/list` 결과에서 결정론적 baseline suite를 만듭니다.
80
+
81
+ ```bash
82
+ mcpeak generate \
83
+ --suite-id weather \
84
+ --name "Weather server" \
85
+ --out weather.json \
86
+ --command node \
87
+ --arg examples/weather-server/server.mjs \
88
+ --baseline-only
89
+ ```
90
+
91
+ 문법은 다음과 같습니다.
92
+
93
+ ```text
94
+ mcpeak generate --suite-id <id> --name <name> --out <suite.json> --command <executable> [--arg <value> ...] [--baseline-only] [--provider <codex|claude>] [--model <model>]
95
+ ```
96
+
97
+ `--baseline-only`는 AI를 호출하지 않는 명시적 비대화형 승인입니다. 생성기는 기존 출력 파일을 덮어쓰지 않으며, 같은 디렉터리의 임시 파일을 다시 읽어 suite와 fingerprint를 검증한 뒤 원자적으로 저장합니다. weather-server의 baseline은 `get_weather`에 `{ "city": "example" }`를 사용하므로, 이어서 `mcpeak test`를 실행하면 get_weather가 실패하고 add는 통과합니다. 이는 baseline이 스키마에서 얻은 출발점일 뿐 실행 성공을 보장하지 않는다는 신호입니다.
98
+
99
+ TTY에서 `--baseline-only`를 빼면 대화형 검토가 시작됩니다. Codex 또는 Claude provider와 model을 선택할 수 있습니다. 기본 model은 Codex `gpt-5.6-luna`, Claude `haiku`입니다. `--provider`와 `--model`을 함께 지정하면 그 정확한 선택을 사용합니다.
100
+
101
+ 각 AI 요청 전에 provider, model, 정제된 요청의 크기, 결과 제한, timeout, fingerprint를 표시하고 전송 승인을 받습니다. 승인하지 않으면 provider를 호출하지 않습니다. 후보 결과는 전체 적용 또는 change ID 선택 적용으로 검토하며, 피드백을 입력해 새 요청을 보낼 수 있습니다. 질문 결과도 표시한 뒤 답변을 새 요청으로 보낼 수 있습니다. 직접 편집은 별도 JSON 파일 경로를 입력해 불러오며, 같은 diff와 승인 경계를 거칩니다.
102
+
103
+ 저장한 명세에는 `approval` 블록이 함께 들어갑니다.
104
+
105
+ ```json
106
+ {
107
+ "schemaVersion": 1,
108
+ "id": "weather",
109
+ "name": "Weather server",
110
+ "approval": {
111
+ "fingerprint": "9f2c1a3b4d5e6f708192a3b4c5d6e7f8091a2b3c4d5e6f708192a3b4c5d6e7f8"
112
+ },
113
+ "defaultTimeoutMs": 5000,
114
+ "cases": []
115
+ }
116
+ ```
117
+
118
+ `fingerprint`는 승인한 시점의 명세를 요약한 소문자 hex 64자입니다. 계산 대상은 파일 바이트가 아니라 파싱된 명세 객체이므로 들여쓰기, 줄 끝 문자, 키 순서를 바꿔도 값이 그대로입니다. 답해야 하는 질문이 "바이트가 바뀌었나"가 아니라 "테스트의 의미가 바뀌었나"이기 때문입니다. `approval` 블록 자신은 계산에서 제외됩니다. 자기를 포함한 채로 자기를 요약할 수는 없습니다. 저장 직후에는 파일을 다시 읽어 계산값과 파일에 적힌 값이 모두 승인 시점의 지문과 같은지 확인한 뒤에만 커밋합니다.
119
+
120
+ 마지막으로 승인된 draft의 fingerprint를 확인하고 저장을 다시 승인해야 JSON을 씁니다. 저장한 파일은 기존 `mcpeak test <suite.json> --command ...` 명령에 그대로 전달할 수 있습니다. 실제 Codex 또는 Claude 호출은 계정과 비용을 사용하는 작업이므로, 자동 테스트나 기본 검증에서는 실행하지 않습니다.
package/README.md CHANGED
@@ -1,9 +1,11 @@
1
+ **English** · [한국어](./README.ko.md)
2
+
1
3
  # MCPeak CLI
2
4
 
3
- `mcpeak test`는 JSON 테스트 명세로 로컬 stdio MCP 서버를 직접 시작하고 종료합니다.
5
+ `mcpeak test` starts and stops a local stdio MCP server directly from a JSON test suite.
4
6
 
5
- 처음 실행하거나 사용 가능한 명령을 확인할 때는 전체 도움말을 표시합니다. 인자 없이 실행해도
6
- 같은 도움말을 stdout에 쓰고 종료 코드 0을 반환합니다.
7
+ When running it for the first time or checking which commands are available, it shows the full help. Running it with no arguments
8
+ also writes the same help to stdout and returns exit code 0.
7
9
 
8
10
  ```bash
9
11
  mcpeak --help
@@ -12,9 +14,9 @@ mcpeak help
12
14
  mcpeak --version
13
15
  ```
14
16
 
15
- `mcpeak help test`와 `mcpeak test --help`는 `test` 도움말을, `mcpeak help generate`와
16
- `mcpeak generate --help`는 `generate` 도움말을 표시합니다. 도움말과 버전은 오류가 아니므로
17
- stderr가 아니라 stdout으로 출력하고 종료 코드 0을 반환합니다.
17
+ `mcpeak help test` and `mcpeak test --help` show the `test` help, and `mcpeak help generate` and
18
+ `mcpeak generate --help` show the `generate` help. Help and version are not errors, so they are printed
19
+ to stdout rather than stderr and return exit code 0.
18
20
 
19
21
  ```bash
20
22
  mcpeak test packages/cli/tests/fixtures/weather-suite.json \
@@ -22,11 +24,11 @@ mcpeak test packages/cli/tests/fixtures/weather-suite.json \
22
24
  --arg examples/weather-server/server.mjs
23
25
  ```
24
26
 
25
- 문법은 `mcpeak test <suite.json> --command <executable> [--arg <value> ...] [--json] [--junit <path>] [--stderr-lines <N>] [--record-session <path> | --session <path>]`입니다. 위 예시의 command와 arg는 `node examples/weather-server/server.mjs`로 실행됩니다. `--arg`는 반복할 수 있고, 하이픈으로 시작하는 값은 `--arg=-m`, 빈 값은 `--arg=`로 전달합니다.
27
+ The syntax is `mcpeak test <suite.json> --command <executable> [--arg <value> ...] [--json] [--junit <path>] [--stderr-lines <N>] [--record-session <path> | --session <path>]`. The command and arg in the example above run as `node examples/weather-server/server.mjs`. `--arg` can be repeated; pass a value starting with a hyphen as `--arg=-m` and an empty value as `--arg=`.
26
28
 
27
- stdout에는 보고서만 나갑니다. 기본은 사람이 읽는 보고서이고, `--json`을 주면 `RunnerReport` JSON이 나갑니다. CLI 오류와 서버 프로세스 진단은 stderr로만 나가므로 `--json > report.json`이 깨지지 않습니다. 모든 테스트가 통과하면 종료 코드 0을, failed 또는 aborted report와 입력, 연결, 종료 오류에는 1을 반환합니다.
29
+ Only the report goes to stdout. By default it is a human-readable report, and with `--json` it is `RunnerReport` JSON. CLI errors and server process diagnostics go only to stderr, so `--json > report.json` does not break. The exit code is 0 when every test passes, and 1 for a failed or aborted report and for input, connection, and shutdown errors.
28
30
 
29
- `--junit <path>`는 CI 도구가 읽는 JUnit XML 리포트를 그 경로에 씁니다.
31
+ `--junit <path>` writes a JUnit XML report that CI tools read to that path.
30
32
 
31
33
  ```bash
32
34
  mcpeak test weather.json \
@@ -34,47 +36,47 @@ mcpeak test weather.json \
34
36
  --junit reports/junit.xml
35
37
  ```
36
38
 
37
- stdout은 그대로 두고 파일만 더하므로 `--json`과 함께 쓸 수 있습니다. 둘의 역할이 다릅니다 — `--json`은 stdout 형식을, `--junit`은 별도 산출물을 정합니다. 경로의 디렉터리는 미리 있어야 하며, 파일을 쓰지 못하면 모든 테스트가 통과했더라도 `JUNIT_WRITE_FAILED`와 함께 종료 코드 1을 냅니다. 리포트 없이 CI가 초록이 되지 않게 하려는 것입니다. XML은 stdout보다 먼저 쓰므로 stdout이 파이프에서 끊겨도 파일은 남습니다.
39
+ It leaves stdout as is and only adds a file, so it can be used together with `--json`. The two have different roles — `--json` sets the stdout format, `--junit` sets a separate artifact. The directory of the path must already exist, and if the file cannot be written, it exits with code 1 and `JUNIT_WRITE_FAILED` even if every test passed. This is so CI never goes green without a report. The XML is written before stdout, so the file remains even if stdout is cut off in a pipe.
38
40
 
39
- XML을 만드는 단계에서 실패하면 `CLI_INTERNAL_ERROR`와 함께 종료 코드 1을 냅니다. 이때는 파일 쓰기에 도달하기 전이므로 **파일을 만들지도, 기존 파일을 덮어쓰지도 않습니다.** 직전 실행의 리포트가 그대로 남으므로, CI에서 이 경로를 읽는 도구가 낡은 리포트를 최신 결과로 오해할 수 있습니다. 종료 코드로 판정하세요.
41
+ If building the XML fails, it exits with code 1 and `CLI_INTERNAL_ERROR`. This happens before the file write is reached, so **it neither creates the file nor overwrites an existing one.** The report from the previous run stays in place, so a tool reading this path in CI may mistake a stale report for the latest result. Judge by the exit code.
40
42
 
41
- `RunnerReport`에는 시간 정보가 없어 모든 `time` 속성은 `0`입니다. "0초 걸렸다"가 아니라 "시간 정보를 갖고 있지 않다"는 뜻입니다. 근거는 [ADR-0016](../../docs/adr/0016-junit-time-속성-고정.md), 플래그 설계는 [ADR-0019](../../docs/adr/0019-junit-리포터-cli-노출-방식.md)에 있습니다.
43
+ `RunnerReport` has no timing information, so every `time` attribute is `0`. It means "has no timing information," not "took 0 seconds." The rationale is in [ADR-0016](../../docs/adr/0016-junit-time-속성-고정.md), and the flag design is in [ADR-0019](../../docs/adr/0019-junit-리포터-cli-노출-방식.md).
42
44
 
43
- `--record-session <path>`는 서버가 `globalThis.fetch`로 호출한 외부 HTTP 응답을 녹화하고,
44
- `--session <path>`는 그 녹화본을 재생합니다. 서버는 재생 때도 실제로 실행됩니다. `node:http`와
45
- `node:https` 계층 호출은 범위 밖이라 실제 네트워크로 나갈 수 있으며, CLI는 녹화 0건이나 재생
46
- 0건처럼 범위 밖 호출이 의심되는 실행을 stderr 알림으로 드러냅니다.
45
+ `--record-session <path>` records the external HTTP responses the server fetched with `globalThis.fetch`,
46
+ and `--session <path>` replays that recording. The server actually runs during replay too. Calls at the `node:http` and
47
+ `node:https` layer are out of scope and may go out to the real network; the CLI surfaces runs where an out-of-scope call is suspected,
48
+ such as zero recorded or zero replayed responses, with a notice on stderr.
47
49
 
48
- `--stderr-lines <N>`은 실패했거나 서버가 비정상 종료·중단했을 때, 진단 내용이 있으면 stderr에 붙는 서버 프로세스 진단 블록의 stderr 표시 줄 수입니다. 기본값은 20이고, `0`을 주면 블록을 완전히 끕니다(그때 출력 바이트는 이 기능이 없던 때와 같습니다). 블록에는 종료 코드와 시그널, 서버가 남긴 stderr의 마지막 N줄이 담기며 잘린 사실은 헤더에 적힙니다. 서버가 정상 종료했고 stderr도 비어 있으면 보여줄 근거가 없으므로 블록을 쓰지 않습니다.
50
+ `--stderr-lines <N>` is the number of stderr lines shown in the server process diagnostic block that is attached to stderr, when there is diagnostic content, after a failure or after the server exits abnormally or is aborted. The default is 20, and `0` turns the block off entirely (the output bytes are then the same as before this feature existed). The block contains the exit code and signal and the last N lines of stderr the server left, and truncation is noted in the header. If the server exited normally and stderr is empty, there is no evidence to show, so the block is not written.
49
51
 
50
- ### 승인 지문 대조
52
+ ### Approval fingerprint check
51
53
 
52
- `test`는 실행할 명세의 승인 지문을 계산해 파일에 적힌 `approval.fingerprint`와 대조하고, 그 결과를 보고서에 적습니다. **판정은 바꾸지 않습니다.** 종료 코드는 케이스 결과로만 정해지므로 지문이 달라도 전부 통과하면 0입니다. 명세를 고치는 것은 정상 작업이고, 그때마다 테스트가 막히면 사용자는 확인 절차를 우회하는 방법부터 찾게 됩니다.
54
+ `test` computes the approval fingerprint of the suite it runs, compares it against the `approval.fingerprint` written in the file, and records the result in the report. **It does not change the verdict.** The exit code is determined only by the case results, so it is 0 if everything passes even when the fingerprint differs. Editing a suite is normal work, and if tests were blocked every time, users would first look for a way around the check.
53
55
 
54
- 표시 여부는 다음과 같습니다. 매 실행 한 줄을 무조건 찍으면 손으로 명세를 쓰는 사용자에게는 영구적인 소음이고, 그러면 정작 필요할 때 그 줄을 읽지 않습니다.
56
+ Whether it is shown is as follows. Printing a line unconditionally on every run would be permanent noise for users who write suites by hand, and then they would not read the line exactly when it matters.
55
57
 
56
- | 지문 상태 | 전부 통과 | 실패·타임아웃 등이 있음 |
58
+ | Fingerprint state | All passed | Has failures, timeouts, etc. |
57
59
  |---|---|---|
58
- | 일치 | 침묵 | 표시 |
59
- | 불일치 | **표시** | 표시 |
60
- | 없음(미고정) | 침묵 | 표시 |
60
+ | Matched | Silent | Shown |
61
+ | Mismatched | **Shown** | Shown |
62
+ | Absent (not pinned) | Silent | Shown |
61
63
 
62
- 전부 통과인데 불일치일 때만 예외를 두는 이유는 승인받지 않은 명세로 초록불이 뜬 상태이기 때문입니다. 그 사실은 실패보다 오히려 조용히 지나가기 쉽습니다.
64
+ The only exception is a mismatch when everything passes, because that is a green result on an unapproved suite. That fact is even easier to let slip by quietly than a failure.
63
65
 
64
- 현재 명세에서 계산한 지문과 저장된 `approval.fingerprint`가 불일치하면 전부 통과했는지 실패가
65
- 있는지에 맞춰 상황을 구분해 알립니다. 지문 두 개만으로는 구체적인 변경 내용을 복원할 수 없으므로
66
- 버전 관리에서 명세를 비교하도록 안내하고, 의도한 변경이면 같은 설정의 `mcpeak generate`에
67
- `--force`를 붙여 다시 생성·승인하도록 안내합니다.
66
+ When the fingerprint computed from the current suite and the saved `approval.fingerprint` do not match, the message distinguishes the situation
67
+ by whether everything passed or there were failures. Two fingerprints alone cannot reconstruct the specific changes, so
68
+ it guides you to compare the suite in version control, and if the change was intended, to regenerate and re-approve by adding
69
+ `--force` to `mcpeak generate` with the same settings.
68
70
 
69
- 명세 줄은 보고서 본문 뒤에 빈 줄 하나를 두고 stdout으로 나갑니다. `--json`에는 위 억제 규칙을 적용하지 않고 `spec` 키를 항상 넣습니다(`approval`은 `matched` · `mismatched` · `absent` 중 하나, `fingerprint`는 실행 시점 계산값, `approvedFingerprint`는 파일에 적힌 값이며 `absent`면 키가 없습니다). 기계가 읽는 출력에서 키가 조건부로 사라지면 소비자가 분기를 하나 더 써야 합니다. 기존 보고서 키는 그대로이므로 기존 소비자는 깨지지 않습니다.
71
+ The suite line goes to stdout after the report body, separated by one blank line. `--json` does not apply the suppression rule above and always includes the `spec` key (`approval` is one of `matched` · `mismatched` · `absent`, `fingerprint` is the value computed at run time, and `approvedFingerprint` is the value written in the file; when `absent`, the key is omitted). If keys conditionally disappear from machine-readable output, consumers have to write one more branch. Existing report keys are unchanged, so existing consumers do not break.
70
72
 
71
- 지문이 없는 명세도 정상입니다. 손으로 쓴 명세와 이 기능 이전에 만든 명세가 여기에 해당하며 실패로 취급하지 않습니다.
73
+ A suite without a fingerprint is also normal. Hand-written suites and suites made before this feature fall into this category and are not treated as failures.
72
74
 
73
- 현재는 UTF-8 JSON 단일 명세와 stdio 서버만 지원합니다. shell 문법, 여러 명세, TypeScript 모듈 명세는 지원하지 않습니다. `record`, `mock` 명령은 아직 구현되지 않았습니다.
75
+ Currently only a single UTF-8 JSON suite and stdio servers are supported. Shell syntax, multiple suites, and TypeScript module suites are not supported. The `record` and `mock` commands are not implemented yet.
74
76
 
75
77
  ## generate
76
78
 
77
- `mcpeak generate`는 서버의 `tools/list` 결과에서 결정론적 baseline suite를 만듭니다.
79
+ `mcpeak generate` builds a deterministic baseline suite from the server's `tools/list` result.
78
80
 
79
81
  ```bash
80
82
  mcpeak generate \
@@ -86,19 +88,19 @@ mcpeak generate \
86
88
  --baseline-only
87
89
  ```
88
90
 
89
- 문법은 다음과 같습니다.
91
+ The syntax is as follows.
90
92
 
91
93
  ```text
92
94
  mcpeak generate --suite-id <id> --name <name> --out <suite.json> --command <executable> [--arg <value> ...] [--baseline-only] [--provider <codex|claude>] [--model <model>]
93
95
  ```
94
96
 
95
- `--baseline-only`는 AI를 호출하지 않는 명시적 비대화형 승인입니다. 생성기는 기존 출력 파일을 덮어쓰지 않으며, 같은 디렉터리의 임시 파일을 다시 읽어 suite와 fingerprint를 검증한 뒤 원자적으로 저장합니다. weather-server의 baseline은 `get_weather`에 `{ "city": "example" }`를 사용하므로, 이어서 `mcpeak test`를 실행하면 get_weather가 실패하고 add는 통과합니다. 이는 baseline이 스키마에서 얻은 출발점일 뿐 실행 성공을 보장하지 않는다는 신호입니다.
97
+ `--baseline-only` is an explicit non-interactive approval that never calls AI. The generator does not overwrite an existing output file; it rereads a temporary file in the same directory to verify the suite and fingerprint and then saves atomically. The weather-server baseline uses `{ "city": "example" }` for `get_weather`, so if you then run `mcpeak test`, get_weather fails and add passes. This is a signal that the baseline is only a starting point derived from the schema and does not guarantee a successful run.
96
98
 
97
- TTY에서 `--baseline-only`를 빼면 대화형 검토가 시작됩니다. Codex 또는 Claude provider와 model을 선택할 수 있습니다. 기본 model은 Codex `gpt-5.6-luna`, Claude `haiku`입니다. `--provider`와 `--model`을 함께 지정하면 그 정확한 선택을 사용합니다.
99
+ In a TTY, leaving out `--baseline-only` starts an interactive review. You can choose a Codex or Claude provider and model. The default models are Codex `gpt-5.6-luna` and Claude `haiku`. If you specify both `--provider` and `--model`, that exact choice is used.
98
100
 
99
- 각 AI 요청 전에 provider, model, 정제된 요청의 크기, 결과 제한, timeout, fingerprint를 표시하고 전송 승인을 받습니다. 승인하지 않으면 provider를 호출하지 않습니다. 후보 결과는 전체 적용 또는 change ID 선택 적용으로 검토하며, 피드백을 입력해 새 요청을 보낼 수 있습니다. 질문 결과도 표시한 뒤 답변을 새 요청으로 보낼 수 있습니다. 직접 편집은 별도 JSON 파일 경로를 입력해 불러오며, 같은 diff와 승인 경계를 거칩니다.
101
+ Before each AI request, it shows the provider, model, size of the sanitized request, result limit, timeout, and fingerprint, and asks for send approval. If you do not approve, the provider is not called. Candidate results are reviewed by applying them all or applying selected change IDs, and you can enter feedback to send a new request. Question results are also shown, and you can send your answer as a new request. Direct editing loads a separate JSON file whose path you enter, and goes through the same diff and approval boundary.
100
102
 
101
- 저장한 명세에는 `approval` 블록이 함께 들어갑니다.
103
+ The saved suite includes an `approval` block.
102
104
 
103
105
  ```json
104
106
  {
@@ -113,6 +115,6 @@ TTY에서 `--baseline-only`를 빼면 대화형 검토가 시작됩니다. Codex
113
115
  }
114
116
  ```
115
117
 
116
- `fingerprint`는 승인한 시점의 명세를 요약한 소문자 hex 64자입니다. 계산 대상은 파일 바이트가 아니라 파싱된 명세 객체이므로 들여쓰기, 줄 끝 문자, 키 순서를 바꿔도 값이 그대로입니다. 답해야 하는 질문이 "바이트가 바뀌었나"가 아니라 "테스트의 의미가 바뀌었나"이기 때문입니다. `approval` 블록 자신은 계산에서 제외됩니다. 자기를 포함한 채로 자기를 요약할 수는 없습니다. 저장 직후에는 파일을 다시 읽어 계산값과 파일에 적힌 값이 모두 승인 시점의 지문과 같은지 확인한 뒤에만 커밋합니다.
118
+ `fingerprint` is 64 lowercase hex characters that summarize the suite as it stood at approval. It is computed from the parsed suite object rather than the file's bytes, so the value stays the same if you change indentation, line endings, or key order. The question it has to answer is not "did the bytes change" but "did the meaning of the tests change." The `approval` block itself is excluded from the computation. Nothing can summarize itself while containing itself. Right after saving, the file is reread, and it is committed only after confirming that both the computed value and the value written in the file equal the fingerprint at approval.
117
119
 
118
- 마지막으로 승인된 draft의 fingerprint를 확인하고 저장을 다시 승인해야 JSON을 씁니다. 저장한 파일은 기존 `mcpeak test <suite.json> --command ...` 명령에 그대로 전달할 수 있습니다. 실제 Codex 또는 Claude 호출은 계정과 비용을 사용하는 작업이므로, 자동 테스트나 기본 검증에서는 실행하지 않습니다.
120
+ Finally, JSON is written only after you confirm the fingerprint of the last approved draft and approve the save again. The saved file can be passed as is to the existing `mcpeak test <suite.json> --command ...` command. An actual Codex or Claude call uses your account and incurs cost, so it is not run in automated tests or default verification.
package/dist/cli.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  //#region src/cli.ts
3
- require("./index.cjs").run(process.argv.slice(2)).then((code) => {
3
+ require("./src-CsQbffCA.cjs").run(process.argv.slice(2)).then((code) => {
4
4
  process.exitCode = code;
5
5
  });
6
6
  //#endregion
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { run } from "./index.mjs";
2
+ import { a as run } from "./src-CZ7uPa_K.mjs";
3
3
  //#region src/cli.ts
4
4
  run(process.argv.slice(2)).then((code) => {
5
5
  process.exitCode = code;
package/dist/commands.cjs CHANGED
@@ -1,10 +1,59 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_test_command = require("./test-command-1m3myzTS.cjs");
3
- exports.REVIEW_BACK_VALUE = require_test_command.REVIEW_BACK_VALUE;
4
- exports.nodeGenerateDependencies = require_test_command.nodeGenerateDependencies;
5
- exports.nodeReviewIO = require_test_command.nodeReviewIO;
6
- exports.parseRepairCommand = require_test_command.parseRepairCommand;
7
- exports.parseTestCommand = require_test_command.parseTestCommand;
8
- exports.runCli = require_test_command.runCli;
9
- exports.runGenerateCommand = require_test_command.runGenerateCommand;
10
- exports.runRepairCommand = require_test_command.runRepairCommand;
2
+ const require_src = require("./src-CsQbffCA.cjs");
3
+ //#region src/auto-review-io.ts
4
+ function autoReviewIO(sink) {
5
+ let menuSeen = false;
6
+ let cancelled = false;
7
+ const note = (question, answer) => {
8
+ sink.write(`▸ 자동 승인: ${summarize(question)} → ${answer}\n`);
9
+ };
10
+ return {
11
+ interactive: true,
12
+ get cancelled() {
13
+ return cancelled;
14
+ },
15
+ write: (text) => sink.write(text),
16
+ async choose(message, choices) {
17
+ if (message === "검토 메뉴") {
18
+ const answer = menuSeen ? "cancel" : "save";
19
+ if (menuSeen) cancelled = true;
20
+ menuSeen = true;
21
+ note(message, answer);
22
+ return answer;
23
+ }
24
+ const answer = choices[0] ?? "";
25
+ note(message, answer);
26
+ return answer;
27
+ },
28
+ async confirm(message) {
29
+ const answer = !/그래도 적용합니까/.test(message);
30
+ note(message, answer ? "예" : "아니오");
31
+ return answer;
32
+ },
33
+ async input(message) {
34
+ const answer = /^\s*선택:\s*$/.test(message) ? "s" : "";
35
+ note(message, answer === "" ? "(엔터)" : answer);
36
+ return answer;
37
+ }
38
+ };
39
+ }
40
+ /** 로그 한 줄에 들어갈 만큼만 남긴다. 질문 본문은 이미 화면에 찍혀 있다. */
41
+ function summarize(question) {
42
+ const oneLine = question.replace(/\s+/g, " ").trim();
43
+ return oneLine.length > 60 ? `${oneLine.slice(0, 57)}...` : oneLine;
44
+ }
45
+ //#endregion
46
+ exports.REVIEW_BACK_VALUE = require_src.REVIEW_BACK_VALUE;
47
+ exports.autoReviewIO = autoReviewIO;
48
+ exports.nodeAuditDependencies = require_src.nodeAuditDependencies;
49
+ exports.nodeGenerateDependencies = require_src.nodeGenerateDependencies;
50
+ exports.nodeReviewIO = require_src.nodeReviewIO;
51
+ exports.parseAuditCommand = require_src.parseAuditCommand;
52
+ exports.parseOptimizeCommand = require_src.parseOptimizeCommand;
53
+ exports.parseRepairCommand = require_src.parseRepairCommand;
54
+ exports.parseTestCommand = require_src.parseTestCommand;
55
+ exports.runAuditCommand = require_src.runAuditCommand;
56
+ exports.runCli = require_src.runCli;
57
+ exports.runGenerateCommand = require_src.runGenerateCommand;
58
+ exports.runOptimizeCommand = require_src.runOptimizeCommand;
59
+ exports.runRepairCommand = require_src.runRepairCommand;
@@ -1,7 +1,36 @@
1
- import { a as GenerateCommandDependencies, c as ReviewIO, d as runGenerateCommand, f as ConnectTarget, i as runRepairCommand, l as nodeGenerateDependencies, n as RepairCommandInput, o as GenerateCommandInput, r as parseRepairCommand, s as REVIEW_BACK_VALUE, t as RepairCommandDependencies, u as nodeReviewIO } from "./repair-command-CVFqxU6V.cjs";
1
+ import { C as AuditCommandInput, E as ConnectTarget, S as AuditCommandDependencies, T as runAuditCommand, _ as REVIEW_BACK_VALUE, b as nodeReviewIO, c as RepairCommandInput, d as OptimizeCommandDependencies, f as OptimizeCommandInput, g as GenerateCommandInput, h as GenerateCommandDependencies, l as parseRepairCommand, m as runOptimizeCommand, p as parseOptimizeCommand, r as nodeAuditDependencies, s as RepairCommandDependencies, u as runRepairCommand, v as ReviewIO, w as parseAuditCommand, x as runGenerateCommand, y as nodeGenerateDependencies } from "./index-_hQ_Ohu-.cjs";
2
2
  import { McpHttpConnection, McpStdioConnection } from "@mcpeak/core";
3
- import { CheckDeterminismOptions, DeterminismResult, FinalizeRunnerExecutionOptions, InputContractOptions, RunSuiteOptions, RunnerExecution, RunnerReport, SpecFindingsResult, SuiteValidationIssue, SuiteValidationResult, TestSuiteSpec } from "@mcpeak/runner";
3
+ import { CheckDeterminismOptions, DeterminismResult, FinalizeRunnerExecutionOptions, InputContractOptions, RunSuiteOptions, RunnerExecution, RunnerReport, SpecFinding, SpecFindingsResult, SuiteValidationIssue, SuiteValidationResult, TestSuiteSpec } from "@mcpeak/runner";
4
4
  import "@mcpeak/record/external";
5
+ //#region src/auto-review-io.d.ts
6
+ /**
7
+ * `generate` 의 승인 질문에 정해진 정책으로 답하는 ReviewIO.
8
+ *
9
+ * 사람용 승인 화면(전송·시험 실행·재검증·저장 확인, 실패 분류, 교정 값 입력)을 에이전트나
10
+ * 대시보드의 "한 번에 검증" 이 사람 개입 없이 지나가게 한다. 판정 로직은 없다. 질문마다 어떤
11
+ * 답을 고르는지만 여기 있고, 고른 답은 `sink` 에 한 줄씩 남겨 무엇이 자동으로 결정됐는지
12
+ * 화면에서 읽을 수 있게 한다.
13
+ *
14
+ * 정책:
15
+ * - 검토 메뉴: 처음은 `save`, 그 뒤는 `cancel`. 저장이 되돌아오면(재검증 실패 등) 같은 답을
16
+ * 되풀이하지 않고 끝낸다.
17
+ * - 확인: 전부 예. 단 "그래도 적용합니까" 처럼 선언 위반이 남은 후보의 적용은 아니오.
18
+ * - 실패 분류(`선택: `): `s`(서버 결함). 교정 뒤에도 남은 실패는 명세가 옳고 서버가 틀린 것으로
19
+ * 기록한다. 보류(`?`)는 저장을 막으므로 쓰지 않는다.
20
+ * - 교정 값 입력(`엔터 = …`): 빈 문자열. 제안이 있으면 제안 값, 없으면 현재 값을 그대로 둔다.
21
+ * - 그 밖의 입력: 빈 문자열. 저장 경로에서는 나오지 않는다.
22
+ */
23
+ interface AutoReviewIO extends ReviewIO {
24
+ /**
25
+ * 검토 메뉴에 두 번째로 닿아 `cancel` 로 끝냈는가. 저장이 되돌아왔다는 뜻이고, 그때 generate
26
+ * 는 저장 없이 0 을 돌려준다. 호출자는 이 값으로 "저장 성공" 과 "취소" 를 가른다.
27
+ */
28
+ readonly cancelled: boolean;
29
+ }
30
+ declare function autoReviewIO(sink: {
31
+ write(text: string): void;
32
+ }): AutoReviewIO;
33
+ //#endregion
5
34
  //#region src/test-command.d.ts
6
35
  interface TestCommandInput {
7
36
  readonly suitePath: string;
@@ -63,8 +92,13 @@ interface TestCommandDependencies {
63
92
  readEnv?(name: string): string | undefined;
64
93
  startRunner(options: RunSuiteOptions): RunnerExecution;
65
94
  finalize(options: FinalizeRunnerExecutionOptions): Promise<RunnerReport>;
95
+ /**
96
+ * `specApproved` 는 명세에 approval 블록이 있는지다. 거절 근거 미확인 고지가 generate 승인
97
+ * 화면을 가리킬지 `--json` 의 rejectionBody 를 가리킬지 가른다. 설계 문서(경쟁 도구 비교) §3.4.
98
+ */
66
99
  renderReport(report: RunnerReport, options?: {
67
100
  color?: boolean;
101
+ specApproved?: boolean;
68
102
  }): string;
69
103
  /**
70
104
  * runner 의 `renderJUnit`. 두 번째 인자를 선언하지 않는다 — CLI 는 `suiteName` 을 넘길 이유가
@@ -79,6 +113,11 @@ interface TestCommandDependencies {
79
113
  */
80
114
  checkInputContract?(options: InputContractOptions): SpecFindingsResult;
81
115
  checkAssertionSubstance?(suite: TestSuiteSpec): SpecFindingsResult;
116
+ /**
117
+ * 거절 기대 케이스에서 억제된 선언 위반. 위 두 필드와 같은 이유로 선택 사항이다. 생략하면
118
+ * `runner` 의 `acceptedViolations` 다. 설계 문서(경쟁 도구 비교) §3.2.
119
+ */
120
+ acceptedViolations?(options: InputContractOptions): ReadonlyMap<string, readonly SpecFinding[]>;
82
121
  /**
83
122
  * 결정론성 비교와 초기화 명령의 주입 지점. 위 두 필드와 같은 이유로 선택 사항이다.
84
123
  * 생략하면 각각 `runner` 의 `checkDeterminism` 과 `reset-hook.ts` 의 `runResetCommand` 다.
@@ -102,4 +141,4 @@ declare function parseTestCommand(argv: readonly string[]): TestCommandInput;
102
141
  */
103
142
  declare function runCli(argv: readonly string[], dependencies: TestCommandDependencies): Promise<number>;
104
143
  //#endregion
105
- export { type CliErrorCode, type CliFailure, type GenerateCommandDependencies, type GenerateCommandInput, REVIEW_BACK_VALUE, type RepairCommandDependencies, type RepairCommandInput, type ReviewIO, type TestCommandDependencies, type TestCommandInput, nodeGenerateDependencies, nodeReviewIO, parseRepairCommand, parseTestCommand, runCli, runGenerateCommand, runRepairCommand };
144
+ export { type AuditCommandDependencies, type AuditCommandInput, type AutoReviewIO, type CliErrorCode, type CliFailure, type GenerateCommandDependencies, type GenerateCommandInput, type OptimizeCommandDependencies, type OptimizeCommandInput, REVIEW_BACK_VALUE, type RepairCommandDependencies, type RepairCommandInput, type ReviewIO, type TestCommandDependencies, type TestCommandInput, autoReviewIO, nodeAuditDependencies, nodeGenerateDependencies, nodeReviewIO, parseAuditCommand, parseOptimizeCommand, parseRepairCommand, parseTestCommand, runAuditCommand, runCli, runGenerateCommand, runOptimizeCommand, runRepairCommand };
@@ -1,7 +1,36 @@
1
- import { a as GenerateCommandDependencies, c as ReviewIO, d as runGenerateCommand, f as ConnectTarget, i as runRepairCommand, l as nodeGenerateDependencies, n as RepairCommandInput, o as GenerateCommandInput, r as parseRepairCommand, s as REVIEW_BACK_VALUE, t as RepairCommandDependencies, u as nodeReviewIO } from "./repair-command-8GUlJJ47.mjs";
2
- import { CheckDeterminismOptions, DeterminismResult, FinalizeRunnerExecutionOptions, InputContractOptions, RunSuiteOptions, RunnerExecution, RunnerReport, SpecFindingsResult, SuiteValidationIssue, SuiteValidationResult, TestSuiteSpec } from "@mcpeak/runner";
1
+ import { C as AuditCommandInput, E as ConnectTarget, S as AuditCommandDependencies, T as runAuditCommand, _ as REVIEW_BACK_VALUE, b as nodeReviewIO, c as RepairCommandInput, d as OptimizeCommandDependencies, f as OptimizeCommandInput, g as GenerateCommandInput, h as GenerateCommandDependencies, l as parseRepairCommand, m as runOptimizeCommand, p as parseOptimizeCommand, r as nodeAuditDependencies, s as RepairCommandDependencies, u as runRepairCommand, v as ReviewIO, w as parseAuditCommand, x as runGenerateCommand, y as nodeGenerateDependencies } from "./index-CBFNkZgR.mjs";
2
+ import { CheckDeterminismOptions, DeterminismResult, FinalizeRunnerExecutionOptions, InputContractOptions, RunSuiteOptions, RunnerExecution, RunnerReport, SpecFinding, SpecFindingsResult, SuiteValidationIssue, SuiteValidationResult, TestSuiteSpec } from "@mcpeak/runner";
3
3
  import { McpHttpConnection, McpStdioConnection } from "@mcpeak/core";
4
4
  import "@mcpeak/record/external";
5
+ //#region src/auto-review-io.d.ts
6
+ /**
7
+ * `generate` 의 승인 질문에 정해진 정책으로 답하는 ReviewIO.
8
+ *
9
+ * 사람용 승인 화면(전송·시험 실행·재검증·저장 확인, 실패 분류, 교정 값 입력)을 에이전트나
10
+ * 대시보드의 "한 번에 검증" 이 사람 개입 없이 지나가게 한다. 판정 로직은 없다. 질문마다 어떤
11
+ * 답을 고르는지만 여기 있고, 고른 답은 `sink` 에 한 줄씩 남겨 무엇이 자동으로 결정됐는지
12
+ * 화면에서 읽을 수 있게 한다.
13
+ *
14
+ * 정책:
15
+ * - 검토 메뉴: 처음은 `save`, 그 뒤는 `cancel`. 저장이 되돌아오면(재검증 실패 등) 같은 답을
16
+ * 되풀이하지 않고 끝낸다.
17
+ * - 확인: 전부 예. 단 "그래도 적용합니까" 처럼 선언 위반이 남은 후보의 적용은 아니오.
18
+ * - 실패 분류(`선택: `): `s`(서버 결함). 교정 뒤에도 남은 실패는 명세가 옳고 서버가 틀린 것으로
19
+ * 기록한다. 보류(`?`)는 저장을 막으므로 쓰지 않는다.
20
+ * - 교정 값 입력(`엔터 = …`): 빈 문자열. 제안이 있으면 제안 값, 없으면 현재 값을 그대로 둔다.
21
+ * - 그 밖의 입력: 빈 문자열. 저장 경로에서는 나오지 않는다.
22
+ */
23
+ interface AutoReviewIO extends ReviewIO {
24
+ /**
25
+ * 검토 메뉴에 두 번째로 닿아 `cancel` 로 끝냈는가. 저장이 되돌아왔다는 뜻이고, 그때 generate
26
+ * 는 저장 없이 0 을 돌려준다. 호출자는 이 값으로 "저장 성공" 과 "취소" 를 가른다.
27
+ */
28
+ readonly cancelled: boolean;
29
+ }
30
+ declare function autoReviewIO(sink: {
31
+ write(text: string): void;
32
+ }): AutoReviewIO;
33
+ //#endregion
5
34
  //#region src/test-command.d.ts
6
35
  interface TestCommandInput {
7
36
  readonly suitePath: string;
@@ -63,8 +92,13 @@ interface TestCommandDependencies {
63
92
  readEnv?(name: string): string | undefined;
64
93
  startRunner(options: RunSuiteOptions): RunnerExecution;
65
94
  finalize(options: FinalizeRunnerExecutionOptions): Promise<RunnerReport>;
95
+ /**
96
+ * `specApproved` 는 명세에 approval 블록이 있는지다. 거절 근거 미확인 고지가 generate 승인
97
+ * 화면을 가리킬지 `--json` 의 rejectionBody 를 가리킬지 가른다. 설계 문서(경쟁 도구 비교) §3.4.
98
+ */
66
99
  renderReport(report: RunnerReport, options?: {
67
100
  color?: boolean;
101
+ specApproved?: boolean;
68
102
  }): string;
69
103
  /**
70
104
  * runner 의 `renderJUnit`. 두 번째 인자를 선언하지 않는다 — CLI 는 `suiteName` 을 넘길 이유가
@@ -79,6 +113,11 @@ interface TestCommandDependencies {
79
113
  */
80
114
  checkInputContract?(options: InputContractOptions): SpecFindingsResult;
81
115
  checkAssertionSubstance?(suite: TestSuiteSpec): SpecFindingsResult;
116
+ /**
117
+ * 거절 기대 케이스에서 억제된 선언 위반. 위 두 필드와 같은 이유로 선택 사항이다. 생략하면
118
+ * `runner` 의 `acceptedViolations` 다. 설계 문서(경쟁 도구 비교) §3.2.
119
+ */
120
+ acceptedViolations?(options: InputContractOptions): ReadonlyMap<string, readonly SpecFinding[]>;
82
121
  /**
83
122
  * 결정론성 비교와 초기화 명령의 주입 지점. 위 두 필드와 같은 이유로 선택 사항이다.
84
123
  * 생략하면 각각 `runner` 의 `checkDeterminism` 과 `reset-hook.ts` 의 `runResetCommand` 다.
@@ -102,4 +141,4 @@ declare function parseTestCommand(argv: readonly string[]): TestCommandInput;
102
141
  */
103
142
  declare function runCli(argv: readonly string[], dependencies: TestCommandDependencies): Promise<number>;
104
143
  //#endregion
105
- export { type CliErrorCode, type CliFailure, type GenerateCommandDependencies, type GenerateCommandInput, REVIEW_BACK_VALUE, type RepairCommandDependencies, type RepairCommandInput, type ReviewIO, type TestCommandDependencies, type TestCommandInput, nodeGenerateDependencies, nodeReviewIO, parseRepairCommand, parseTestCommand, runCli, runGenerateCommand, runRepairCommand };
144
+ export { type AuditCommandDependencies, type AuditCommandInput, type AutoReviewIO, type CliErrorCode, type CliFailure, type GenerateCommandDependencies, type GenerateCommandInput, type OptimizeCommandDependencies, type OptimizeCommandInput, REVIEW_BACK_VALUE, type RepairCommandDependencies, type RepairCommandInput, type ReviewIO, type TestCommandDependencies, type TestCommandInput, autoReviewIO, nodeAuditDependencies, nodeGenerateDependencies, nodeReviewIO, parseAuditCommand, parseOptimizeCommand, parseRepairCommand, parseTestCommand, runAuditCommand, runCli, runGenerateCommand, runOptimizeCommand, runRepairCommand };
package/dist/commands.mjs CHANGED
@@ -1,2 +1,45 @@
1
- import { a as REVIEW_BACK_VALUE, c as runGenerateCommand, i as runRepairCommand, n as runCli, o as nodeGenerateDependencies, r as parseRepairCommand, s as nodeReviewIO, t as parseTestCommand } from "./test-command-P8_uaAIy.mjs";
2
- export { REVIEW_BACK_VALUE, nodeGenerateDependencies, nodeReviewIO, parseRepairCommand, parseTestCommand, runCli, runGenerateCommand, runRepairCommand };
1
+ import { _ as runCli, c as parseOptimizeCommand, d as nodeGenerateDependencies, f as nodeReviewIO, g as parseTestCommand, h as runAuditCommand, l as runOptimizeCommand, m as parseAuditCommand, n as nodeAuditDependencies, o as parseRepairCommand, p as runGenerateCommand, s as runRepairCommand, u as REVIEW_BACK_VALUE } from "./src-CZ7uPa_K.mjs";
2
+ //#region src/auto-review-io.ts
3
+ function autoReviewIO(sink) {
4
+ let menuSeen = false;
5
+ let cancelled = false;
6
+ const note = (question, answer) => {
7
+ sink.write(`▸ 자동 승인: ${summarize(question)} → ${answer}\n`);
8
+ };
9
+ return {
10
+ interactive: true,
11
+ get cancelled() {
12
+ return cancelled;
13
+ },
14
+ write: (text) => sink.write(text),
15
+ async choose(message, choices) {
16
+ if (message === "검토 메뉴") {
17
+ const answer = menuSeen ? "cancel" : "save";
18
+ if (menuSeen) cancelled = true;
19
+ menuSeen = true;
20
+ note(message, answer);
21
+ return answer;
22
+ }
23
+ const answer = choices[0] ?? "";
24
+ note(message, answer);
25
+ return answer;
26
+ },
27
+ async confirm(message) {
28
+ const answer = !/그래도 적용합니까/.test(message);
29
+ note(message, answer ? "예" : "아니오");
30
+ return answer;
31
+ },
32
+ async input(message) {
33
+ const answer = /^\s*선택:\s*$/.test(message) ? "s" : "";
34
+ note(message, answer === "" ? "(엔터)" : answer);
35
+ return answer;
36
+ }
37
+ };
38
+ }
39
+ /** 로그 한 줄에 들어갈 만큼만 남긴다. 질문 본문은 이미 화면에 찍혀 있다. */
40
+ function summarize(question) {
41
+ const oneLine = question.replace(/\s+/g, " ").trim();
42
+ return oneLine.length > 60 ? `${oneLine.slice(0, 57)}...` : oneLine;
43
+ }
44
+ //#endregion
45
+ export { REVIEW_BACK_VALUE, autoReviewIO, nodeAuditDependencies, nodeGenerateDependencies, nodeReviewIO, parseAuditCommand, parseOptimizeCommand, parseRepairCommand, parseTestCommand, runAuditCommand, runCli, runGenerateCommand, runOptimizeCommand, runRepairCommand };