isthmus-cli 0.1.4 → 0.1.5

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.md CHANGED
@@ -22,10 +22,11 @@ isthmus는 조사한 도구들이 언어별로 나눠 보던 이 교차 경계
22
22
 
23
23
  ## 상태
24
24
 
25
- **0.1.4.** bridge-facts 버전 1 파서와 `check`, `query`, `graph`, `diff`,
25
+ **0.1.5.** bridge-facts 버전 1 파서와 `check`, `query`, `graph`, `diff`,
26
26
  cartograph용 외부 보존 근거 왕복을 구현했다. 외부 입력·혼합 target·그래프 크기와
27
- Dart/Swift Phase 0 추출 경계를 fail-closed로 강화했다. 다음 단계는 실제 Flutter 앱
28
- 도그푸딩과 React Native 지원이다.
27
+ Dart/Swift Phase 0 추출 경계를 fail-closed로 강화했고, 조인하지 못한 사실과 근거를
28
+ 만들지 못한 보존 대상이 조용히 사라지지 않도록 소비자 쪽에서 다시 센다. 다음 단계는
29
+ 실제 Flutter 앱 도그푸딩과 React Native 지원이다.
29
30
 
30
31
  정식 producer는 cartograph 0.5.3 이상과 dartograph 0.1.1 이상이다. 두 도구의 실제 출력과
31
32
  공개 battery 플러그인의 Swift USR·Dart 호출 근거 왕복을 검증했다.
@@ -101,6 +102,10 @@ cartograph dead --external-retentions external-retentions.json
101
102
 
102
103
  `retentions`는 핸들러의 USR을 우선 사용하고 없으면 `qualifiedName`을 남긴다. `mixed-targets` 문서는 v1에서 사실별 target을 복원할 수 없어 모든 소비 명령이 종료 코드 2로 조인을 보류한다. 먼저 생산 단계에서 target별 문서로 분리해야 한다.
103
104
 
105
+ cartograph는 Swift 심볼만 보존하므로 `--for cartograph`는 수신 측 Swift 문서를 최소 하나 요구하고, 없으면 빈 보존 문서 대신 종료 코드 2로 거부한다. 호출자가 있는데도 `symbol`이 없어 보존 근거로 바꿀 수 없는 Swift 핸들러가 있으면 부분 문서를 만들지 않고 같은 코드로 실패한다. 근거가 빠진 보존 파일은 소비자에게 살아 있는 핸들러를 미사용으로 보이게 하기 때문이다.
106
+
107
+ 모든 소비 명령은 호출 측(dart)과 수신 측(swift) 플랫폼 문서를 최소 하나씩 요구한다. 한쪽만 있으면 한쪽 관찰을 경계 불일치로 오독하지 않고 종료 코드 2로 거부한다. 입력 실패 메시지는 원인(읽기 실패, JSON 오류, 교환 계약 위반, project 불일치, 플랫폼 구성 누락, 크기 상한)과 입력 순서, 해결 방향을 구분해 전달하며 입력 본문과 경로는 노출하지 않는다.
108
+
104
109
  실제 공개 Flutter 플러그인에서 생산부터 소비까지 확인하려면 저장소 루트에서 다음 검증을
105
110
  실행한다. 스크립트는 `plus_plugins`의 고정 커밋을 sparse checkout하고 배터리 플러그인의
106
111
  원본 Dart·Swift 소스에서 세 메서드의 보존 근거를 확인한 뒤 임시 checkout을 지운다.
@@ -147,16 +152,37 @@ isthmus graph dart-bridges.json swift-bridges.json --format mermaid
147
152
  - `unregistered-channel-creation` (error): 호출 측 채널 생성은 있지만 네이티브 등록이 없음
148
153
  - `registration-without-creation` (warning): 네이티브 채널 등록은 있지만 호출 측 생성이 없음
149
154
  - `handler-without-invocation` (warning): 네이티브 핸들러는 있지만 호출 측 사용이 없음
155
+ - `unhandled-invocation-unverified` (warning): 위 첫 항목과 같은 사실이지만, 수신 측이
156
+ 핸들러를 놓쳤을 수 있다고 스스로 신고해 없는 것인지 못 본 것인지 판정할 수 없음
157
+ - `unregistered-channel-creation-unverified` (warning): 같은 이유로 등록 여부를 판정할 수 없음
158
+
159
+ `-unverified` 종류는 수신 측 문서의 한계에서 나온다. 예를 들어 Flutter 핸들러가
160
+ Objective-C로 쓰인 플러그인에서 cartograph는 `objective-c-sources:`를 신고하고 핸들러 사실을
161
+ 내지 못한다. 이때 "핸들러 없는 호출"을 error로 단정하면 이 도구가 없애려던 오탐을 이 도구가
162
+ 만든다. 사실과 증거는 그대로 보고하되 `--strict`를 실패시키지 않는다. 공백의 종류는 구분해서,
163
+ 이름이 리터럴이 아닌 채널 등록은 채널 진단만 낮추고 메서드 진단은 낮추지 않는다. 호출 측
164
+ 한계는 네이티브 코드를 가리지 않으므로 심각도에 영향을 주지 않으며, 알려지지 않은 한계
165
+ 문구는 공백으로 해석하지 않는다.
150
166
 
151
167
  모든 이슈는 관찰된 위치를 `evidence`로 제공한다. 동적 이름, 해석하지 못한 receiver나
152
168
  handler 본문, USR 누락, 입력 생성 시각 차이, 혼합 target은 `limitations`에 출처와 함께
153
169
  남긴다. 이 도구는 삭제 가능 여부를 판정하지 않는다.
154
170
 
171
+ `limitations`에는 생산자가 신고한 한계와 isthmus가 직접 센 한계가 함께 들어간다.
172
+ `tool`이 `isthmus`인 항목은 조인 단계에서 관찰한 것이다. 조인하지 못한 사실은 생산자의
173
+ 신고나 그 개수와 무관하게 플랫폼별로 다시 센다.
174
+
175
+ - `unjoined-dynamic-channels`: 이름이 리터럴이 아닌 채널 생성·등록 사실
176
+ - `unjoined-dynamic-methods`: 이름이 리터럴이 아닌 호출·핸들러 사실
177
+ - `unjoined-unattributed-handlers`: 어느 채널에 속하는지 모르는 핸들러 사실
178
+
179
+ 같은 위치의 중복 사실은 한 번만 센다. dynamic이면서 미귀속인 핸들러는 dynamic으로만 센다.
180
+
155
181
  | 종료 코드 | 의미 |
156
182
  |---|---|
157
183
  | `0` | 실행 성공. 기본 모드에서는 이슈가 있어도 보고만 함 |
158
- | `1` | `--strict`에서 error 이슈를 발견함 |
159
- | `2` | 파일 읽기, JSON, 교환 계약, 보류된 조인 등 도구 실패 |
184
+ | `1` | `--strict`에서 error 이슈를 발견함. `-unverified` 경고는 실패시키지 않음 |
185
+ | `2` | 파일 읽기, JSON, 교환 계약, project 불일치, 플랫폼 구성 누락, 보류된 조인 등 도구 실패. stderr가 원인을 구분 |
160
186
  | `64` | 잘못된 명령·옵션·입력 개수 또는 `query`의 `notFound`·`ambiguous` |
161
187
 
162
188
  저장소 checkout에서 개발할 때는 먼저 `npm ci`를 실행한다. 개발 검증은 타입 체크,
@@ -196,6 +222,7 @@ isthmus diff \
196
222
  `--strict`는 새로 관찰된 error가 있을 때만 1이다. 기존 오류·경고·분석 한계만 있으면 0이므로
197
223
  성공 코드가 삭제 안전성이나 완전한 분석을 뜻하지 않는다. `resolvedIssues`도 이전 불일치가
198
224
  더 이상 관찰되지 않는다는 뜻이며, 동적 전환·추출기 변경 때문인지 한계를 함께 확인해야 한다.
225
+ `--strict`은 인자 위치와 무관하게 인식하며 두 번 이상 줄 수 없다.
199
226
 
200
227
  현재 diff는 Flutter의 Dart·Swift 문서만 받는다. 각 시점에 두 플랫폼이 모두 필요하며,
201
228
  양 시점의 `project`와 플랫폼·도구별 문서 개수가
