isthmus-cli 0.5.0 → 0.7.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/README.ko.md +170 -45
- package/README.md +178 -36
- package/Skills/isthmus/SKILL.md +104 -5
- package/compatibility.json +10 -0
- package/dist/cli/check-command.d.ts +2 -2
- package/dist/cli/check-command.js +22 -9
- package/dist/cli/check-command.js.map +1 -1
- package/dist/cli/command-support.d.ts +20 -2
- package/dist/cli/command-support.js +38 -9
- package/dist/cli/command-support.js.map +1 -1
- package/dist/cli/diff-command.js +4 -3
- package/dist/cli/diff-command.js.map +1 -1
- package/dist/cli/doctor-command.d.ts +11 -0
- package/dist/cli/doctor-command.js +128 -0
- package/dist/cli/doctor-command.js.map +1 -0
- package/dist/cli/extract-js-command.d.ts +33 -0
- package/dist/cli/extract-js-command.js +233 -0
- package/dist/cli/extract-js-command.js.map +1 -0
- package/dist/cli/graph-command.js +13 -6
- package/dist/cli/graph-command.js.map +1 -1
- package/dist/cli/impact-command.d.ts +5 -0
- package/dist/cli/impact-command.js +111 -0
- package/dist/cli/impact-command.js.map +1 -0
- package/dist/cli/init-command.d.ts +11 -0
- package/dist/cli/init-command.js +115 -0
- package/dist/cli/init-command.js.map +1 -0
- package/dist/cli/main.js +67 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/mcp-server.d.ts +16 -0
- package/dist/cli/mcp-server.js +534 -0
- package/dist/cli/mcp-server.js.map +1 -0
- package/dist/cli/preflight-command.d.ts +5 -0
- package/dist/cli/preflight-command.js +83 -0
- package/dist/cli/preflight-command.js.map +1 -0
- package/dist/cli/query-command.js +13 -6
- package/dist/cli/query-command.js.map +1 -1
- package/dist/cli/retentions-command.js +14 -7
- package/dist/cli/retentions-command.js.map +1 -1
- package/dist/cli/runtime-command.d.ts +5 -0
- package/dist/cli/runtime-command.js +42 -0
- package/dist/cli/runtime-command.js.map +1 -0
- package/dist/cli/runtime-json-reader.d.ts +12 -0
- package/dist/cli/runtime-json-reader.js +37 -0
- package/dist/cli/runtime-json-reader.js.map +1 -0
- package/dist/cli/serve-command.d.ts +13 -0
- package/dist/cli/serve-command.js +43 -0
- package/dist/cli/serve-command.js.map +1 -0
- package/dist/exchange/capture-config.d.ts +18 -0
- package/dist/exchange/capture-config.js +100 -0
- package/dist/exchange/capture-config.js.map +1 -0
- package/dist/exchange/impact-selection.d.ts +13 -0
- package/dist/exchange/impact-selection.js +35 -0
- package/dist/exchange/impact-selection.js.map +1 -0
- package/dist/exchange/kartograph-impact.d.ts +4 -0
- package/dist/exchange/kartograph-impact.js +169 -0
- package/dist/exchange/kartograph-impact.js.map +1 -0
- package/dist/exchange/messages.d.ts +36 -0
- package/dist/exchange/messages.js +96 -0
- package/dist/exchange/messages.js.map +1 -0
- package/dist/exchange/parse.d.ts +69 -0
- package/dist/exchange/parse.js +127 -20
- package/dist/exchange/parse.js.map +1 -1
- package/dist/exchange/preflight-context.d.ts +71 -0
- package/dist/exchange/preflight-context.js +317 -0
- package/dist/exchange/preflight-context.js.map +1 -0
- package/dist/exchange/producer-impact.d.ts +17 -0
- package/dist/exchange/producer-impact.js +226 -0
- package/dist/exchange/producer-impact.js.map +1 -0
- package/dist/exchange/runtime.d.ts +69 -0
- package/dist/exchange/runtime.js +160 -0
- package/dist/exchange/runtime.js.map +1 -0
- package/dist/extract/js-document.d.ts +22 -0
- package/dist/extract/js-document.js +230 -0
- package/dist/extract/js-document.js.map +1 -0
- package/dist/extract/js-scan.d.ts +93 -0
- package/dist/extract/js-scan.js +1205 -0
- package/dist/extract/js-scan.js.map +1 -0
- package/dist/extract/lexer.d.ts +26 -0
- package/dist/extract/lexer.js +316 -0
- package/dist/extract/lexer.js.map +1 -0
- package/dist/join/join.d.ts +66 -1
- package/dist/join/join.js +171 -1
- package/dist/join/join.js.map +1 -1
- package/dist/join/message-address.d.ts +7 -0
- package/dist/join/message-address.js +37 -0
- package/dist/join/message-address.js.map +1 -0
- package/dist/join/messages.d.ts +26 -0
- package/dist/join/messages.js +87 -0
- package/dist/join/messages.js.map +1 -0
- package/dist/report/check-report.d.ts +20 -3
- package/dist/report/check-report.js +240 -8
- package/dist/report/check-report.js.map +1 -1
- package/dist/report/codequality.d.ts +45 -0
- package/dist/report/codequality.js +74 -0
- package/dist/report/codequality.js.map +1 -0
- package/dist/report/diff.d.ts +25 -3
- package/dist/report/diff.js +91 -10
- package/dist/report/diff.js.map +1 -1
- package/dist/report/graph.d.ts +10 -4
- package/dist/report/graph.js +60 -6
- package/dist/report/graph.js.map +1 -1
- package/dist/report/impact.d.ts +62 -0
- package/dist/report/impact.js +168 -0
- package/dist/report/impact.js.map +1 -0
- package/dist/report/preflight-runtime.d.ts +42 -0
- package/dist/report/preflight-runtime.js +193 -0
- package/dist/report/preflight-runtime.js.map +1 -0
- package/dist/report/preflight-view.d.ts +146 -0
- package/dist/report/preflight-view.js +216 -0
- package/dist/report/preflight-view.js.map +1 -0
- package/dist/report/preflight.d.ts +104 -0
- package/dist/report/preflight.js +331 -0
- package/dist/report/preflight.js.map +1 -0
- package/dist/report/query.d.ts +11 -4
- package/dist/report/query.js +84 -17
- package/dist/report/query.js.map +1 -1
- package/dist/report/retentions.d.ts +17 -5
- package/dist/report/retentions.js +85 -8
- package/dist/report/retentions.js.map +1 -1
- package/dist/report/rules.d.ts +16 -0
- package/dist/report/rules.js +30 -0
- package/dist/report/rules.js.map +1 -0
- package/dist/report/runtime-impact.d.ts +38 -0
- package/dist/report/runtime-impact.js +94 -0
- package/dist/report/runtime-impact.js.map +1 -0
- package/dist/report/runtime.d.ts +54 -0
- package/dist/report/runtime.js +137 -0
- package/dist/report/runtime.js.map +1 -0
- package/dist/report/sarif.d.ts +2 -8
- package/dist/report/sarif.js +2 -10
- package/dist/report/sarif.js.map +1 -1
- package/dist/report/sorted-json.d.ts +1 -1
- package/dist/report/sorted-json.js +2 -2
- package/dist/report/sorted-json.js.map +1 -1
- package/docs/BRIDGE-EVENTS.md +87 -0
- package/docs/BRIDGE-MESSAGES.md +117 -0
- package/docs/GRAPH-EXCHANGE.md +382 -0
- package/docs/IMPACT.md +96 -0
- package/docs/MCP.md +62 -0
- package/docs/PREFLIGHT.md +311 -0
- package/docs/RUNTIME.md +172 -0
- package/docs/TOOLCHAIN.md +101 -0
- package/package.json +14 -2
- package/scripts/build-preflight-toolchain.mjs +186 -0
- package/scripts/capture-preflight.mjs +380 -0
- package/scripts/run-child.mjs +17 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"impact-command.js","sourceRoot":"","sources":["../../src/cli/impact-command.ts"],"names":[],"mappings":"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","sourcesContent":["import { ImpactSelectionValidationError, parseImpactSelection } from '../exchange/impact-selection.ts';\nimport type { ImpactSelection } from '../exchange/impact-selection.ts';\nimport { isSafeNonEmptyString } from '../exchange/parse.ts';\nimport { parseBridgeRuntime, RuntimeValidationError } from '../exchange/runtime.ts';\nimport { MAX_DOCUMENTS_PER_JOIN } from '../join/join.ts';\nimport { createBridgeImpact, encodeBridgeImpact, hasImpactBlockers } from '../report/impact.ts';\nimport type { ImpactRuntimeInput } from '../report/runtime-impact.ts';\nimport {\n inputFailure, inputFailureResult, internalError, isJsonParseFailure,\n MAX_INPUT_TEXT_LENGTH, readBridgeDocuments,\n} from './command-support.ts';\nimport type { CommandResult, ReadTextFile } from './command-support.ts';\nimport { parseCommandArguments } from './parse-arguments.ts';\n\n/** 파일·심볼·CI 변경 목록을 브리지 영향 보고서로 바꾸는 CLI 경계다. */\nexport async function runImpactCommand(\n arguments_: readonly string[], readTextFile: ReadTextFile,\n): Promise<CommandResult> {\n const parsed = parseCommandArguments(arguments_.slice(1),\n ['--file', '--symbol', '--changes', '--runtime', '--revision'], ['--strict', '--compact']);\n if (parsed === undefined || ['--file', '--symbol', '--changes'].filter((flag) => parsed.valueFlags.has(flag)).length !== 1 ||\n parsed.positionals.length < 2 || parsed.positionals.length > MAX_DOCUMENTS_PER_JOIN) {\n return usageError();\n }\n const runtimePath = parsed.valueFlags.get('--runtime');\n const revision = parsed.valueFlags.get('--revision');\n if ((runtimePath === undefined) !== (revision === undefined) ||\n (revision !== undefined && !isSafeNonEmptyString(revision))) return usageError();\n try {\n let selection: ImpactSelection;\n let supplementalTextLength = 0;\n const changesPath = parsed.valueFlags.get('--changes');\n if (changesPath !== undefined) {\n const loaded = await readSupplemental(changesPath, readTextFile, 'changes', parseImpactSelection);\n if ('exitCode' in loaded) return loaded;\n selection = loaded.document;\n supplementalTextLength += loaded.textLength;\n } else {\n const file = parsed.valueFlags.get('--file');\n const symbol = parsed.valueFlags.get('--symbol');\n try {\n selection = parseImpactSelection({ format: 'isthmus-changes', version: 1,\n files: file === undefined ? [] : [file], symbols: symbol === undefined ? [] : [symbol] });\n } catch (error) {\n if (error instanceof ImpactSelectionValidationError) return usageError();\n throw error;\n }\n }\n let runtime: ImpactRuntimeInput | undefined;\n if (runtimePath !== undefined && revision !== undefined) {\n const loaded = await readSupplemental(runtimePath, readTextFile, 'runtime', parseBridgeRuntime);\n if ('exitCode' in loaded) return loaded;\n supplementalTextLength += loaded.textLength;\n runtime = { document: loaded.document, revision };\n }\n const documents = await readBridgeDocuments(parsed.positionals, readTextFile, supplementalTextLength);\n const report = createBridgeImpact(documents, selection, runtime);\n const blocked = parsed.booleanFlags.has('--strict') && hasImpactBlockers(report);\n return {\n standardOutput: encodeBridgeImpact(report, parsed.booleanFlags.has('--compact')),\n standardError: blocked\n ? 'Change preflight requires review: related errors, analysis gaps, or unobserved selectors remain.\\n'\n : report.status === 'unobserved'\n ? 'No selected bridge facts were observed; inspect source coverage and use a pre-change snapshot for deleted code.\\n'\n : '',\n exitCode: blocked ? 1 : 0,\n };\n } catch (error) {\n if (error instanceof RuntimeValidationError) return inputFailure(`${error.message}\\n`);\n return inputFailureResult(error) ?? internalError();\n }\n}\n\n/** 변경 파일도 브리지 입력과 같은 읽기·구문·계약 실패 경계를 지킨다. */\nasync function readSupplemental<T>(\n path: string, readTextFile: ReadTextFile, kind: 'changes' | 'runtime', parse: (value: unknown) => T,\n): Promise<\n { document: T; textLength: number } | CommandResult\n> {\n const label = kind === 'changes' ? 'Changes' : 'Runtime';\n const format = kind === 'changes' ? 'isthmus-changes' : 'bridge-runtime';\n let text: string;\n try { text = await readTextFile(path); }\n catch { return inputFailure(`Unable to read ${kind} input; check that the file exists and is readable.\\n`); }\n if (text.length > MAX_INPUT_TEXT_LENGTH) return inputFailure(`${label} input exceeds the input size limit.\\n`);\n let value: unknown;\n try { value = JSON.parse(text); }\n catch (error) {\n if (isJsonParseFailure(error)) return inputFailure(`${label} input is not valid JSON.\\n`);\n throw error;\n }\n try { return { document: parse(value), textLength: text.length }; }\n catch (error) {\n if (error instanceof ImpactSelectionValidationError || error instanceof RuntimeValidationError) {\n return inputFailure(`${label} input violates the ${format} contract: ${error.message}\\n`);\n }\n throw error;\n }\n}\n\n/** 잘못된 인수는 입력을 읽기 전에 코드 64로 거부한다. */\nfunction usageError(): CommandResult {\n return { standardOutput: '', standardError: `${impactUsage}\\n`, exitCode: 64 };\n}\n\n/** impact 명령의 독립적인 선택 방식과 CI 실패 옵션이다. */\nexport const impactUsage = 'Usage: isthmus impact (--file <relative-path> | --symbol <name-or-usr> '\n + '| --changes <changes.json>) <bridge-facts.json> <bridge-facts.json> [more...] '\n + '[--runtime <runtime.json> --revision <revision>] [--strict] [--compact]';\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type CaptureFileSystem, type CommandResult, type ReadTextFile, type WriteTextFile } from './command-support.ts';
|
|
2
|
+
/**
|
|
3
|
+
* capture 설정 scaffold를 JSON으로 쓴다.
|
|
4
|
+
*
|
|
5
|
+
* producer를 실행하거나 탐지하지 않는다 — 기본 producer 명령은 PATH 이름이고,
|
|
6
|
+
* `--toolchain`을 주면 이미 구축한 `isthmus-built-toolchain` JSON의 실제 명령을
|
|
7
|
+
* 채운다. `prepare`는 앱마다 달라 자리표시자로 남긴다.
|
|
8
|
+
*/
|
|
9
|
+
export declare function runInitCommand(arguments_: readonly string[], readTextFile: ReadTextFile, writeTextFile: WriteTextFile, fileSystem: CaptureFileSystem, cwd: string): Promise<CommandResult>;
|
|
10
|
+
/** init 명령의 한 줄 사용법이다. */
|
|
11
|
+
export declare const initUsage: string;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { isJsonObject, isSafeNonEmptyString } from "../exchange/parse.js";
|
|
3
|
+
import { encodeSortedJson } from "../report/sorted-json.js";
|
|
4
|
+
import { parseCommandArguments } from "./parse-arguments.js";
|
|
5
|
+
import { inputFailure, isJsonParseFailure, MAX_INPUT_TEXT_LENGTH, } from "./command-support.js";
|
|
6
|
+
/**
|
|
7
|
+
* capture 설정 scaffold를 JSON으로 쓴다.
|
|
8
|
+
*
|
|
9
|
+
* producer를 실행하거나 탐지하지 않는다 — 기본 producer 명령은 PATH 이름이고,
|
|
10
|
+
* `--toolchain`을 주면 이미 구축한 `isthmus-built-toolchain` JSON의 실제 명령을
|
|
11
|
+
* 채운다. `prepare`는 앱마다 달라 자리표시자로 남긴다.
|
|
12
|
+
*/
|
|
13
|
+
export async function runInitCommand(arguments_, readTextFile, writeTextFile, fileSystem, cwd) {
|
|
14
|
+
if (arguments_[0] !== 'init')
|
|
15
|
+
return usageError();
|
|
16
|
+
const parsed = parseCommandArguments(arguments_.slice(1), ['--project', '--toolchain'], ['--force']);
|
|
17
|
+
if (parsed === undefined || parsed.positionals.length > 1)
|
|
18
|
+
return usageError();
|
|
19
|
+
const outputPath = resolve(cwd, parsed.positionals[0] ?? 'capture.json');
|
|
20
|
+
let project;
|
|
21
|
+
try {
|
|
22
|
+
project = await fileSystem.realPath(resolve(cwd, parsed.valueFlags.get('--project') ?? cwd));
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return inputFailure('The project path does not exist; pass --project at the app root.\n');
|
|
26
|
+
}
|
|
27
|
+
let producers = { dartograph: ['dartograph'], cartograph: ['cartograph'] };
|
|
28
|
+
const toolchainPath = parsed.valueFlags.get('--toolchain');
|
|
29
|
+
let toolchainAbsolute;
|
|
30
|
+
if (toolchainPath !== undefined) {
|
|
31
|
+
toolchainAbsolute = resolve(cwd, toolchainPath);
|
|
32
|
+
const loaded = await readToolchain(toolchainAbsolute, readTextFile);
|
|
33
|
+
if (loaded === undefined) {
|
|
34
|
+
return inputFailure('The toolchain manifest is missing or invalid; build one with '
|
|
35
|
+
+ 'scripts/build-preflight-toolchain.mjs first.\n');
|
|
36
|
+
}
|
|
37
|
+
producers = loaded;
|
|
38
|
+
}
|
|
39
|
+
if (!parsed.booleanFlags.has('--force') &&
|
|
40
|
+
(await fileSystem.statPath(outputPath)) !== 'missing') {
|
|
41
|
+
return inputFailure(`The capture config already exists at ${outputPath}; pass --force to overwrite it.\n`);
|
|
42
|
+
}
|
|
43
|
+
const scaffold = {
|
|
44
|
+
project,
|
|
45
|
+
...producers,
|
|
46
|
+
prepare: [['replace-with-native-index-build']],
|
|
47
|
+
inputs: ['lib'],
|
|
48
|
+
toolInputs: [toolchainAbsolute ?? 'toolchain.json'],
|
|
49
|
+
selection: { dart: { files: [], symbols: [] } },
|
|
50
|
+
output: '.isthmus/context.json',
|
|
51
|
+
cache: '.isthmus/cache.json',
|
|
52
|
+
};
|
|
53
|
+
try {
|
|
54
|
+
await writeTextFile(outputPath, `${encodeSortedJson(scaffold)}\n`);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return inputFailure('Unable to write the capture config; check that the path is writable.\n');
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
standardOutput: encodeSortedJson({
|
|
61
|
+
format: 'isthmus-init',
|
|
62
|
+
version: 1,
|
|
63
|
+
path: outputPath,
|
|
64
|
+
project,
|
|
65
|
+
wrote: true,
|
|
66
|
+
}),
|
|
67
|
+
standardError: '',
|
|
68
|
+
exitCode: 0,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/** `isthmus-built-toolchain` JSON에서 실제 producer 명령을 읽는다. */
|
|
72
|
+
async function readToolchain(path, readTextFile) {
|
|
73
|
+
let text;
|
|
74
|
+
try {
|
|
75
|
+
text = await readTextFile(path);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
if (text.length > MAX_INPUT_TEXT_LENGTH)
|
|
81
|
+
return undefined;
|
|
82
|
+
let value;
|
|
83
|
+
try {
|
|
84
|
+
value = JSON.parse(text);
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
if (isJsonParseFailure(error))
|
|
88
|
+
return undefined;
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
if (!isJsonObject(value) || value.format !== 'isthmus-built-toolchain' ||
|
|
92
|
+
value.version !== 1 || !isJsonObject(value.commands)) {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
const commands = value.commands;
|
|
96
|
+
if (!isCommand(commands.dartograph))
|
|
97
|
+
return undefined;
|
|
98
|
+
return {
|
|
99
|
+
dartograph: commands.dartograph,
|
|
100
|
+
...(isCommand(commands.cartograph) ? { cartograph: commands.cartograph } : {}),
|
|
101
|
+
...(isCommand(commands.kartograph) ? { kartograph: commands.kartograph } : {}),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/** 명령 배열은 비어 있지 않은 안전한 문자열의 비어 있지 않은 배열이다. */
|
|
105
|
+
function isCommand(value) {
|
|
106
|
+
return Array.isArray(value) && value.length > 0 && value.every(isSafeNonEmptyString);
|
|
107
|
+
}
|
|
108
|
+
/** 잘못된 CLI 호출을 경로 없는 사용법과 코드 64로 변환한다. */
|
|
109
|
+
function usageError() {
|
|
110
|
+
return { standardOutput: '', standardError: `${initUsage}\n`, exitCode: 64 };
|
|
111
|
+
}
|
|
112
|
+
/** init 명령의 한 줄 사용법이다. */
|
|
113
|
+
export const initUsage = 'Usage: isthmus init [capture.json] [--project <dir>] '
|
|
114
|
+
+ '[--toolchain <toolchain.json>] [--force]';
|
|
115
|
+
//# sourceMappingURL=init-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-command.js","sourceRoot":"","sources":["../../src/cli/init-command.ts"],"names":[],"mappings":"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","sourcesContent":["import { resolve } from 'node:path';\n\nimport { isJsonObject, isSafeNonEmptyString } from '../exchange/parse.ts';\nimport { encodeSortedJson } from '../report/sorted-json.ts';\nimport { parseCommandArguments } from './parse-arguments.ts';\nimport {\n inputFailure,\n isJsonParseFailure,\n MAX_INPUT_TEXT_LENGTH,\n type CaptureFileSystem,\n type CommandResult,\n type ReadTextFile,\n type WriteTextFile,\n} from './command-support.ts';\n\n/** init이 쓰는 scaffold의 producer 명령 묶음이다. */\ninterface InitProducers {\n readonly dartograph: readonly string[];\n readonly cartograph?: readonly string[];\n readonly kartograph?: readonly string[];\n}\n\n/**\n * capture 설정 scaffold를 JSON으로 쓴다.\n *\n * producer를 실행하거나 탐지하지 않는다 — 기본 producer 명령은 PATH 이름이고,\n * `--toolchain`을 주면 이미 구축한 `isthmus-built-toolchain` JSON의 실제 명령을\n * 채운다. `prepare`는 앱마다 달라 자리표시자로 남긴다.\n */\nexport async function runInitCommand(\n arguments_: readonly string[],\n readTextFile: ReadTextFile,\n writeTextFile: WriteTextFile,\n fileSystem: CaptureFileSystem,\n cwd: string,\n): Promise<CommandResult> {\n if (arguments_[0] !== 'init') return usageError();\n const parsed = parseCommandArguments(\n arguments_.slice(1),\n ['--project', '--toolchain'],\n ['--force'],\n );\n if (parsed === undefined || parsed.positionals.length > 1) return usageError();\n const outputPath = resolve(cwd, parsed.positionals[0] ?? 'capture.json');\n\n let project: string;\n try {\n project = await fileSystem.realPath(resolve(cwd, parsed.valueFlags.get('--project') ?? cwd));\n } catch {\n return inputFailure('The project path does not exist; pass --project at the app root.\\n');\n }\n\n let producers: InitProducers = { dartograph: ['dartograph'], cartograph: ['cartograph'] };\n const toolchainPath = parsed.valueFlags.get('--toolchain');\n let toolchainAbsolute: string | undefined;\n if (toolchainPath !== undefined) {\n toolchainAbsolute = resolve(cwd, toolchainPath);\n const loaded = await readToolchain(toolchainAbsolute, readTextFile);\n if (loaded === undefined) {\n return inputFailure(\n 'The toolchain manifest is missing or invalid; build one with '\n + 'scripts/build-preflight-toolchain.mjs first.\\n',\n );\n }\n producers = loaded;\n }\n\n if (!parsed.booleanFlags.has('--force') &&\n (await fileSystem.statPath(outputPath)) !== 'missing') {\n return inputFailure(\n `The capture config already exists at ${outputPath}; pass --force to overwrite it.\\n`,\n );\n }\n\n const scaffold = {\n project,\n ...producers,\n prepare: [['replace-with-native-index-build']],\n inputs: ['lib'],\n toolInputs: [toolchainAbsolute ?? 'toolchain.json'],\n selection: { dart: { files: [], symbols: [] } },\n output: '.isthmus/context.json',\n cache: '.isthmus/cache.json',\n };\n try {\n await writeTextFile(outputPath, `${encodeSortedJson(scaffold)}\\n`);\n } catch {\n return inputFailure('Unable to write the capture config; check that the path is writable.\\n');\n }\n return {\n standardOutput: encodeSortedJson({\n format: 'isthmus-init',\n version: 1,\n path: outputPath,\n project,\n wrote: true,\n }),\n standardError: '',\n exitCode: 0,\n };\n}\n\n/** `isthmus-built-toolchain` JSON에서 실제 producer 명령을 읽는다. */\nasync function readToolchain(\n path: string,\n readTextFile: ReadTextFile,\n): Promise<InitProducers | undefined> {\n let text: string;\n try {\n text = await readTextFile(path);\n } catch {\n return undefined;\n }\n if (text.length > MAX_INPUT_TEXT_LENGTH) return undefined;\n let value: unknown;\n try {\n value = JSON.parse(text);\n } catch (error) {\n if (isJsonParseFailure(error)) return undefined;\n throw error;\n }\n if (!isJsonObject(value) || value.format !== 'isthmus-built-toolchain' ||\n value.version !== 1 || !isJsonObject(value.commands)) {\n return undefined;\n }\n const commands = value.commands;\n if (!isCommand(commands.dartograph)) return undefined;\n return {\n dartograph: commands.dartograph,\n ...(isCommand(commands.cartograph) ? { cartograph: commands.cartograph } : {}),\n ...(isCommand(commands.kartograph) ? { kartograph: commands.kartograph } : {}),\n };\n}\n\n/** 명령 배열은 비어 있지 않은 안전한 문자열의 비어 있지 않은 배열이다. */\nfunction isCommand(value: unknown): value is readonly string[] {\n return Array.isArray(value) && value.length > 0 && value.every(isSafeNonEmptyString);\n}\n\n/** 잘못된 CLI 호출을 경로 없는 사용법과 코드 64로 변환한다. */\nfunction usageError(): CommandResult {\n return { standardOutput: '', standardError: `${initUsage}\\n`, exitCode: 64 };\n}\n\n/** init 명령의 한 줄 사용법이다. */\nexport const initUsage =\n 'Usage: isthmus init [capture.json] [--project <dir>] '\n + '[--toolchain <toolchain.json>] [--force]';"]}
|
package/dist/cli/main.js
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { readdir, readFile, realpath, stat } from 'node:fs/promises';
|
|
3
3
|
import { writeTextAtomically } from "./atomic-write.js";
|
|
4
4
|
import { checkUsage, runCheckCommand } from "./check-command.js";
|
|
5
|
+
import { doctorUsage, runDoctorCommand } from "./doctor-command.js";
|
|
6
|
+
import { initUsage, runInitCommand } from "./init-command.js";
|
|
7
|
+
import { extractJsUsage, runExtractJsCommand, } from "./extract-js-command.js";
|
|
5
8
|
import { graphUsage, runGraphCommand } from "./graph-command.js";
|
|
6
9
|
import { diffUsage, runDiffCommand } from "./diff-command.js";
|
|
7
10
|
import { queryUsage, runQueryCommand } from "./query-command.js";
|
|
11
|
+
import { impactUsage, runImpactCommand } from "./impact-command.js";
|
|
12
|
+
import { runtimeUsage, runRuntimeCommand } from "./runtime-command.js";
|
|
13
|
+
import { preflightUsage, runPreflightCommand } from "./preflight-command.js";
|
|
8
14
|
import { retentionUsage, runRetentionsCommand, } from "./retentions-command.js";
|
|
15
|
+
import { runServeCommand, serveUsage } from "./serve-command.js";
|
|
9
16
|
process.stdout.on('error', handleStreamError);
|
|
10
17
|
process.stderr.on('error', handleStreamError);
|
|
11
18
|
const commandUsages = new Map([
|
|
@@ -13,16 +20,30 @@ const commandUsages = new Map([
|
|
|
13
20
|
['graph', graphUsage],
|
|
14
21
|
['diff', diffUsage],
|
|
15
22
|
['query', queryUsage],
|
|
23
|
+
['impact', impactUsage],
|
|
24
|
+
['preflight', preflightUsage],
|
|
25
|
+
['verify-runtime', runtimeUsage],
|
|
16
26
|
['retentions', retentionUsage],
|
|
27
|
+
['serve', serveUsage],
|
|
28
|
+
['extract-js', extractJsUsage],
|
|
29
|
+
['doctor', doctorUsage],
|
|
30
|
+
['init', initUsage],
|
|
17
31
|
]);
|
|
18
32
|
const rootHelp = `Usage: isthmus <command> [options]
|
|
19
33
|
|
|
20
34
|
Commands:
|
|
21
35
|
check Report unmatched bridge calls and handlers
|
|
22
36
|
query Find both sides of a channel or method
|
|
37
|
+
impact Inspect bridge dependencies before changing files or symbols
|
|
38
|
+
preflight Trace cross-language impact from producer analysis context
|
|
39
|
+
verify-runtime Verify recorded calls against scenario expectations
|
|
23
40
|
graph Render matched boundary edges
|
|
24
41
|
diff Compare bridge observations before and after a change
|
|
25
42
|
retentions Produce external retention evidence
|
|
43
|
+
extract-js Extract React Native caller-side bridge facts from JS/TS
|
|
44
|
+
doctor Validate a capture config and its executable paths
|
|
45
|
+
init Write a capture config scaffold
|
|
46
|
+
serve Speak MCP over stdio for agent clients
|
|
26
47
|
help Show command help
|
|
27
48
|
|
|
28
49
|
Options:
|
|
@@ -32,6 +53,37 @@ Options:
|
|
|
32
53
|
const arguments_ = process.argv.slice(2);
|
|
33
54
|
const readTextFile = (path) => readFile(path, 'utf8');
|
|
34
55
|
const writeTextFile = (path, text) => writeTextAtomically(path, text);
|
|
56
|
+
/** extract-js가 쓰는 실제 파일시스템 구현이다 — 테스트는 계약만 주입한다. */
|
|
57
|
+
const extractJsFileSystem = {
|
|
58
|
+
statPath: async (path) => {
|
|
59
|
+
try {
|
|
60
|
+
const entry = await stat(path);
|
|
61
|
+
return entry.isDirectory() ? 'directory' : 'file';
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return 'missing';
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
listDirectory: async (path) => (await readdir(path, { withFileTypes: true })).map((entry) => ({
|
|
68
|
+
name: entry.name,
|
|
69
|
+
isFile: entry.isFile(),
|
|
70
|
+
isDirectory: entry.isDirectory(),
|
|
71
|
+
})),
|
|
72
|
+
realPath: (path) => realpath(path),
|
|
73
|
+
};
|
|
74
|
+
/** doctor·init이 쓰는 실제 파일시스템이다. producer는 실행하지 않는다. */
|
|
75
|
+
const captureFileSystem = {
|
|
76
|
+
statPath: async (path) => {
|
|
77
|
+
try {
|
|
78
|
+
const entry = await stat(path);
|
|
79
|
+
return entry.isDirectory() ? 'directory' : 'file';
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return 'missing';
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
realPath: (path) => realpath(path),
|
|
86
|
+
};
|
|
35
87
|
const informationalResult = await runInformationalCommand(arguments_);
|
|
36
88
|
const result = informationalResult ?? await dispatchCommand(arguments_);
|
|
37
89
|
process.stdout.write(result.standardOutput);
|
|
@@ -81,6 +133,20 @@ async function dispatchCommand(commandArguments) {
|
|
|
81
133
|
return runDiffCommand(commandArguments, readTextFile);
|
|
82
134
|
case 'query':
|
|
83
135
|
return runQueryCommand(commandArguments, readTextFile);
|
|
136
|
+
case 'impact':
|
|
137
|
+
return runImpactCommand(commandArguments, readTextFile);
|
|
138
|
+
case 'preflight':
|
|
139
|
+
return runPreflightCommand(commandArguments, readTextFile);
|
|
140
|
+
case 'verify-runtime':
|
|
141
|
+
return runRuntimeCommand(commandArguments, readTextFile);
|
|
142
|
+
case 'extract-js':
|
|
143
|
+
return runExtractJsCommand(commandArguments, extractJsFileSystem, readTextFile, () => new Date(), await readPackageVersion());
|
|
144
|
+
case 'doctor':
|
|
145
|
+
return runDoctorCommand(commandArguments, readTextFile, captureFileSystem, process.cwd(), process.env.PATH ?? '');
|
|
146
|
+
case 'init':
|
|
147
|
+
return runInitCommand(commandArguments, readTextFile, writeTextFile, captureFileSystem, process.cwd());
|
|
148
|
+
case 'serve':
|
|
149
|
+
return runServeCommand(commandArguments, readTextFile, writeTextFile, await readPackageVersion());
|
|
84
150
|
case 'retentions': {
|
|
85
151
|
const version = await readPackageVersion();
|
|
86
152
|
return version === undefined
|
package/dist/cli/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n\nimport { readFile } from 'node:fs/promises';\n\nimport { writeTextAtomically } from './atomic-write.ts';\nimport { checkUsage, runCheckCommand } from './check-command.ts';\nimport type { CommandResult } from './command-support.ts';\nimport { graphUsage, runGraphCommand } from './graph-command.ts';\nimport { diffUsage, runDiffCommand } from './diff-command.ts';\nimport { queryUsage, runQueryCommand } from './query-command.ts';\nimport {\n retentionUsage,\n runRetentionsCommand,\n} from './retentions-command.ts';\n\nprocess.stdout.on('error', handleStreamError);\nprocess.stderr.on('error', handleStreamError);\n\nconst commandUsages = new Map([\n ['check', checkUsage],\n ['graph', graphUsage],\n ['diff', diffUsage],\n ['query', queryUsage],\n ['retentions', retentionUsage],\n]);\n\nconst rootHelp = `Usage: isthmus <command> [options]\n\nCommands:\n check Report unmatched bridge calls and handlers\n query Find both sides of a channel or method\n graph Render matched boundary edges\n diff Compare bridge observations before and after a change\n retentions Produce external retention evidence\n help Show command help\n\nOptions:\n -h, --help Show help; after a command it shows that command's usage\n --version Show version\n`;\n\nconst arguments_ = process.argv.slice(2);\nconst readTextFile = (path: string) => readFile(path, 'utf8');\nconst writeTextFile = (path: string, text: string) =>\n writeTextAtomically(path, text);\nconst informationalResult = await runInformationalCommand(arguments_);\nconst result = informationalResult ?? await dispatchCommand(arguments_);\n\nprocess.stdout.write(result.standardOutput);\nprocess.stderr.write(result.standardError);\nprocess.exitCode = result.exitCode;\n\n/** 파이프 소비자가 먼저 닫힌 정상 상황만 조용히 종료한다. */\nfunction handleStreamError(error: NodeJS.ErrnoException): void {\n if (error.code === 'EPIPE') {\n process.exitCode = 0;\n return;\n }\n throw error;\n}\n\n/** 도움말과 버전처럼 입력 문서가 필요 없는 명령을 실행한다. */\nasync function runInformationalCommand(\n commandArguments: readonly string[],\n): Promise<CommandResult | undefined> {\n // 도움말 플래그는 어느 위치에 있든 이긴다. 긴 호출 끝에 붙여도 사용법을 본다.\n const helpFlagIndex = commandArguments.findIndex(\n (argument) => argument === '--help' || argument === '-h',\n );\n if (helpFlagIndex >= 0) return commandHelp(commandArguments[0]);\n if (commandArguments[0] === 'help') {\n return commandHelp(commandArguments[1]);\n }\n if (\n commandArguments.length === 1 &&\n commandArguments[0] === '--version'\n ) {\n return readVersion();\n }\n return undefined;\n}\n\n/** 명령 이름에 맞는 사용법을, 모르면 루트 도움말을 돌려준다. */\nfunction commandHelp(command: string | undefined): CommandResult {\n if (command === undefined) return successfulText(rootHelp);\n const usage = commandUsages.get(command);\n return usage === undefined\n ? successfulText(rootHelp)\n : successfulText(`${usage}\\n`);\n}\n\n/** 알려진 분석 하위 명령으로만 라우팅한다. */\nasync function dispatchCommand(\n commandArguments: readonly string[],\n): Promise<CommandResult> {\n switch (commandArguments[0]) {\n case 'check':\n // SARIF driver에만 필요하므로 메타데이터 부재는 json 보고서를 막지 않는다.\n return runCheckCommand(\n commandArguments,\n readTextFile,\n writeTextFile,\n undefined,\n await readPackageVersion(),\n );\n case 'graph':\n return runGraphCommand(commandArguments, readTextFile);\n case 'diff':\n return runDiffCommand(commandArguments, readTextFile);\n case 'query':\n return runQueryCommand(commandArguments, readTextFile);\n case 'retentions': {\n const version = await readPackageVersion();\n return version === undefined\n ? packageMetadataError()\n : runRetentionsCommand(\n commandArguments,\n readTextFile,\n () => new Date(),\n version,\n );\n }\n default:\n return {\n standardOutput: '',\n standardError: rootHelp,\n exitCode: 64,\n };\n }\n}\n\n/** 설치된 package.json을 단일 출처로 사용해 버전을 출력한다. */\nasync function readVersion(): Promise<CommandResult> {\n const version = await readPackageVersion();\n return version === undefined\n ? packageMetadataError()\n : successfulText(`${version}\\n`);\n}\n\n/** 설치된 package.json에서 검증된 버전 문자열을 읽는다. */\nasync function readPackageVersion(): Promise<string | undefined> {\n try {\n const text = await readFile(new URL('../../package.json', import.meta.url), 'utf8');\n const document: unknown = JSON.parse(text);\n return isVersionDocument(document) ? document.version : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** package metadata가 비어 있지 않은 버전을 제공하는지 확인한다. */\nfunction isVersionDocument(value: unknown): value is { readonly version: string } {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'version' in value &&\n typeof value.version === 'string' &&\n value.version.length > 0\n );\n}\n\n/** stdout 텍스트와 성공 종료 코드를 만든다. */\nfunction successfulText(standardOutput: string): CommandResult {\n return { standardOutput, standardError: '', exitCode: 0 };\n}\n\n/** package metadata 실패를 민감정보 없는 코드 2로 바꾼다. */\nfunction packageMetadataError(): CommandResult {\n return {\n standardOutput: '',\n standardError: 'Unable to read package metadata.\\n',\n exitCode: 2,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n\nimport { readdir, readFile, realpath, stat } from 'node:fs/promises';\n\nimport { writeTextAtomically } from './atomic-write.ts';\nimport { checkUsage, runCheckCommand } from './check-command.ts';\nimport type { CaptureFileSystem, CommandResult } from './command-support.ts';\nimport { doctorUsage, runDoctorCommand } from './doctor-command.ts';\nimport { initUsage, runInitCommand } from './init-command.ts';\nimport {\n extractJsUsage,\n type ExtractJsFileSystem,\n runExtractJsCommand,\n} from './extract-js-command.ts';\nimport { graphUsage, runGraphCommand } from './graph-command.ts';\nimport { diffUsage, runDiffCommand } from './diff-command.ts';\nimport { queryUsage, runQueryCommand } from './query-command.ts';\nimport { impactUsage, runImpactCommand } from './impact-command.ts';\nimport { runtimeUsage, runRuntimeCommand } from './runtime-command.ts';\nimport { preflightUsage, runPreflightCommand } from './preflight-command.ts';\nimport {\n retentionUsage,\n runRetentionsCommand,\n} from './retentions-command.ts';\nimport { runServeCommand, serveUsage } from './serve-command.ts';\n\nprocess.stdout.on('error', handleStreamError);\nprocess.stderr.on('error', handleStreamError);\n\nconst commandUsages = new Map([\n ['check', checkUsage],\n ['graph', graphUsage],\n ['diff', diffUsage],\n ['query', queryUsage],\n ['impact', impactUsage],\n ['preflight', preflightUsage],\n ['verify-runtime', runtimeUsage],\n ['retentions', retentionUsage],\n ['serve', serveUsage],\n ['extract-js', extractJsUsage],\n ['doctor', doctorUsage],\n ['init', initUsage],\n]);\n\nconst rootHelp = `Usage: isthmus <command> [options]\n\nCommands:\n check Report unmatched bridge calls and handlers\n query Find both sides of a channel or method\n impact Inspect bridge dependencies before changing files or symbols\n preflight Trace cross-language impact from producer analysis context\n verify-runtime Verify recorded calls against scenario expectations\n graph Render matched boundary edges\n diff Compare bridge observations before and after a change\n retentions Produce external retention evidence\n extract-js Extract React Native caller-side bridge facts from JS/TS\n doctor Validate a capture config and its executable paths\n init Write a capture config scaffold\n serve Speak MCP over stdio for agent clients\n help Show command help\n\nOptions:\n -h, --help Show help; after a command it shows that command's usage\n --version Show version\n`;\n\nconst arguments_ = process.argv.slice(2);\nconst readTextFile = (path: string) => readFile(path, 'utf8');\nconst writeTextFile = (path: string, text: string) =>\n writeTextAtomically(path, text);\n\n/** extract-js가 쓰는 실제 파일시스템 구현이다 — 테스트는 계약만 주입한다. */\nconst extractJsFileSystem: ExtractJsFileSystem = {\n statPath: async (path) => {\n try {\n const entry = await stat(path);\n return entry.isDirectory() ? 'directory' : 'file';\n } catch {\n return 'missing';\n }\n },\n listDirectory: async (path) =>\n (await readdir(path, { withFileTypes: true })).map((entry) => ({\n name: entry.name,\n isFile: entry.isFile(),\n isDirectory: entry.isDirectory(),\n })),\n realPath: (path) => realpath(path),\n};\n/** doctor·init이 쓰는 실제 파일시스템이다. producer는 실행하지 않는다. */\nconst captureFileSystem: CaptureFileSystem = {\n statPath: async (path) => {\n try {\n const entry = await stat(path);\n return entry.isDirectory() ? 'directory' : 'file';\n } catch {\n return 'missing';\n }\n },\n realPath: (path) => realpath(path),\n};\nconst informationalResult = await runInformationalCommand(arguments_);\nconst result = informationalResult ?? await dispatchCommand(arguments_);\n\nprocess.stdout.write(result.standardOutput);\nprocess.stderr.write(result.standardError);\nprocess.exitCode = result.exitCode;\n\n/** 파이프 소비자가 먼저 닫힌 정상 상황만 조용히 종료한다. */\nfunction handleStreamError(error: NodeJS.ErrnoException): void {\n if (error.code === 'EPIPE') {\n process.exitCode = 0;\n return;\n }\n throw error;\n}\n\n/** 도움말과 버전처럼 입력 문서가 필요 없는 명령을 실행한다. */\nasync function runInformationalCommand(\n commandArguments: readonly string[],\n): Promise<CommandResult | undefined> {\n // 도움말 플래그는 어느 위치에 있든 이긴다. 긴 호출 끝에 붙여도 사용법을 본다.\n const helpFlagIndex = commandArguments.findIndex(\n (argument) => argument === '--help' || argument === '-h',\n );\n if (helpFlagIndex >= 0) return commandHelp(commandArguments[0]);\n if (commandArguments[0] === 'help') {\n return commandHelp(commandArguments[1]);\n }\n if (\n commandArguments.length === 1 &&\n commandArguments[0] === '--version'\n ) {\n return readVersion();\n }\n return undefined;\n}\n\n/** 명령 이름에 맞는 사용법을, 모르면 루트 도움말을 돌려준다. */\nfunction commandHelp(command: string | undefined): CommandResult {\n if (command === undefined) return successfulText(rootHelp);\n const usage = commandUsages.get(command);\n return usage === undefined\n ? successfulText(rootHelp)\n : successfulText(`${usage}\\n`);\n}\n\n/** 알려진 분석 하위 명령으로만 라우팅한다. */\nasync function dispatchCommand(\n commandArguments: readonly string[],\n): Promise<CommandResult> {\n switch (commandArguments[0]) {\n case 'check':\n // SARIF driver에만 필요하므로 메타데이터 부재는 json 보고서를 막지 않는다.\n return runCheckCommand(\n commandArguments,\n readTextFile,\n writeTextFile,\n undefined,\n await readPackageVersion(),\n );\n case 'graph':\n return runGraphCommand(commandArguments, readTextFile);\n case 'diff':\n return runDiffCommand(commandArguments, readTextFile);\n case 'query':\n return runQueryCommand(commandArguments, readTextFile);\n case 'impact':\n return runImpactCommand(commandArguments, readTextFile);\n case 'preflight':\n return runPreflightCommand(commandArguments, readTextFile);\n case 'verify-runtime':\n return runRuntimeCommand(commandArguments, readTextFile);\n case 'extract-js':\n return runExtractJsCommand(\n commandArguments,\n extractJsFileSystem,\n readTextFile,\n () => new Date(),\n await readPackageVersion(),\n );\n case 'doctor':\n return runDoctorCommand(\n commandArguments,\n readTextFile,\n captureFileSystem,\n process.cwd(),\n process.env.PATH ?? '',\n );\n case 'init':\n return runInitCommand(\n commandArguments,\n readTextFile,\n writeTextFile,\n captureFileSystem,\n process.cwd(),\n );\n case 'serve':\n return runServeCommand(\n commandArguments,\n readTextFile,\n writeTextFile,\n await readPackageVersion(),\n );\n case 'retentions': {\n const version = await readPackageVersion();\n return version === undefined\n ? packageMetadataError()\n : runRetentionsCommand(\n commandArguments,\n readTextFile,\n () => new Date(),\n version,\n );\n }\n default:\n return {\n standardOutput: '',\n standardError: rootHelp,\n exitCode: 64,\n };\n }\n}\n\n/** 설치된 package.json을 단일 출처로 사용해 버전을 출력한다. */\nasync function readVersion(): Promise<CommandResult> {\n const version = await readPackageVersion();\n return version === undefined\n ? packageMetadataError()\n : successfulText(`${version}\\n`);\n}\n\n/** 설치된 package.json에서 검증된 버전 문자열을 읽는다. */\nasync function readPackageVersion(): Promise<string | undefined> {\n try {\n const text = await readFile(new URL('../../package.json', import.meta.url), 'utf8');\n const document: unknown = JSON.parse(text);\n return isVersionDocument(document) ? document.version : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** package metadata가 비어 있지 않은 버전을 제공하는지 확인한다. */\nfunction isVersionDocument(value: unknown): value is { readonly version: string } {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'version' in value &&\n typeof value.version === 'string' &&\n value.version.length > 0\n );\n}\n\n/** stdout 텍스트와 성공 종료 코드를 만든다. */\nfunction successfulText(standardOutput: string): CommandResult {\n return { standardOutput, standardError: '', exitCode: 0 };\n}\n\n/** package metadata 실패를 민감정보 없는 코드 2로 바꾼다. */\nfunction packageMetadataError(): CommandResult {\n return {\n standardOutput: '',\n standardError: 'Unable to read package metadata.\\n',\n exitCode: 2,\n };\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ReadTextFile, WriteTextFile } from './command-support.ts';
|
|
2
|
+
/** 세션이 외부에 필요로 하는 주입이다. */
|
|
3
|
+
export interface McpServerDependencies {
|
|
4
|
+
readonly readTextFile: ReadTextFile;
|
|
5
|
+
readonly writeTextFile?: WriteTextFile | undefined;
|
|
6
|
+
readonly producerVersion?: string | undefined;
|
|
7
|
+
}
|
|
8
|
+
/** JSON-RPC 메시지 한 건을 처리해 응답 라인을 반환하는 세션이다. */
|
|
9
|
+
export interface McpSession {
|
|
10
|
+
readonly handleLine: (line: string) => Promise<string | undefined>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* MCP 세션을 만든다. 반환된 handleLine은 한 줄의 JSON-RPC 메시지를 받아
|
|
14
|
+
* 응답이 필요하면 직렬화된 한 줄을, 알림이면 undefined를 돌려준다.
|
|
15
|
+
*/
|
|
16
|
+
export declare function createMcpSession(dependencies: McpServerDependencies): McpSession;
|