@@ -211,6 +238,10 @@ isthmus diff \
211
238
  확인하도록 가르치는 skill 원문을 [`Skills/isthmus/SKILL.md`](Skills/isthmus/SKILL.md)에 제공한다.
212
239
  사용하는 에이전트의 프로젝트 skill 디렉터리에 이 파일을 복사해 사용할 수 있다.
213
240
 
241
+ Codex는 이 checkout의 `.agents/skills/isthmus` 링크로 같은 원문을 발견한다.
242
+ `Skills/isthmus/SKILL.md` 한 곳만 편집하며, npm 패키지에는 이 원문이 포함된다.
243
+ 스킬 내용 검증과 모델별 지침 조정 근거는 [에이전트 감사 기록](docs/AGENT-AUDIT.md)에 있다.
244
+
214
245
  ## 라이선스
215
246
 
216
247
  [MIT](LICENSE). 상업적 사용을 포함해 영구 무료다.
@@ -1,56 +1,45 @@
1
1
  ---
2
2
  name: isthmus
3
3
  description: >-
4
- Use before deleting or renaming native bridge handlers, or when tracing callers across
5
- Flutter and other cross-platform language boundaries.
4
+ Trace Flutter Dart-to-Swift bridge callers, compare bridge snapshots, or produce
5
+ cartograph retention evidence with isthmus. Use for native MethodChannel handler
6
+ changes; React Native and Kotlin extraction are not supported.
6
7
  ---
7
8
 
8
9
  # isthmus
9
10
 
10
- Native bridge calls are string-keyed, so a language-specific symbol index cannot see the
11
- whole call path. Use isthmus before changing a native handler that Dart, JavaScript, or
12
- another platform may call.
13
-
14
- ## Before deleting or renaming a bridge handler
15
-
16
- Obtain current `bridge-facts` JSON from both sides, then run:
17
-
18
- Use cartograph 0.5.3 or later for Swift and dartograph 0.1.1 or later for Dart.
19
- Build the Swift project first to create its compiler index. Run both producers against
20
- the same project root and select `cartograph bridges --target flutter --format json`.
21
- Do not fabricate a missing facts file or treat an older file as current evidence.
22
-
23
- ```bash
24
- isthmus query <channel-or-method> <bridge-facts.json> <bridge-facts.json> [more...]
25
- ```
26
-
27
- Read the entire response:
28
-
29
- - `usedBy` is the calling or channel-creation side.
30
- - `dependsOn` is the handler or channel-registration side.
31
- - `limitations` records dynamic names, stale inputs, missing symbols, or joins that were
32
- deliberately deferred.
33
- - `ambiguous` provides `qualifiedName` candidates. Query the intended candidate rather
34
- than guessing.
35
-
36
- A `found` match is evidence of a cross-language dependency, not permission to delete.
37
- A `notFound` response and exit code 64 do not prove the handler is unused. Check spelling,
38
- input freshness, dynamic-name limitations, and whether every relevant platform produced a
39
- facts file. Regenerate facts after source changes before relying on the answer.
40
-
41
- ## Feeding the result back to cartograph
42
-
43
- For Swift handlers, produce external retention evidence and use the same inputs:
44
-
45
- ```bash
46
- isthmus retentions <bridge-facts.json> <bridge-facts.json> --for cartograph \
47
- > external-retentions.json &&
48
- test -s external-retentions.json &&
49
- cartograph dead --external-retentions external-retentions.json
50
- ```
51
-
52
- Only continue when every command exits 0. A failed or empty retentions file is not evidence
53
- that a native handler is unused; remove the incomplete output and regenerate both facts files.
54
-
55
- Do not commit generated retention files when they contain local source paths unless the
56
- project has explicitly chosen to version them.
11
+ Use current bridge facts to answer the requested boundary question. This skill supplies
12
+ analysis evidence; it does not authorize source edits, deletion, publishing, or a wider audit.
13
+
14
+ ## Inputs
15
+
16
+ Use `isthmus-cli` 0.1.4+ (`isthmus` binary), cartograph 0.5.3+ and dartograph 0.1.1+.
17
+ Obtain both Dart and Swift bridge-facts JSON with identical project roots and analysis scope.
18
+ Swift production requires a built compiler index; use `cartograph bridges --target flutter --format json`.
19
+ Do not fabricate missing facts or rewrite project identifiers just to make a join pass.
20
+ If inputs are missing, identify the required files and proceed with independent authorized work.
21
+
22
+ ## Choose the requested operation
23
+
24
+ - Trace callers: `isthmus query <channel-or-method> <dart.json> <swift.json>`.
25
+ Read `usedBy`, `dependsOn`, symbol evidence, and `limitations`.
26
+ `ambiguous` returns qualified-name candidates; disambiguate from context or ask when necessary.
27
+ - Review a change: `isthmus diff --before <old-dart.json> <old-swift.json> --after <new-dart.json> <new-swift.json> --strict`.
28
+ Inspect added/removed logical methods, introduced/resolved issues, both sets of limitations,
29
+ and producer versions/timestamps. Revisions come from the caller's before/after choice.
30
+ Same-key endpoint changes and rename inference are outside this comparison.
31
+ - Supply Swift retention evidence, when requested:
32
+ `isthmus retentions <dart.json> <swift.json> --for cartograph`.
33
+ Save stdout to a new private temporary file, check successful output, then pass its path to
34
+ `cartograph dead --external-retentions <path>`. Clean up only artifacts created for this run.
35
+
36
+ ## Interpret and finish
37
+
38
+ Code 0 means the command ran successfully, not that code is safe to delete.
39
+ Code 1 from check/diff strict is a finding to report; query code 64 with
40
+ `notFound`/`ambiguous` is a usable answer, while usage errors require corrected arguments.
41
+ Code 2 indicates unreadable, invalid, or deferred inputs: explain the cause category and next step.
42
+ Empty results, `resolvedIssues`, and missing callers can reflect dynamic names or incomplete coverage.
43
+ Regenerate after source changes. Report the requested finding, relevant locations/symbols and limits.
44
+ Respect existing user authorization; ask only when missing information changes the action.
45
+ Do not commit generated facts/retentions with private project information.
@@ -15,8 +15,8 @@ export interface CommandResult {
15
15
  export declare function runCheckCommand(arguments_: readonly string[], readTextFile: ReadTextFile): Promise<CommandResult>;
16
16
  /** 입력을 순서대로 읽어 파일 수·메모리 상한 안에서 교환 문서로 파싱한다. */
17
17
  export declare function readBridgeDocuments(inputPaths: readonly string[], readTextFile: ReadTextFile): Promise<BridgeFactsDocument[]>;
18
- /** 외부 입력에서 기대하는 실패 종류인지 확인한다. */
19
- export declare function isExpectedInputError(error: unknown): boolean;
18
+ /** 알려진 입력·조인 실패를 원인별 해결 방향을 담은 코드 2 결과로 바꾼다. */
19
+ export declare function inputFailureResult(error: unknown): CommandResult | undefined;
20
20
  /** 전체 조인 보류를 깨끗한 결과와 구분하는 코드 2 결과로 바꾼다. */
21
21
  export declare function bridgeJoinDeferredError(): CommandResult;
22
22
  /** 내부 결함을 입력 탓으로 돌리지 않는 경로 없는 코드 2 결과다. */
@@ -30,48 +30,103 @@ export async function runCheckCommand(arguments_, readTextFile) {
30
30
  };
31
31
  }
32
32
  catch (error) {
33
- return isExpectedInputError(error) ? inputError() : internalError();
33
+ return inputFailureResult(error) ?? internalError();
34
34
  }
35
35
  }
36
36
  /** 입력을 순서대로 읽어 파일 수·메모리 상한 안에서 교환 문서로 파싱한다. */
37
37
  export async function readBridgeDocuments(inputPaths, readTextFile) {
38
38
  const documents = [];
39
39
  let totalTextLength = 0;
40
- for (const path of inputPaths) {
40
+ for (const [index, path] of inputPaths.entries()) {
41
+ const inputPosition = index + 1;
41
42
  let text;
42
43
  try {
43
44
  text = await readTextFile(path);
44
45
  }
45
46
  catch {
46
- throw new BridgeInputError();
47
+ throw new BridgeInputReadError(inputPosition);
47
48
  }
48
49
  totalTextLength += text.length;
49
50
  if (text.length > MAX_INPUT_TEXT_LENGTH ||
50
51
  totalTextLength > MAX_TOTAL_INPUT_TEXT_LENGTH) {
51
- throw new BridgeInputLimitError();
52
+ throw new BridgeInputLimitError(inputPosition);
52
53
  }
53
54
  try {
54
55
  documents.push(parseBridgeFactsDocument(JSON.parse(text)));
55
56
  }
56
57
  catch (error) {
57
- if (error instanceof SyntaxError ||
58
- error instanceof BridgeFactsValidationError) {
59
- throw new BridgeInputError();
58
+ if (error instanceof SyntaxError) {
59
+ throw new BridgeInputJsonError(inputPosition);
60
+ }
61
+ if (error instanceof BridgeFactsValidationError) {
62
+ throw new BridgeInputContractError(inputPosition, error.message);
60
63
  }
61
64
  throw error;
62
65
  }
63
66
  }
64
67
  return documents;
65
68
  }
66
- /** 입력 텍스트가 CLI 메모리 예산을 넘었음을 나타낸다. */
69
+ /** 실패한 입력의 1부터 시작하는 순서를 보존하는 입력 오류다. */
67
70
  class BridgeInputError extends Error {
71
+ inputPosition;
72
+ constructor(name, inputPosition) {
73
+ super(`${name} at input ${inputPosition}`);
74
+ this.name = name;
75
+ this.inputPosition = inputPosition;
76
+ }
77
+ }
78
+ /** 입력 파일을 읽지 못한 경우를 구분한다. */
79
+ class BridgeInputReadError extends BridgeInputError {
80
+ constructor(inputPosition) {
81
+ super('BridgeInputReadError', inputPosition);
82
+ }
83
+ }
84
+ /** 입력 텍스트가 JSON이 아닌 경우를 구분한다. */
85
+ class BridgeInputJsonError extends BridgeInputError {
86
+ constructor(inputPosition) {
87
+ super('BridgeInputJsonError', inputPosition);
88
+ }
89
+ }
90
+ /** 입력 문서가 교환 계약을 어긴 경우와 그 이유를 구분한다. */
91
+ class BridgeInputContractError extends BridgeInputError {
92
+ reason;
93
+ constructor(inputPosition, reason) {
94
+ super('BridgeInputContractError', inputPosition);
95
+ this.reason = reason;
96
+ }
68
97
  }
69
98
  /** 입력 텍스트의 크기만 계약을 넘은 경우를 구분한다. */
70
99
  class BridgeInputLimitError extends BridgeInputError {
100
+ constructor(inputPosition) {
101
+ super('BridgeInputLimitError', inputPosition);
102
+ }
103
+ }
104
+ /** 알려진 입력·조인 실패를 원인별 해결 방향을 담은 코드 2 결과로 바꾼다. */
105
+ export function inputFailureResult(error) {
106
+ if (error instanceof BridgeInputReadError) {
107
+ return inputFailure(`Unable to read bridge facts input ${error.inputPosition}; `
108
+ + 'check that the file exists and is readable.\n');
109
+ }
110
+ if (error instanceof BridgeInputJsonError) {
111
+ return inputFailure(`Bridge facts input ${error.inputPosition} is not valid JSON; `
112
+ + 'regenerate it with a bridge-facts producer.\n');
113
+ }
114
+ if (error instanceof BridgeInputContractError) {
115
+ return inputFailure(`Bridge facts input ${error.inputPosition} violates the bridge-facts `
116
+ + `contract: ${error.reason}\n`);
117
+ }
118
+ if (error instanceof BridgeInputLimitError) {
119
+ return inputFailure(`Bridge facts input ${error.inputPosition} exceeds the input size limits; `
120
+ + 'split the extraction into smaller documents.\n');
121
+ }
122
+ if (error instanceof BridgeJoinValidationError) {
123
+ return inputFailure(`${error.message}\n`);
124
+ }
125
+ return undefined;
71
126
  }
72
- /** 외부 입력에서 기대하는 실패 종류인지 확인한다. */
73
- export function isExpectedInputError(error) {
74
- return error instanceof BridgeInputError || error instanceof BridgeJoinValidationError;
127
+ /** 원인 메시지만 stdout 없이 코드 2로 내보낸다. */
128
+ function inputFailure(standardError) {
129
+ return { standardOutput: '', standardError, exitCode: 2 };
75
130
  }
76
131
  /** 전체 조인 보류를 깨끗한 결과와 구분하는 코드 2 결과로 바꾼다. */
77
132
  export function bridgeJoinDeferredError() {
@@ -81,14 +136,6 @@ export function bridgeJoinDeferredError() {
81
136
  exitCode: 2,
82
137
  };
83
138
  }
84
- /** 파일·JSON·계약 오류를 민감정보 없는 코드 2 결과로 바꾼다. */
85
- function inputError() {
86
- return {
87
- standardOutput: '',
88
- standardError: 'Unable to read or validate bridge facts; check the input files.\n',
89
- exitCode: 2,
90
- };
91
- }
92
139
  /** 내부 결함을 입력 탓으로 돌리지 않는 경로 없는 코드 2 결과다. */
93
140
  export function internalError() {
94
141
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"check-command.js","sourceRoot":"","sources":["../../src/cli/check-command.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BridgeFactsValidationError,\n parseBridgeFactsDocument,\n type BridgeFactsDocument,\n} from '../exchange/parse.ts';\nimport {\n BridgeJoinValidationError,\n isBridgeJoinDeferred,\n joinBridgeDocuments,\n MAX_DOCUMENTS_PER_JOIN,\n} from '../join/join.ts';\nimport { createCheckReport, encodeCheckReport } from '../report/check-report.ts';\n\n/** 파일 경로를 받아 UTF-8 텍스트를 읽는 주입 경계다. */\nexport type ReadTextFile = (path: string) => Promise<string>;\n\n/** 한 입력 파일에서 허용하는 최대 UTF-16 문자열 길이다. */\nexport const MAX_INPUT_TEXT_LENGTH = 16 * 1024 * 1024;\n\n/** 한 명령에서 허용하는 전체 UTF-16 입력 문자열 길이다. */\nexport const MAX_TOTAL_INPUT_TEXT_LENGTH = 64 * 1024 * 1024;\n\n/** CLI가 프로세스 경계에 쓸 출력과 종료 코드다. */\nexport interface CommandResult {\n readonly standardOutput: string;\n readonly standardError: string;\n readonly exitCode: 0 | 1 | 2 | 64;\n}\n\n/** check 인자를 실행해 프로세스에 독립적인 결과를 반환한다. */\nexport async function runCheckCommand(\n arguments_: readonly string[],\n readTextFile: ReadTextFile,\n): Promise<CommandResult> {\n if (arguments_[0] !== 'check') return usageError();\n const options = arguments_.slice(1).filter((argument) => argument.startsWith('-'));\n if (options.some((option) => option !== '--strict')) return usageError();\n const isStrict = arguments_.includes('--strict');\n const inputPaths = arguments_.slice(1).filter((argument) => argument !== '--strict');\n if (inputPaths.length < 2 || inputPaths.length > MAX_DOCUMENTS_PER_JOIN) {\n return usageError();\n }\n try {\n const documents = await readBridgeDocuments(inputPaths, readTextFile);\n const joined = joinBridgeDocuments(documents);\n if (isBridgeJoinDeferred(joined)) return bridgeJoinDeferredError();\n const report = createCheckReport(joined);\n return {\n standardOutput: encodeCheckReport(report),\n standardError: '',\n exitCode: isStrict && report.summary.errors > 0 ? 1 : 0,\n };\n } catch (error) {\n return isExpectedInputError(error) ? inputError() : internalError();\n }\n}\n\n/** 입력을 순서대로 읽어 파일 수·메모리 상한 안에서 교환 문서로 파싱한다. */\nexport async function readBridgeDocuments(\n inputPaths: readonly string[],\n readTextFile: ReadTextFile,\n): Promise<BridgeFactsDocument[]> {\n const documents: BridgeFactsDocument[] = [];\n let totalTextLength = 0;\n for (const path of inputPaths) {\n let text: string;\n try {\n text = await readTextFile(path);\n } catch {\n throw new BridgeInputError();\n }\n totalTextLength += text.length;\n if (\n text.length > MAX_INPUT_TEXT_LENGTH ||\n totalTextLength > MAX_TOTAL_INPUT_TEXT_LENGTH\n ) {\n throw new BridgeInputLimitError();\n }\n try {\n documents.push(parseBridgeFactsDocument(JSON.parse(text)));\n } catch (error) {\n if (\n error instanceof SyntaxError ||\n error instanceof BridgeFactsValidationError\n ) {\n throw new BridgeInputError();\n }\n throw error;\n }\n }\n return documents;\n}\n\n/** 입력 텍스트가 CLI 메모리 예산을 넘었음을 나타낸다. */\nclass BridgeInputError extends Error {}\n\n/** 입력 텍스트의 크기만 계약을 넘은 경우를 구분한다. */\nclass BridgeInputLimitError extends BridgeInputError {}\n\n/** 외부 입력에서 기대하는 실패 종류인지 확인한다. */\nexport function isExpectedInputError(error: unknown): boolean {\n return error instanceof BridgeInputError || error instanceof BridgeJoinValidationError;\n}\n\n/** 전체 조인 보류를 깨끗한 결과와 구분하는 코드 2 결과로 바꾼다. */\nexport function bridgeJoinDeferredError(): CommandResult {\n return {\n standardOutput: '',\n standardError:\n 'Bridge facts could not be joined; split mixed bridge targets and retry.\\n',\n exitCode: 2,\n };\n}\n\n/** 파일·JSON·계약 오류를 민감정보 없는 코드 2 결과로 바꾼다. */\nfunction inputError(): CommandResult {\n return {\n standardOutput: '',\n standardError:\n 'Unable to read or validate bridge facts; check the input files.\\n',\n exitCode: 2,\n };\n}\n\n/** 내부 결함을 입력 탓으로 돌리지 않는 경로 없는 코드 2 결과다. */\nexport function internalError(): CommandResult {\n return {\n standardOutput: '',\n standardError: 'Internal isthmus error; retry with a current version.\\n',\n exitCode: 2,\n };\n}\n\n/** 잘못된 CLI 호출을 경로 없는 사용법과 코드 64로 바꾼다. */\nfunction usageError(): CommandResult {\n return {\n standardOutput: '',\n standardError: `${checkUsage}\\n`,\n exitCode: 64,\n };\n}\n\n/** check 명령의 한 줄 사용법이다. */\nexport const checkUsage =\n 'Usage: isthmus check <bridge-facts.json> <bridge-facts.json> '\n + '[more...] [--strict]';\n"]}
1
+ {"version":3,"file":"check-command.js","sourceRoot":"","sources":["../../src/cli/check-command.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BridgeFactsValidationError,\n parseBridgeFactsDocument,\n type BridgeFactsDocument,\n} from '../exchange/parse.ts';\nimport {\n BridgeJoinValidationError,\n isBridgeJoinDeferred,\n joinBridgeDocuments,\n MAX_DOCUMENTS_PER_JOIN,\n} from '../join/join.ts';\nimport { createCheckReport, encodeCheckReport } from '../report/check-report.ts';\n\n/** 파일 경로를 받아 UTF-8 텍스트를 읽는 주입 경계다. */\nexport type ReadTextFile = (path: string) => Promise<string>;\n\n/** 한 입력 파일에서 허용하는 최대 UTF-16 문자열 길이다. */\nexport const MAX_INPUT_TEXT_LENGTH = 16 * 1024 * 1024;\n\n/** 한 명령에서 허용하는 전체 UTF-16 입력 문자열 길이다. */\nexport const MAX_TOTAL_INPUT_TEXT_LENGTH = 64 * 1024 * 1024;\n\n/** CLI가 프로세스 경계에 쓸 출력과 종료 코드다. */\nexport interface CommandResult {\n readonly standardOutput: string;\n readonly standardError: string;\n readonly exitCode: 0 | 1 | 2 | 64;\n}\n\n/** check 인자를 실행해 프로세스에 독립적인 결과를 반환한다. */\nexport async function runCheckCommand(\n arguments_: readonly string[],\n readTextFile: ReadTextFile,\n): Promise<CommandResult> {\n if (arguments_[0] !== 'check') return usageError();\n const options = arguments_.slice(1).filter((argument) => argument.startsWith('-'));\n if (options.some((option) => option !== '--strict')) return usageError();\n const isStrict = arguments_.includes('--strict');\n const inputPaths = arguments_.slice(1).filter((argument) => argument !== '--strict');\n if (inputPaths.length < 2 || inputPaths.length > MAX_DOCUMENTS_PER_JOIN) {\n return usageError();\n }\n try {\n const documents = await readBridgeDocuments(inputPaths, readTextFile);\n const joined = joinBridgeDocuments(documents);\n if (isBridgeJoinDeferred(joined)) return bridgeJoinDeferredError();\n const report = createCheckReport(joined);\n return {\n standardOutput: encodeCheckReport(report),\n standardError: '',\n exitCode: isStrict && report.summary.errors > 0 ? 1 : 0,\n };\n } catch (error) {\n return inputFailureResult(error) ?? internalError();\n }\n}\n\n/** 입력을 순서대로 읽어 파일 수·메모리 상한 안에서 교환 문서로 파싱한다. */\nexport async function readBridgeDocuments(\n inputPaths: readonly string[],\n readTextFile: ReadTextFile,\n): Promise<BridgeFactsDocument[]> {\n const documents: BridgeFactsDocument[] = [];\n let totalTextLength = 0;\n for (const [index, path] of inputPaths.entries()) {\n const inputPosition = index + 1;\n let text: string;\n try {\n text = await readTextFile(path);\n } catch {\n throw new BridgeInputReadError(inputPosition);\n }\n totalTextLength += text.length;\n if (\n text.length > MAX_INPUT_TEXT_LENGTH ||\n totalTextLength > MAX_TOTAL_INPUT_TEXT_LENGTH\n ) {\n throw new BridgeInputLimitError(inputPosition);\n }\n try {\n documents.push(parseBridgeFactsDocument(JSON.parse(text)));\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new BridgeInputJsonError(inputPosition);\n }\n if (error instanceof BridgeFactsValidationError) {\n throw new BridgeInputContractError(inputPosition, error.message);\n }\n throw error;\n }\n }\n return documents;\n}\n\n/** 실패한 입력의 1부터 시작하는 순서를 보존하는 입력 오류다. */\nclass BridgeInputError extends Error {\n readonly inputPosition: number;\n\n constructor(name: string, inputPosition: number) {\n super(`${name} at input ${inputPosition}`);\n this.name = name;\n this.inputPosition = inputPosition;\n }\n}\n\n/** 입력 파일을 읽지 못한 경우를 구분한다. */\nclass BridgeInputReadError extends BridgeInputError {\n constructor(inputPosition: number) {\n super('BridgeInputReadError', inputPosition);\n }\n}\n\n/** 입력 텍스트가 JSON이 아닌 경우를 구분한다. */\nclass BridgeInputJsonError extends BridgeInputError {\n constructor(inputPosition: number) {\n super('BridgeInputJsonError', inputPosition);\n }\n}\n\n/** 입력 문서가 교환 계약을 어긴 경우와 그 이유를 구분한다. */\nclass BridgeInputContractError extends BridgeInputError {\n readonly reason: string;\n\n constructor(inputPosition: number, reason: string) {\n super('BridgeInputContractError', inputPosition);\n this.reason = reason;\n }\n}\n\n/** 입력 텍스트의 크기만 계약을 넘은 경우를 구분한다. */\nclass BridgeInputLimitError extends BridgeInputError {\n constructor(inputPosition: number) {\n super('BridgeInputLimitError', inputPosition);\n }\n}\n\n/** 알려진 입력·조인 실패를 원인별 해결 방향을 담은 코드 2 결과로 바꾼다. */\nexport function inputFailureResult(error: unknown): CommandResult | undefined {\n if (error instanceof BridgeInputReadError) {\n return inputFailure(\n `Unable to read bridge facts input ${error.inputPosition}; `\n + 'check that the file exists and is readable.\\n',\n );\n }\n if (error instanceof BridgeInputJsonError) {\n return inputFailure(\n `Bridge facts input ${error.inputPosition} is not valid JSON; `\n + 'regenerate it with a bridge-facts producer.\\n',\n );\n }\n if (error instanceof BridgeInputContractError) {\n return inputFailure(\n `Bridge facts input ${error.inputPosition} violates the bridge-facts `\n + `contract: ${error.reason}\\n`,\n );\n }\n if (error instanceof BridgeInputLimitError) {\n return inputFailure(\n `Bridge facts input ${error.inputPosition} exceeds the input size limits; `\n + 'split the extraction into smaller documents.\\n',\n );\n }\n if (error instanceof BridgeJoinValidationError) {\n return inputFailure(`${error.message}\\n`);\n }\n return undefined;\n}\n\n/** 원인 메시지만 stdout 없이 코드 2로 내보낸다. */\nfunction inputFailure(standardError: string): CommandResult {\n return { standardOutput: '', standardError, exitCode: 2 };\n}\n\n/** 전체 조인 보류를 깨끗한 결과와 구분하는 코드 2 결과로 바꾼다. */\nexport function bridgeJoinDeferredError(): CommandResult {\n return {\n standardOutput: '',\n standardError:\n 'Bridge facts could not be joined; split mixed bridge targets and retry.\\n',\n exitCode: 2,\n };\n}\n\n/** 내부 결함을 입력 탓으로 돌리지 않는 경로 없는 코드 2 결과다. */\nexport function internalError(): CommandResult {\n return {\n standardOutput: '',\n standardError: 'Internal isthmus error; retry with a current version.\\n',\n exitCode: 2,\n };\n}\n\n/** 잘못된 CLI 호출을 경로 없는 사용법과 코드 64로 바꾼다. */\nfunction usageError(): CommandResult {\n return {\n standardOutput: '',\n standardError: `${checkUsage}\\n`,\n exitCode: 64,\n };\n}\n\n/** check 명령의 한 줄 사용법이다. */\nexport const checkUsage =\n 'Usage: isthmus check <bridge-facts.json> <bridge-facts.json> '\n + '[more...] [--strict]';\n"]}
@@ -1,17 +1,22 @@
1
- import { BridgeJoinValidationError, MAX_DOCUMENTS_PER_JOIN } from "../join/join.js";
1
+ import { MAX_DOCUMENTS_PER_JOIN } from "../join/join.js";
2
2
  import { createBridgeDiff } from "../report/diff.js";
3
3
  import { encodeSortedJson } from "../report/sorted-json.js";
4
- import { internalError, isExpectedInputError, readBridgeDocuments } from "./check-command.js";
4
+ import { internalError, inputFailureResult, readBridgeDocuments, } from "./check-command.js";
5
5
  /** 전후 교환 파일을 하나의 입력 예산으로 읽어 새 경계 오류만 CI 실패로 표시한다. */
6
6
  export async function runDiffCommand(arguments_, readTextFile) {
7
- const strict = arguments_.at(-1) === '--strict';
8
- const args = strict ? arguments_.slice(0, -1) : arguments_;
7
+ const strictFlags = arguments_.filter((argument) => argument === '--strict');
8
+ const args = arguments_.filter((argument) => argument !== '--strict');
9
9
  const separator = args.indexOf('--after');
10
10
  const beforePaths = args.slice(2, separator);
11
11
  const afterPaths = args.slice(separator + 1);
12
12
  const paths = [...beforePaths, ...afterPaths];
13
- if (args[0] !== 'diff' || args[1] !== '--before' || separator < 4 ||
14
- beforePaths.length < 2 || afterPaths.length < 2 || paths.length > MAX_DOCUMENTS_PER_JOIN ||
13
+ if (args[0] !== 'diff' ||
14
+ args[1] !== '--before' ||
15
+ strictFlags.length > 1 ||
16
+ separator < 4 ||
17
+ beforePaths.length < 2 ||
18
+ afterPaths.length < 2 ||
19
+ paths.length > MAX_DOCUMENTS_PER_JOIN ||
15
20
  paths.some((path) => path.trim().length === 0 || path.startsWith('-'))) {
16
21
  return { standardOutput: '', standardError: `${diffUsage}\n`, exitCode: 64 };
17
22
  }
@@ -21,16 +26,11 @@ export async function runDiffCommand(arguments_, readTextFile) {
21
26
  return {
22
27
  standardOutput: encodeSortedJson(report),
23
28
  standardError: '',
24
- exitCode: strict && report.summary.introducedErrors > 0 ? 1 : 0,
29
+ exitCode: strictFlags.length === 1 && report.summary.introducedErrors > 0 ? 1 : 0,
25
30
  };
26
31
  }
27
32
  catch (error) {
28
- if (error instanceof BridgeJoinValidationError) {
29
- return { standardOutput: '', standardError: 'Unable to compare bridge facts; use the same project and Flutter Dart/Swift producer inventory without mixed targets in both snapshots.\n', exitCode: 2 };
30
- }
31
- return isExpectedInputError(error)
32
- ? { standardOutput: '', standardError: 'Unable to read or validate bridge facts; check the input files.\n', exitCode: 2 }
33
- : internalError();
33
+ return inputFailureResult(error) ?? internalError();
34
34
  }
35
35
  }
36
36
  /** 각 snapshot은 caller와 receiver 문서를 함께 제공해야 한다. */
@@ -1 +1 @@
1
- {"version":3,"file":"diff-command.js","sourceRoot":"","sources":["../../src/cli/diff-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACpF,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,mBAAmB,EAAyC,MAAM,oBAAoB,CAAC;AAErI,qDAAqD;AACrD,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,UAA6B,EAAE,YAA0B;IAC5F,MAAM,MAAM,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC;IAChD,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;IAC3D,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC1C,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,CAAC,GAAG,WAAW,EAAE,GAAG,UAAU,CAAC,CAAC;IAC9C,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,UAAU,IAAI,SAAS,GAAG,CAAC;QAC/D,WAAW,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,sBAAsB;QACxF,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QACzE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,aAAa,EAAE,GAAG,SAAS,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC/E,CAAC;IACD,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;QACjE,MAAM,MAAM,GAAG,gBAAgB,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7G,OAAO;YACL,cAAc,EAAE,gBAAgB,CAAC,MAAM,CAAC;YACxC,aAAa,EAAE,EAAE;YACjB,QAAQ,EAAE,MAAM,IAAI,MAAM,CAAC,OAAO,CAAC,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SAChE,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,yBAAyB,EAAE,CAAC;YAC/C,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,aAAa,EAAE,2IAA2I,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QACzM,CAAC;QACD,OAAO,oBAAoB,CAAC,KAAK,CAAC;YAChC,CAAC,CAAC,EAAE,cAAc,EAAE,EAAE,EAAE,aAAa,EAAE,mEAAmE,EAAE,QAAQ,EAAE,CAAC,EAAE;YACzH,CAAC,CAAC,aAAa,EAAE,CAAC;IACtB,CAAC;AACH,CAAC;AAED,mDAAmD;AACnD,MAAM,CAAC,MAAM,SAAS,GAAG,kEAAkE;MACvF,uDAAuD,CAAC","sourcesContent":["import { BridgeJoinValidationError, MAX_DOCUMENTS_PER_JOIN } from '../join/join.ts';\nimport { createBridgeDiff } from '../report/diff.ts';\nimport { encodeSortedJson } from '../report/sorted-json.ts';\nimport { internalError, isExpectedInputError, readBridgeDocuments, type CommandResult, type ReadTextFile } from './check-command.ts';\n\n/** 전후 교환 파일을 하나의 입력 예산으로 읽어 새 경계 오류만 CI 실패로 표시한다. */\nexport async function runDiffCommand(arguments_: readonly string[], readTextFile: ReadTextFile): Promise<CommandResult> {\n const strict = arguments_.at(-1) === '--strict';\n const args = strict ? arguments_.slice(0, -1) : arguments_;\n const separator = args.indexOf('--after');\n const beforePaths = args.slice(2, separator);\n const afterPaths = args.slice(separator + 1);\n const paths = [...beforePaths, ...afterPaths];\n if (args[0] !== 'diff' || args[1] !== '--before' || separator < 4 ||\n beforePaths.length < 2 || afterPaths.length < 2 || paths.length > MAX_DOCUMENTS_PER_JOIN ||\n paths.some((path) => path.trim().length === 0 || path.startsWith('-'))) {\n return { standardOutput: '', standardError: `${diffUsage}\\n`, exitCode: 64 };\n }\n try {\n const documents = await readBridgeDocuments(paths, readTextFile);\n const report = createBridgeDiff(documents.slice(0, beforePaths.length), documents.slice(beforePaths.length));\n return {\n standardOutput: encodeSortedJson(report),\n standardError: '',\n exitCode: strict && report.summary.introducedErrors > 0 ? 1 : 0,\n };\n } catch (error) {\n if (error instanceof BridgeJoinValidationError) {\n return { standardOutput: '', standardError: 'Unable to compare bridge facts; use the same project and Flutter Dart/Swift producer inventory without mixed targets in both snapshots.\\n', exitCode: 2 };\n }\n return isExpectedInputError(error)\n ? { standardOutput: '', standardError: 'Unable to read or validate bridge facts; check the input files.\\n', exitCode: 2 }\n : internalError();\n }\n}\n\n/** 각 snapshot은 caller와 receiver 문서를 함께 제공해야 한다. */\nexport const diffUsage = 'Usage: isthmus diff --before <dart.json> <swift.json> [more...] '\n + '--after <dart.json> <swift.json> [more...] [--strict]';\n"]}
1
+ {"version":3,"file":"diff-command.js","sourceRoot":"","sources":["../../src/cli/diff-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,mBAAmB,GAGpB,MAAM,oBAAoB,CAAC;AAE5B,qDAAqD;AACrD,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,UAA6B,EAC7B,YAA0B;IAE1B,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC;IAC7E,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC;IACtE,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC1C,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,CAAC,GAAG,WAAW,EAAE,GAAG,UAAU,CAAC,CAAC;IAC9C,IACE,IAAI,CAAC,CAAC,CAAC,KAAK,MAAM;QAClB,IAAI,CAAC,CAAC,CAAC,KAAK,UAAU;QACtB,WAAW,CAAC,MAAM,GAAG,CAAC;QACtB,SAAS,GAAG,CAAC;QACb,WAAW,CAAC,MAAM,GAAG,CAAC;QACtB,UAAU,CAAC,MAAM,GAAG,CAAC;QACrB,KAAK,CAAC,MAAM,GAAG,sBAAsB;QACrC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EACtE,CAAC;QACD,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,aAAa,EAAE,GAAG,SAAS,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC/E,CAAC;IACD,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;QACjE,MAAM,MAAM,GAAG,gBAAgB,CAC7B,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,EACtC,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CACpC,CAAC;QACF,OAAO;YACL,cAAc,EAAE,gBAAgB,CAAC,MAAM,CAAC;YACxC,aAAa,EAAE,EAAE;YACjB,QAAQ,EAAE,WAAW,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SAClF,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,kBAAkB,CAAC,KAAK,CAAC,IAAI,aAAa,EAAE,CAAC;IACtD,CAAC;AACH,CAAC;AAED,mDAAmD;AACnD,MAAM,CAAC,MAAM,SAAS,GACpB,kEAAkE;MAChE,uDAAuD,CAAC","sourcesContent":["import { MAX_DOCUMENTS_PER_JOIN } from '../join/join.ts';\nimport { createBridgeDiff } from '../report/diff.ts';\nimport { encodeSortedJson } from '../report/sorted-json.ts';\nimport {\n internalError,\n inputFailureResult,\n readBridgeDocuments,\n type CommandResult,\n type ReadTextFile,\n} from './check-command.ts';\n\n/** 전후 교환 파일을 하나의 입력 예산으로 읽어 새 경계 오류만 CI 실패로 표시한다. */\nexport async function runDiffCommand(\n arguments_: readonly string[],\n readTextFile: ReadTextFile,\n): Promise<CommandResult> {\n const strictFlags = arguments_.filter((argument) => argument === '--strict');\n const args = arguments_.filter((argument) => argument !== '--strict');\n const separator = args.indexOf('--after');\n const beforePaths = args.slice(2, separator);\n const afterPaths = args.slice(separator + 1);\n const paths = [...beforePaths, ...afterPaths];\n if (\n args[0] !== 'diff' ||\n args[1] !== '--before' ||\n strictFlags.length > 1 ||\n separator < 4 ||\n beforePaths.length < 2 ||\n afterPaths.length < 2 ||\n paths.length > MAX_DOCUMENTS_PER_JOIN ||\n paths.some((path) => path.trim().length === 0 || path.startsWith('-'))\n ) {\n return { standardOutput: '', standardError: `${diffUsage}\\n`, exitCode: 64 };\n }\n try {\n const documents = await readBridgeDocuments(paths, readTextFile);\n const report = createBridgeDiff(\n documents.slice(0, beforePaths.length),\n documents.slice(beforePaths.length),\n );\n return {\n standardOutput: encodeSortedJson(report),\n standardError: '',\n exitCode: strictFlags.length === 1 && report.summary.introducedErrors > 0 ? 1 : 0,\n };\n } catch (error) {\n return inputFailureResult(error) ?? internalError();\n }\n}\n\n/** 각 snapshot은 caller와 receiver 문서를 함께 제공해야 한다. */\nexport const diffUsage =\n 'Usage: isthmus diff --before <dart.json> <swift.json> [more...] '\n + '--after <dart.json> <swift.json> [more...] [--strict]';\n"]}
@@ -1,6 +1,6 @@
1
1
  import { isBridgeJoinDeferred, joinBridgeDocuments, MAX_DOCUMENTS_PER_JOIN, } from "../join/join.js";
2
2
  import { BridgeGraphLimitError, BridgeGraphValidationError, createBridgeGraph, renderBridgeGraph, } from "../report/graph.js";
3
- import { bridgeJoinDeferredError, internalError, isExpectedInputError, readBridgeDocuments, } from "./check-command.js";
3
+ import { bridgeJoinDeferredError, internalError, inputFailureResult, readBridgeDocuments, } from "./check-command.js";
4
4
  /** graph 인자를 실행해 경계 그래프와 종료 코드를 반환한다. */
5
5
  export async function runGraphCommand(arguments_, readTextFile) {
6
6
  const options = parseGraphArguments(arguments_);
@@ -19,11 +19,15 @@ export async function runGraphCommand(arguments_, readTextFile) {
19
19
  };
20
20
  }
21
21
  catch (error) {
22
- return isExpectedInputError(error) ||
23
- error instanceof BridgeGraphLimitError ||
24
- error instanceof BridgeGraphValidationError
25
- ? graphInputError()
26
- : internalError();
22
+ if (error instanceof BridgeGraphLimitError ||
23
+ error instanceof BridgeGraphValidationError) {
24
+ return {
25
+ standardOutput: '',
26
+ standardError: `${error.message}\n`,
27
+ exitCode: 2,
28
+ };
29
+ }
30
+ return inputFailureResult(error) ?? internalError();
27
31
  }
28
32
  }
29
33
  /** graph의 입력 파일과 선택 출력 형식을 검증한다. */
@@ -56,14 +60,6 @@ function graphUsageError() {
56
60
  exitCode: 64,
57
61
  };
58
62
  }
59
- /** graph 입력 실패를 경로 없는 코드 2로 바꾼다. */
60
- function graphInputError() {
61
- return {
62
- standardOutput: '',
63
- standardError: 'Unable to read or validate bridge facts; check the input files.\n',
64
- exitCode: 2,
65
- };
66
- }
67
63
  /** graph 명령의 한 줄 사용법이다. */
68
64
  export const graphUsage = 'Usage: isthmus graph <bridge-facts.json> <bridge-facts.json> '
69
65
  + '[more...] [--format json|dot|mermaid]';
@@ -1 +1 @@
1
- {"version":3,"file":"graph-command.js","sourceRoot":"","sources":["../../src/cli/graph-command.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n isBridgeJoinDeferred,\n joinBridgeDocuments,\n MAX_DOCUMENTS_PER_JOIN,\n} from '../join/join.ts';\nimport {\n BridgeGraphLimitError,\n BridgeGraphValidationError,\n createBridgeGraph,\n renderBridgeGraph,\n} from '../report/graph.ts';\nimport {\n bridgeJoinDeferredError,\n internalError,\n isExpectedInputError,\n readBridgeDocuments,\n type CommandResult,\n type ReadTextFile,\n} from './check-command.ts';\n\n/** graph 인자를 실행해 경계 그래프와 종료 코드를 반환한다. */\nexport async function runGraphCommand(\n arguments_: readonly string[],\n readTextFile: ReadTextFile,\n): Promise<CommandResult> {\n const options = parseGraphArguments(arguments_);\n if (options === undefined) return graphUsageError();\n try {\n const documents = await readBridgeDocuments(options.inputPaths, readTextFile);\n const joined = joinBridgeDocuments(documents);\n if (isBridgeJoinDeferred(joined)) return bridgeJoinDeferredError();\n const graph = createBridgeGraph(joined);\n return {\n standardOutput: renderBridgeGraph(graph, options.format),\n standardError: '',\n exitCode: 0,\n };\n } catch (error) {\n return isExpectedInputError(error) ||\n error instanceof BridgeGraphLimitError ||\n error instanceof BridgeGraphValidationError\n ? graphInputError()\n : internalError();\n }\n}\n\n/** graph의 입력 파일과 선택 출력 형식을 검증한다. */\nfunction parseGraphArguments(arguments_: readonly string[]): GraphOptions | undefined {\n if (arguments_[0] !== 'graph') return undefined;\n const formatIndex = arguments_.indexOf('--format');\n const inputPaths = arguments_.slice(1, formatIndex < 0 ? undefined : formatIndex);\n if (\n inputPaths.length < 2 ||\n inputPaths.length > MAX_DOCUMENTS_PER_JOIN ||\n inputPaths.some((path) => path.startsWith('-'))\n ) {\n return undefined;\n }\n if (formatIndex < 0) return { inputPaths, format: 'json' };\n if (formatIndex !== arguments_.length - 2) return undefined;\n const format = arguments_[formatIndex + 1];\n return isGraphFormat(format) ? { inputPaths, format } : undefined;\n}\n\n/** 지원하는 그래프 형식인지 확인한다. */\nfunction isGraphFormat(value: string | undefined): value is GraphFormat {\n return value === 'json' || value === 'dot' || value === 'mermaid';\n}\n\n/** graph 사용 오류를 경로 없는 코드 64로 바꾼다. */\nfunction graphUsageError(): CommandResult {\n return {\n standardOutput: '',\n standardError: `${graphUsage}\\n`,\n exitCode: 64,\n };\n}\n\n/** graph 입력 실패를 경로 없는 코드 2로 바꾼다. */\nfunction graphInputError(): CommandResult {\n return {\n standardOutput: '',\n standardError:\n 'Unable to read or validate bridge facts; check the input files.\\n',\n exitCode: 2,\n };\n}\n\n/** 검증된 graph 명령 옵션이다. */\ninterface GraphOptions {\n readonly inputPaths: readonly string[];\n readonly format: GraphFormat;\n}\n\ntype GraphFormat = 'json' | 'dot' | 'mermaid';\n\n/** graph 명령의 한 줄 사용법이다. */\nexport const graphUsage =\n 'Usage: isthmus graph <bridge-facts.json> <bridge-facts.json> '\n + '[more...] [--format json|dot|mermaid]';\n"]}
1
+ {"version":3,"file":"graph-command.js","sourceRoot":"","sources":["../../src/cli/graph-command.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n isBridgeJoinDeferred,\n joinBridgeDocuments,\n MAX_DOCUMENTS_PER_JOIN,\n} from '../join/join.ts';\nimport {\n BridgeGraphLimitError,\n BridgeGraphValidationError,\n createBridgeGraph,\n renderBridgeGraph,\n} from '../report/graph.ts';\nimport {\n bridgeJoinDeferredError,\n internalError,\n inputFailureResult,\n readBridgeDocuments,\n type CommandResult,\n type ReadTextFile,\n} from './check-command.ts';\n\n/** graph 인자를 실행해 경계 그래프와 종료 코드를 반환한다. */\nexport async function runGraphCommand(\n arguments_: readonly string[],\n readTextFile: ReadTextFile,\n): Promise<CommandResult> {\n const options = parseGraphArguments(arguments_);\n if (options === undefined) return graphUsageError();\n try {\n const documents = await readBridgeDocuments(options.inputPaths, readTextFile);\n const joined = joinBridgeDocuments(documents);\n if (isBridgeJoinDeferred(joined)) return bridgeJoinDeferredError();\n const graph = createBridgeGraph(joined);\n return {\n standardOutput: renderBridgeGraph(graph, options.format),\n standardError: '',\n exitCode: 0,\n };\n } catch (error) {\n if (\n error instanceof BridgeGraphLimitError ||\n error instanceof BridgeGraphValidationError\n ) {\n return {\n standardOutput: '',\n standardError: `${error.message}\\n`,\n exitCode: 2,\n };\n }\n return inputFailureResult(error) ?? internalError();\n }\n}\n\n/** graph의 입력 파일과 선택 출력 형식을 검증한다. */\nfunction parseGraphArguments(arguments_: readonly string[]): GraphOptions | undefined {\n if (arguments_[0] !== 'graph') return undefined;\n const formatIndex = arguments_.indexOf('--format');\n const inputPaths = arguments_.slice(1, formatIndex < 0 ? undefined : formatIndex);\n if (\n inputPaths.length < 2 ||\n inputPaths.length > MAX_DOCUMENTS_PER_JOIN ||\n inputPaths.some((path) => path.startsWith('-'))\n ) {\n return undefined;\n }\n if (formatIndex < 0) return { inputPaths, format: 'json' };\n if (formatIndex !== arguments_.length - 2) return undefined;\n const format = arguments_[formatIndex + 1];\n return isGraphFormat(format) ? { inputPaths, format } : undefined;\n}\n\n/** 지원하는 그래프 형식인지 확인한다. */\nfunction isGraphFormat(value: string | undefined): value is GraphFormat {\n return value === 'json' || value === 'dot' || value === 'mermaid';\n}\n\n/** graph 사용 오류를 경로 없는 코드 64로 바꾼다. */\nfunction graphUsageError(): CommandResult {\n return {\n standardOutput: '',\n standardError: `${graphUsage}\\n`,\n exitCode: 64,\n };\n}\n\n/** 검증된 graph 명령 옵션이다. */\ninterface GraphOptions {\n readonly inputPaths: readonly string[];\n readonly format: GraphFormat;\n}\n\ntype GraphFormat = 'json' | 'dot' | 'mermaid';\n\n/** graph 명령의 한 줄 사용법이다. */\nexport const graphUsage =\n 'Usage: isthmus graph <bridge-facts.json> <bridge-facts.json> '\n + '[more...] [--format json|dot|mermaid]';\n"]}
@@ -1,6 +1,6 @@
1
1
  import { isBridgeJoinDeferred, joinBridgeDocuments, MAX_DOCUMENTS_PER_JOIN, } from "../join/join.js";
2
2
  import { createBridgeQuery, encodeBridgeQuery } from "../report/query.js";
3
- import { bridgeJoinDeferredError, internalError, isExpectedInputError, readBridgeDocuments, } from "./check-command.js";
3
+ import { bridgeJoinDeferredError, internalError, inputFailureResult, readBridgeDocuments, } from "./check-command.js";
4
4
  /** query 인자를 실행해 bridge 질의 JSON과 종료 코드를 반환한다. */
5
5
  export async function runQueryCommand(arguments_, readTextFile) {
6
6
  const requested = arguments_[1];
@@ -26,17 +26,9 @@ export async function runQueryCommand(arguments_, readTextFile) {
26
26
  };
27
27
  }
28
28
  catch (error) {
29
- return isExpectedInputError(error) ? queryInputError() : internalError();
29
+ return inputFailureResult(error) ?? internalError();
30
30
  }
31
31
  }
32
- /** 입력 실패를 경로 없는 도구 실패 2로 바꾼다. */
33
- function queryInputError() {
34
- return {
35
- standardOutput: '',
36
- standardError: 'Unable to read or validate bridge facts; check the input files.\n',
37
- exitCode: 2,
38
- };
39
- }
40
32
  /** 잘못된 query 호출을 사용법과 코드 64로 바꾼다. */
41
33
  function queryUsageError() {
42
34
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"query-command.js","sourceRoot":"","sources":["../../src/cli/query-command.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EACL,uBAAuB,EACvB,aAAa,EACb,oBAAoB,EACpB,mBAAmB,GAGpB,MAAM,oBAAoB,CAAC;AAE5B,iDAAiD;AACjD,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,UAA6B,EAC7B,YAA0B;IAE1B,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IAChC,MAAM,UAAU,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACvC,IACE,UAAU,CAAC,CAAC,CAAC,KAAK,OAAO;QACzB,SAAS,KAAK,SAAS;QACvB,SAAS,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAC7B,UAAU,CAAC,MAAM,GAAG,CAAC;QACrB,UAAU,CAAC,MAAM,GAAG,sBAAsB;QAC1C,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAC/C,CAAC;QACD,OAAO,eAAe,EAAE,CAAC;IAC3B,CAAC;IACD,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;QACtE,MAAM,MAAM,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC9C,IAAI,oBAAoB,CAAC,MAAM,CAAC;YAAE,OAAO,uBAAuB,EAAE,CAAC;QACnE,MAAM,KAAK,GAAG,iBAAiB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACnD,OAAO;YACL,cAAc,EAAE,iBAAiB,CAAC,KAAK,CAAC;YACxC,aAAa,EAAE,EAAE;YACjB,QAAQ,EAAE,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;SAC5C,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IAC3E,CAAC;AACH,CAAC;AAED,iCAAiC;AACjC,SAAS,eAAe;IACtB,OAAO;QACL,cAAc,EAAE,EAAE;QAClB,aAAa,EACX,mEAAmE;QACrE,QAAQ,EAAE,CAAC;KACZ,CAAC;AACJ,CAAC;AAED,qCAAqC;AACrC,SAAS,eAAe;IACtB,OAAO;QACL,cAAc,EAAE,EAAE;QAClB,aAAa,EAAE,GAAG,UAAU,IAAI;QAChC,QAAQ,EAAE,EAAE;KACb,CAAC;AACJ,CAAC;AAED,2BAA2B;AAC3B,MAAM,CAAC,MAAM,UAAU,GACrB,+DAA+D;MAC7D,+BAA+B,CAAC","sourcesContent":["import {\n isBridgeJoinDeferred,\n joinBridgeDocuments,\n MAX_DOCUMENTS_PER_JOIN,\n} from '../join/join.ts';\nimport { createBridgeQuery, encodeBridgeQuery } from '../report/query.ts';\nimport {\n bridgeJoinDeferredError,\n internalError,\n isExpectedInputError,\n readBridgeDocuments,\n type CommandResult,\n type ReadTextFile,\n} from './check-command.ts';\n\n/** query 인자를 실행해 bridge 질의 JSON과 종료 코드를 반환한다. */\nexport async function runQueryCommand(\n arguments_: readonly string[],\n readTextFile: ReadTextFile,\n): Promise<CommandResult> {\n const requested = arguments_[1];\n const inputPaths = arguments_.slice(2);\n if (\n arguments_[0] !== 'query' ||\n requested === undefined ||\n requested.trim().length === 0 ||\n inputPaths.length < 2 ||\n inputPaths.length > MAX_DOCUMENTS_PER_JOIN ||\n inputPaths.some((path) => path.startsWith('-'))\n ) {\n return queryUsageError();\n }\n try {\n const documents = await readBridgeDocuments(inputPaths, readTextFile);\n const joined = joinBridgeDocuments(documents);\n if (isBridgeJoinDeferred(joined)) return bridgeJoinDeferredError();\n const query = createBridgeQuery(joined, requested);\n return {\n standardOutput: encodeBridgeQuery(query),\n standardError: '',\n exitCode: query.status === 'found' ? 0 : 64,\n };\n } catch (error) {\n return isExpectedInputError(error) ? queryInputError() : internalError();\n }\n}\n\n/** 입력 실패를 경로 없는 도구 실패 2로 바꾼다. */\nfunction queryInputError(): CommandResult {\n return {\n standardOutput: '',\n standardError:\n 'Unable to read or validate bridge facts; check the input files.\\n',\n exitCode: 2,\n };\n}\n\n/** 잘못된 query 호출을 사용법과 코드 64로 바꾼다. */\nfunction queryUsageError(): CommandResult {\n return {\n standardOutput: '',\n standardError: `${queryUsage}\\n`,\n exitCode: 64,\n };\n}\n\n/** query 명령의 한 줄 사용법이다. */\nexport const queryUsage =\n 'Usage: isthmus query <channel-or-method> <bridge-facts.json> '\n + '<bridge-facts.json> [more...]';\n"]}
1
+ {"version":3,"file":"query-command.js","sourceRoot":"","sources":["../../src/cli/query-command.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EACL,uBAAuB,EACvB,aAAa,EACb,kBAAkB,EAClB,mBAAmB,GAGpB,MAAM,oBAAoB,CAAC;AAE5B,iDAAiD;AACjD,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,UAA6B,EAC7B,YAA0B;IAE1B,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IAChC,MAAM,UAAU,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACvC,IACE,UAAU,CAAC,CAAC,CAAC,KAAK,OAAO;QACzB,SAAS,KAAK,SAAS;QACvB,SAAS,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAC7B,UAAU,CAAC,MAAM,GAAG,CAAC;QACrB,UAAU,CAAC,MAAM,GAAG,sBAAsB;QAC1C,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAC/C,CAAC;QACD,OAAO,eAAe,EAAE,CAAC;IAC3B,CAAC;IACD,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;QACtE,MAAM,MAAM,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC9C,IAAI,oBAAoB,CAAC,MAAM,CAAC;YAAE,OAAO,uBAAuB,EAAE,CAAC;QACnE,MAAM,KAAK,GAAG,iBAAiB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACnD,OAAO;YACL,cAAc,EAAE,iBAAiB,CAAC,KAAK,CAAC;YACxC,aAAa,EAAE,EAAE;YACjB,QAAQ,EAAE,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;SAC5C,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,kBAAkB,CAAC,KAAK,CAAC,IAAI,aAAa,EAAE,CAAC;IACtD,CAAC;AACH,CAAC;AAED,qCAAqC;AACrC,SAAS,eAAe;IACtB,OAAO;QACL,cAAc,EAAE,EAAE;QAClB,aAAa,EAAE,GAAG,UAAU,IAAI;QAChC,QAAQ,EAAE,EAAE;KACb,CAAC;AACJ,CAAC;AAED,2BAA2B;AAC3B,MAAM,CAAC,MAAM,UAAU,GACrB,+DAA+D;MAC7D,+BAA+B,CAAC","sourcesContent":["import {\n isBridgeJoinDeferred,\n joinBridgeDocuments,\n MAX_DOCUMENTS_PER_JOIN,\n} from '../join/join.ts';\nimport { createBridgeQuery, encodeBridgeQuery } from '../report/query.ts';\nimport {\n bridgeJoinDeferredError,\n internalError,\n inputFailureResult,\n readBridgeDocuments,\n type CommandResult,\n type ReadTextFile,\n} from './check-command.ts';\n\n/** query 인자를 실행해 bridge 질의 JSON과 종료 코드를 반환한다. */\nexport async function runQueryCommand(\n arguments_: readonly string[],\n readTextFile: ReadTextFile,\n): Promise<CommandResult> {\n const requested = arguments_[1];\n const inputPaths = arguments_.slice(2);\n if (\n arguments_[0] !== 'query' ||\n requested === undefined ||\n requested.trim().length === 0 ||\n inputPaths.length < 2 ||\n inputPaths.length > MAX_DOCUMENTS_PER_JOIN ||\n inputPaths.some((path) => path.startsWith('-'))\n ) {\n return queryUsageError();\n }\n try {\n const documents = await readBridgeDocuments(inputPaths, readTextFile);\n const joined = joinBridgeDocuments(documents);\n if (isBridgeJoinDeferred(joined)) return bridgeJoinDeferredError();\n const query = createBridgeQuery(joined, requested);\n return {\n standardOutput: encodeBridgeQuery(query),\n standardError: '',\n exitCode: query.status === 'found' ? 0 : 64,\n };\n } catch (error) {\n return inputFailureResult(error) ?? internalError();\n }\n}\n\n/** 잘못된 query 호출을 사용법과 코드 64로 바꾼다. */\nfunction queryUsageError(): CommandResult {\n return {\n standardOutput: '',\n standardError: `${queryUsage}\\n`,\n exitCode: 64,\n };\n}\n\n/** query 명령의 한 줄 사용법이다. */\nexport const queryUsage =\n 'Usage: isthmus query <channel-or-method> <bridge-facts.json> '\n + '<bridge-facts.json> [more...]';\n"]}