@obov/mext 0.3.1 → 0.4.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/dist/build.js +67 -4
- package/dist/build.js.map +1 -1
- package/dist/cli/ask-url.d.ts +16 -0
- package/dist/cli/ask-url.js +27 -0
- package/dist/cli/ask-url.js.map +1 -0
- package/dist/cli/build.js +7 -1
- package/dist/cli/build.js.map +1 -1
- package/dist/cli/dev-server.d.ts +7 -1
- package/dist/cli/dev-server.js +15 -2
- package/dist/cli/dev-server.js.map +1 -1
- package/dist/cli/dev.js +22 -7
- package/dist/cli/dev.js.map +1 -1
- package/dist/cli/login.d.ts +5 -0
- package/dist/cli/login.js +11 -7
- package/dist/cli/login.js.map +1 -1
- package/dist/cli/logout.js +4 -6
- package/dist/cli/logout.js.map +1 -1
- package/dist/cli/output.d.ts +1 -1
- package/dist/cli/output.js.map +1 -1
- package/dist/cli/run.js +7 -3
- package/dist/cli/run.js.map +1 -1
- package/dist/client/cache.d.ts +14 -4
- package/dist/client/cache.js +10 -3
- package/dist/client/cache.js.map +1 -1
- package/dist/client/main.js +11 -10
- package/dist/client/main.js.map +1 -1
- package/dist/client/manifest.d.ts +13 -1
- package/dist/client/manifest.js +43 -0
- package/dist/client/manifest.js.map +1 -1
- package/dist/client/runner.d.ts +3 -1
- package/dist/client/runner.js +80 -19
- package/dist/client/runner.js.map +1 -1
- package/dist/client/task.d.ts +47 -0
- package/dist/client/task.js +126 -0
- package/dist/client/task.js.map +1 -0
- package/dist/command.d.ts +30 -3
- package/dist/command.js +16 -0
- package/dist/command.js.map +1 -1
- package/dist/config.d.ts +40 -6
- package/dist/config.js +57 -8
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +3 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +17 -5
- package/dist/index.js +9 -2
- package/dist/index.js.map +1 -1
- package/dist/instrumentation.d.ts +14 -2
- package/dist/instrumentation.js +12 -4
- package/dist/instrumentation.js.map +1 -1
- package/dist/invoke.d.ts +38 -0
- package/dist/invoke.js +72 -3
- package/dist/invoke.js.map +1 -1
- package/dist/local-bin.js +5 -3
- package/dist/local-bin.js.map +1 -1
- package/dist/manifest.d.ts +48 -3
- package/dist/manifest.js +14 -3
- package/dist/manifest.js.map +1 -1
- package/dist/mcp/constants.d.ts +4 -0
- package/dist/mcp/constants.js +4 -0
- package/dist/mcp/constants.js.map +1 -1
- package/dist/mcp/dispatch.d.ts +21 -7
- package/dist/mcp/dispatch.js +42 -7
- package/dist/mcp/dispatch.js.map +1 -1
- package/dist/mcp/http.d.ts +23 -5
- package/dist/mcp/http.js +64 -9
- package/dist/mcp/http.js.map +1 -1
- package/dist/mcp/index.d.ts +14 -6
- package/dist/mcp/index.js +7 -3
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/mrtr.d.ts +40 -8
- package/dist/mcp/mrtr.js +32 -11
- package/dist/mcp/mrtr.js.map +1 -1
- package/dist/mcp/prompts.d.ts +25 -0
- package/dist/mcp/prompts.js +164 -0
- package/dist/mcp/prompts.js.map +1 -0
- package/dist/mcp/resources.d.ts +48 -0
- package/dist/mcp/resources.js +142 -0
- package/dist/mcp/resources.js.map +1 -0
- package/dist/mcp/server.d.ts +30 -5
- package/dist/mcp/server.js +143 -16
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/stdio.d.ts +5 -0
- package/dist/mcp/stdio.js +16 -3
- package/dist/mcp/stdio.js.map +1 -1
- package/dist/mcp/subscriptions.d.ts +61 -0
- package/dist/mcp/subscriptions.js +188 -0
- package/dist/mcp/subscriptions.js.map +1 -0
- package/dist/mcp/tasks.d.ts +127 -0
- package/dist/mcp/tasks.js +448 -0
- package/dist/mcp/tasks.js.map +1 -0
- package/dist/module-files.d.ts +24 -0
- package/dist/module-files.js +97 -0
- package/dist/module-files.js.map +1 -0
- package/dist/prompt.d.ts +133 -0
- package/dist/prompt.js +222 -0
- package/dist/prompt.js.map +1 -0
- package/dist/registry.d.ts +6 -0
- package/dist/registry.js.map +1 -1
- package/dist/remote/client.d.ts +17 -1
- package/dist/remote/client.js +18 -2
- package/dist/remote/client.js.map +1 -1
- package/dist/resource.d.ts +169 -0
- package/dist/resource.js +301 -0
- package/dist/resource.js.map +1 -0
- package/dist/route.d.ts +71 -0
- package/dist/route.js +280 -0
- package/dist/route.js.map +1 -0
- package/dist/start.d.ts +14 -3
- package/dist/start.js +76 -11
- package/dist/start.js.map +1 -1
- package/dist/state.d.ts +38 -0
- package/dist/state.js +98 -0
- package/dist/state.js.map +1 -0
- package/package.json +1 -1
package/dist/client/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/client/main.ts"],"names":[],"mappings":"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","sourcesContent":["import { table } from \"../cli/help.ts\"\nimport { resolveIo, type CliIo } from \"../cli/io.ts\"\nimport { loginCommand } from \"../cli/login.ts\"\nimport { logoutCommand } from \"../cli/logout.ts\"\nimport { EXIT, formatJson, type CliErrorFormatter } from \"../cli/output.ts\"\nimport { mcpInstallText } from \"../mcp/install.ts\"\nimport { envPrefix } from \"../remote/credentials.ts\"\nimport type { ClientManifest } from \"./manifest.ts\"\nimport { runRemote } from \"./runner.ts\"\n\n/**\n * 고객 CLI 런타임 (§5). mext build 가 이 모듈 + 설정 (CustomerCliConfig) 을 .mext/cli/bin.js 하나로 번들한다.\n * 번들 · 범용 형태가 같은 코드: manifest 가 있으면 help · 플래그 파싱을 내장 manifest 로, 없으면 서버 help 로.\n * 명령: <bin> help · <bin> <ns> <cmd> [flags] · login · logout · mcp install · --version. 원격 실행 = mext run --url 과 같은 runner\n */\n\n/** bin.js 에 인라인되는 설정 (mext build 가 생성) */\nexport interface CustomerCliConfig {\n bin: string\n /** 빌드 설정의 서버 MCP 엔드포인트. 실행 시 <BIN>_URL 이 있으면 그 값 */\n url: string\n /** --version · clientInfo.version */\n version: string\n packageName: string\n /** 빌드한 @obov/mext 버전 */\n mextVersion: string\n /** 빌드 시 manifestHash. 번들 형태 = 내장 manifest 의 해시 (서버 _meta[\"dev.mext/manifestHash\"] 와 비교) */\n manifestHash: string\n /** 번들 형태의 내장 manifest. 없음 = 범용 형태 */\n manifest?: ClientManifest\n}\n\n/** bin.js 에 번들되는 코드 (설정과 달리 JSON 이 아님) */\nexport interface CustomerCliHooks {\n /** cli.errors 모듈의 default export */\n formatError?: CliErrorFormatter\n}\n\nexport async function runCustomerCli(\n config: CustomerCliConfig,\n argv: readonly string[],\n partialIo: Partial<CliIo> = {},\n hooks: CustomerCliHooks = {},\n): Promise<number> {\n const io = resolveIo(partialIo)\n const { bin } = config\n const prefix = envPrefix(bin)\n const url = io.env[`${prefix}_URL`] || config.url\n if (!/^https?:\\/\\//i.test(url)) {\n io.stderr.write(`error: ${prefix}_URL must be an http(s) URL (got \"${url}\")\\n`)\n return EXIT.usage\n }\n const [first, ...rest] = argv\n switch (first) {\n case \"--version\":\n case \"-v\":\n io.stdout.write(`${config.version}\\n`)\n return EXIT.ok\n case \"login\":\n return loginCommand({ bin, url })(rest, io)\n case \"logout\":\n return logoutCommand({ bin, url })(rest, io)\n case \"mcp\":\n return mcp(config, url, rest, io)\n case \"__mext_inspect\":\n // 숨김: 지원 · 디버깅용 내장 설정 (토큰 없음)\n io.stdout.write(\n formatJson({\n bin,\n url,\n version: config.version,\n packageName: config.packageName,\n mextVersion: config.mextVersion,\n manifestHash: config.manifestHash,\n form: config.manifest ? \"bundled\" : \"universal\",\n }),\n )\n return EXIT.ok\n }\n return runRemote(\n {\n bin,\n url,\n prog: bin,\n login: `${bin} login`,\n version: config.version,\n ...(config.manifest ? { manifest: config.manifest, manifestHash: config.manifestHash } : {}),\n rootHelpFooter: builtinHelp(config, url),\n ...(hooks.formatError ? { formatError: hooks.formatError } : {}),\n },\n argv,\n io,\n )\n}\n\n/** 프로세스 진입점 (bin.js). 첫 SIGINT = 진행 중 요청 abort (exit 130), 두 번째 = 즉시 종료 */\nexport async function main(config: CustomerCliConfig, hooks: CustomerCliHooks = {}): Promise<void> {\n const controller = new AbortController()\n process.on(\"SIGINT\", () => {\n if (controller.signal.aborted) process.exit(130)\n controller.abort()\n })\n const code = await runCustomerCli(config, process.argv.slice(2), { signal: controller.signal }, hooks)\n process.stdout.write(\"\", () => process.stderr.write(\"\", () => process.exit(code)))\n}\n\nfunction mcp(config: CustomerCliConfig, url: string, argv: readonly string[], io: CliIo): number {\n const [sub, ...rest] = argv\n const isHelp = (t: string) => t === \"--help\" || t === \"-h\"\n const usage = `Usage:\\n ${config.bin} mcp install Print MCP client registration commands (does not modify client config files)\\n`\n if (sub !== undefined && (isHelp(sub) || (sub === \"install\" && rest.some(isHelp)))) {\n io.stdout.write(usage)\n return EXIT.ok\n }\n if (sub === \"install\" && rest.length === 0) {\n io.stdout.write(`${mcpInstallText({ name: config.bin, url, stdioCommand: false, auth: true })}\\n`)\n return EXIT.ok\n }\n io.stderr.write(`error: ${sub === undefined ? \"missing subcommand\" : `unknown argument \"${argv.join(\" \")}\"`}\\n\\n${usage}`)\n return EXIT.usage\n}\n\n/** 사람용 루트 help 뒤의 내장 명령 · 환경변수 */\nfunction builtinHelp(config: CustomerCliConfig, url: string): string {\n const { bin } = config\n const prefix = envPrefix(bin)\n return [\n \"CLI commands:\",\n ...table([\n [\"login\", `Log in to ${url} (${bin} login --help)`],\n [\"logout\", \"Revoke and remove the stored token\"],\n [\"mcp install\", \"Print MCP client registration commands\"],\n [\"--version\", \"Print the version\"],\n ]).map((l) => ` ${l}`),\n \"\",\n \"Environment:\",\n ...table([\n [`${prefix}_TOKEN`, `API token (instead of ${bin} login)`],\n [`${prefix}_URL`, `Server URL (default: ${config.url})`],\n ]).map((l) => ` ${l}`),\n \"\",\n ].join(\"\\n\")\n}\n"]}
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/client/main.ts"],"names":[],"mappings":"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","sourcesContent":["import { table } from \"../cli/help.ts\"\nimport { resolveIo, type CliIo } from \"../cli/io.ts\"\nimport { loginCommand } from \"../cli/login.ts\"\nimport { logoutCommand } from \"../cli/logout.ts\"\nimport { emitError, EXIT, formatJson, type CliErrorFormatter } from \"../cli/output.ts\"\nimport { mcpInstallText } from \"../mcp/install.ts\"\nimport { envPrefix } from \"../remote/credentials.ts\"\nimport type { ClientManifest } from \"./manifest.ts\"\nimport { runRemote } from \"./runner.ts\"\n\n/**\n * 고객 CLI 런타임 (§5). mext build 가 이 모듈 + 설정 (CustomerCliConfig) 을 .mext/cli/bin.js 하나로 번들한다.\n * 번들 · 범용 형태가 같은 코드: manifest 가 있으면 help · 플래그 파싱을 내장 manifest 로, 없으면 서버 help 로.\n * 명령: <bin> help · <bin> <ns> <cmd> [flags] · login · logout · mcp install · --version. 원격 실행 = mext run --url 과 같은 runner\n */\n\n/** bin.js 에 인라인되는 설정 (mext build 가 생성) */\nexport interface CustomerCliConfig {\n bin: string\n /** 빌드 설정의 서버 MCP 엔드포인트. 실행 시 <BIN>_URL 이 있으면 그 값 */\n url: string\n /** --version · clientInfo.version */\n version: string\n packageName: string\n /** 빌드한 @obov/mext 버전 */\n mextVersion: string\n /** 빌드 시 manifestHash. 번들 형태 = 내장 manifest 의 해시 (서버 _meta[\"dev.mext/manifestHash\"] 와 비교) */\n manifestHash: string\n /** 번들 형태의 내장 manifest. 없음 = 범용 형태 */\n manifest?: ClientManifest\n}\n\n/** bin.js 에 번들되는 코드 (설정과 달리 JSON 이 아님) */\nexport interface CustomerCliHooks {\n /** cli.errors 모듈의 default export */\n formatError?: CliErrorFormatter\n}\n\nexport async function runCustomerCli(\n config: CustomerCliConfig,\n argv: readonly string[],\n partialIo: Partial<CliIo> = {},\n hooks: CustomerCliHooks = {},\n): Promise<number> {\n const io = resolveIo(partialIo)\n const { bin } = config\n const prefix = envPrefix(bin)\n const url = io.env[`${prefix}_URL`] || config.url\n const formatter = hooks.formatError\n if (!/^https?:\\/\\//i.test(url)) {\n const message = `${prefix}_URL must be an http(s) URL (got \"${url}\")`\n return emitError(io, { body: { code: \"INVALID_ARGUMENT\", message }, text: `error: ${message}\\n`, exitCode: EXIT.usage, json: false }, formatter)\n }\n const [first, ...rest] = argv\n switch (first) {\n case \"--version\":\n case \"-v\":\n io.stdout.write(`${config.version}\\n`)\n return EXIT.ok\n case \"login\":\n return loginCommand({ bin, url, ...(formatter ? { formatter } : {}) })(rest, io)\n case \"logout\":\n return logoutCommand({ bin, url, ...(formatter ? { formatter } : {}) })(rest, io)\n case \"mcp\":\n return mcp(config, url, rest, io, formatter)\n case \"__mext_inspect\":\n // 숨김: 지원 · 디버깅용 내장 설정 (토큰 없음)\n io.stdout.write(\n formatJson({\n bin,\n url,\n version: config.version,\n packageName: config.packageName,\n mextVersion: config.mextVersion,\n manifestHash: config.manifestHash,\n form: config.manifest ? \"bundled\" : \"universal\",\n }),\n )\n return EXIT.ok\n }\n return runRemote(\n {\n bin,\n url,\n prog: bin,\n login: `${bin} login`,\n version: config.version,\n ...(config.manifest ? { manifest: config.manifest, manifestHash: config.manifestHash } : {}),\n rootHelpFooter: builtinHelp(config, url),\n ...(formatter ? { formatError: formatter } : {}),\n },\n argv,\n io,\n )\n}\n\n/** 프로세스 진입점 (bin.js). 첫 SIGINT = 진행 중 요청 abort (exit 130), 두 번째 = 즉시 종료 */\nexport async function main(config: CustomerCliConfig, hooks: CustomerCliHooks = {}): Promise<void> {\n const controller = new AbortController()\n process.on(\"SIGINT\", () => {\n if (controller.signal.aborted) process.exit(130)\n controller.abort()\n })\n const code = await runCustomerCli(config, process.argv.slice(2), { signal: controller.signal }, hooks)\n process.stdout.write(\"\", () => process.stderr.write(\"\", () => process.exit(code)))\n}\n\nfunction mcp(config: CustomerCliConfig, url: string, argv: readonly string[], io: CliIo, formatter: CliErrorFormatter | undefined): number {\n const [sub, ...rest] = argv\n const isHelp = (t: string) => t === \"--help\" || t === \"-h\"\n const usage = `Usage:\\n ${config.bin} mcp install Print MCP client registration commands (does not modify client config files)\\n`\n if (sub !== undefined && (isHelp(sub) || (sub === \"install\" && rest.some(isHelp)))) {\n io.stdout.write(usage)\n return EXIT.ok\n }\n if (sub === \"install\" && rest.length === 0) {\n io.stdout.write(`${mcpInstallText({ name: config.bin, url, stdioCommand: false, auth: true })}\\n`)\n return EXIT.ok\n }\n const message = sub === undefined ? \"missing subcommand\" : `unknown argument \"${argv.join(\" \")}\"`\n return emitError(io, { body: { code: \"INVALID_ARGUMENT\", message }, text: `error: ${message}\\n\\n${usage}`, exitCode: EXIT.usage, json: false }, formatter)\n}\n\n/** 사람용 루트 help 뒤의 내장 명령 · 환경변수 */\nfunction builtinHelp(config: CustomerCliConfig, url: string): string {\n const { bin } = config\n const prefix = envPrefix(bin)\n return [\n \"CLI commands:\",\n ...table([\n [\"login\", `Log in to ${url} (${bin} login --help)`],\n [\"logout\", \"Revoke and remove the stored token\"],\n [\"mcp install\", \"Print MCP client registration commands\"],\n [\"--version\", \"Print the version\"],\n ]).map((l) => ` ${l}`),\n \"\",\n \"Environment:\",\n ...table([\n [`${prefix}_TOKEN`, `API token (instead of ${bin} login)`],\n [`${prefix}_URL`, `Server URL (default: ${config.url})`],\n ]).map((l) => ` ${l}`),\n \"\",\n ].join(\"\\n\")\n}\n"]}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { type RemoteTool } from "../remote/client.ts";
|
|
1
2
|
import type { Manifest, ManifestCommand, ManifestNamespace } from "../manifest.ts";
|
|
3
|
+
import type { ToolExposure } from "../mcp/dispatch.ts";
|
|
2
4
|
import type { Help } from "../mcp/help.ts";
|
|
3
5
|
/**
|
|
4
6
|
* 고객 CLI 번들 형태의 내장 manifest = 빌드 manifest 에서 서버 전용 항목 (file · module · 빌드 경로) 을 뺀 것.
|
|
@@ -6,6 +8,8 @@ import type { Help } from "../mcp/help.ts";
|
|
|
6
8
|
*/
|
|
7
9
|
export type ClientManifestCommand = Omit<ManifestCommand, "file">;
|
|
8
10
|
export interface ClientManifest {
|
|
11
|
+
/** 서버 도구 노출 방식 (빌드 manifest tools). command = 명령어 ID 를 도구 이름으로 호출. 없음 = dispatcher (execute · split) */
|
|
12
|
+
tools?: ToolExposure;
|
|
9
13
|
/** commands/_index.md */
|
|
10
14
|
description?: string;
|
|
11
15
|
/** 루트 제외, ID 순 */
|
|
@@ -14,6 +18,14 @@ export interface ClientManifest {
|
|
|
14
18
|
commands: ClientManifestCommand[];
|
|
15
19
|
}
|
|
16
20
|
/** 빌드 manifest → 내장 manifest (mext build 가 호출) */
|
|
17
|
-
export declare function clientManifest(manifest: Pick<Manifest, "description" | "namespaces" | "commands">
|
|
21
|
+
export declare function clientManifest(manifest: Pick<Manifest, "description" | "namespaces" | "commands"> & {
|
|
22
|
+
tools?: ToolExposure;
|
|
23
|
+
}): ClientManifest;
|
|
24
|
+
/**
|
|
25
|
+
* command 노출 서버의 tools/list → manifest (범용 형태 · stale 번들의 help · 플래그 파싱, §12.2).
|
|
26
|
+
* 명령어 = 도구 (이름 = ID · description · inputSchema · outputSchema) + _meta[COMMAND_META_KEY] (별칭 · 안전성 · scopes ·
|
|
27
|
+
* positional · examples · task, 없으면 annotations 의 readOnlyHint · destructiveHint). 네임스페이스 = ID 의 상위 경로 (설명 없음)
|
|
28
|
+
*/
|
|
29
|
+
export declare function manifestFromTools(tools: readonly RemoteTool[]): ClientManifest;
|
|
18
30
|
/** 내장 manifest 의 help (target "" = 루트 · 네임스페이스 · 명령어 ID · 별칭). 없는 target = UNKNOWN_COMMAND */
|
|
19
31
|
export declare function manifestHelp(manifest: ClientManifest, target: string): Help;
|
package/dist/client/manifest.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { parentNamespace } from "../ids.js";
|
|
2
|
+
import { COMMAND_META_KEY } from "../mcp/constants.js";
|
|
3
|
+
import { isRecord } from "../remote/client.js";
|
|
2
4
|
import { unknownCommand } from "../lookup.js";
|
|
3
5
|
/** 빌드 manifest → 내장 manifest (mext build 가 호출) */
|
|
4
6
|
export function clientManifest(manifest) {
|
|
5
7
|
const out = {
|
|
8
|
+
...(manifest.tools !== undefined ? { tools: manifest.tools } : {}),
|
|
6
9
|
namespaces: manifest.namespaces.map((n) => ({ ...n })),
|
|
7
10
|
commands: manifest.commands.map((c) => {
|
|
8
11
|
const { file: _file, module: _module, ...rest } = c;
|
|
@@ -13,6 +16,46 @@ export function clientManifest(manifest) {
|
|
|
13
16
|
out.description = manifest.description;
|
|
14
17
|
return out;
|
|
15
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* command 노출 서버의 tools/list → manifest (범용 형태 · stale 번들의 help · 플래그 파싱, §12.2).
|
|
21
|
+
* 명령어 = 도구 (이름 = ID · description · inputSchema · outputSchema) + _meta[COMMAND_META_KEY] (별칭 · 안전성 · scopes ·
|
|
22
|
+
* positional · examples · task, 없으면 annotations 의 readOnlyHint · destructiveHint). 네임스페이스 = ID 의 상위 경로 (설명 없음)
|
|
23
|
+
*/
|
|
24
|
+
export function manifestFromTools(tools) {
|
|
25
|
+
const commands = [];
|
|
26
|
+
const namespaces = new Set();
|
|
27
|
+
for (const tool of tools) {
|
|
28
|
+
const meta = isRecord(tool._meta) && isRecord(tool._meta[COMMAND_META_KEY]) ? tool._meta[COMMAND_META_KEY] : {};
|
|
29
|
+
const hints = isRecord(tool.annotations) ? tool.annotations : {};
|
|
30
|
+
const flag = (key, hint) => (typeof meta[key] === "boolean" ? meta[key] : hint === true);
|
|
31
|
+
const strings = (key) => Array.isArray(meta[key]) ? meta[key].filter((v) => typeof v === "string") : [];
|
|
32
|
+
const command = {
|
|
33
|
+
id: tool.name,
|
|
34
|
+
description: tool.description ?? "",
|
|
35
|
+
aliases: strings("aliases"),
|
|
36
|
+
readOnly: flag("readOnly", hints.readOnlyHint),
|
|
37
|
+
destructive: flag("destructive", hints.readOnlyHint === true ? false : hints.destructiveHint),
|
|
38
|
+
requiresConfirmation: flag("requiresConfirmation", false),
|
|
39
|
+
scopes: strings("scopes"),
|
|
40
|
+
positional: strings("positional"),
|
|
41
|
+
examples: Array.isArray(meta.examples) ? [...meta.examples] : [],
|
|
42
|
+
inputSchema: tool.inputSchema ?? { type: "object" },
|
|
43
|
+
};
|
|
44
|
+
if (isRecord(tool.outputSchema))
|
|
45
|
+
command.outputSchema = tool.outputSchema;
|
|
46
|
+
if (isRecord(meta.task) && typeof meta.task.ttlMs === "number")
|
|
47
|
+
command.task = { ttlMs: meta.task.ttlMs };
|
|
48
|
+
commands.push(command);
|
|
49
|
+
for (let ns = parentNamespace(tool.name); ns !== ""; ns = parentNamespace(ns))
|
|
50
|
+
namespaces.add(ns);
|
|
51
|
+
}
|
|
52
|
+
const byId = (a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
|
|
53
|
+
return {
|
|
54
|
+
tools: "command",
|
|
55
|
+
namespaces: [...namespaces].map((id) => ({ id })).sort(byId),
|
|
56
|
+
commands: commands.sort(byId),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
16
59
|
/** 내장 manifest 의 help (target "" = 루트 · 네임스페이스 · 명령어 ID · 별칭). 없는 target = UNKNOWN_COMMAND */
|
|
17
60
|
export function manifestHelp(manifest, target) {
|
|
18
61
|
const id = target.trim();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/client/manifest.ts"],"names":[],"mappings":"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","sourcesContent":["import { parentNamespace } from \"../ids.ts\"\nimport { unknownCommand } from \"../lookup.ts\"\nimport type { Manifest, ManifestCommand, ManifestNamespace } from \"../manifest.ts\"\nimport type { CommandHelp, Help, HelpCommandSummary, HelpNamespaceSummary, NamespaceHelp, RootHelp } from \"../mcp/help.ts\"\n\n/**\n * 고객 CLI 번들 형태의 내장 manifest = 빌드 manifest 에서 서버 전용 항목 (file · module · 빌드 경로) 을 뺀 것.\n * help 결과는 서버 help (mcp/help.ts help()) 와 같은 모양 (split 노출의 tool 필드 제외)\n */\n\nexport type ClientManifestCommand = Omit<ManifestCommand, \"file\">\n\nexport interface ClientManifest {\n /** commands/_index.md */\n description?: string\n /** 루트 제외, ID 순 */\n namespaces: ManifestNamespace[]\n /** ID 순 */\n commands: ClientManifestCommand[]\n}\n\n/** 빌드 manifest → 내장 manifest (mext build 가 호출) */\nexport function clientManifest(manifest: Pick<Manifest, \"description\" | \"namespaces\" | \"commands\">): ClientManifest {\n const out: ClientManifest = {\n namespaces: manifest.namespaces.map((n) => ({ ...n })),\n commands: manifest.commands.map((c) => {\n const { file: _file, module: _module, ...rest } = c as ManifestCommand & { module?: string }\n return rest\n }),\n }\n if (manifest.description !== undefined) out.description = manifest.description\n return out\n}\n\n/** 내장 manifest 의 help (target \"\" = 루트 · 네임스페이스 · 명령어 ID · 별칭). 없는 target = UNKNOWN_COMMAND */\nexport function manifestHelp(manifest: ClientManifest, target: string): Help {\n const id = target.trim()\n const namespaces = new Map(manifest.namespaces.map((n) => [n.id, n]))\n const children = (ns: string) => ({\n namespaces: manifest.namespaces.filter((n) => parentNamespace(n.id) === ns).map(namespaceSummary),\n commands: manifest.commands.filter((c) => parentNamespace(c.id) === ns).map(commandSummary),\n })\n // 키 순서 = 서버 help (--help --json 출력이 같은 텍스트)\n if (id === \"\") {\n const out: RootHelp = { kind: \"root\", ...children(\"\") }\n if (manifest.description !== undefined) out.description = manifest.description\n return out\n }\n const ns = namespaces.get(id)\n if (ns) {\n const out: NamespaceHelp = { kind: \"namespace\", id, ...children(id) }\n if (ns.description !== undefined) out.description = ns.description\n const self = manifest.commands.find((c) => c.id === id)\n if (self) out.command = commandHelp(self)\n return out\n }\n const command = manifest.commands.find((c) => c.id === id) ?? manifest.commands.find((c) => c.aliases.includes(id))\n if (command) return commandHelp(command)\n throw unknownCommand(\n id,\n manifest.commands.flatMap((c): [string, string][] => [[c.id, c.id], ...c.aliases.map((a): [string, string] => [a, c.id])]),\n (n) => namespaces.has(n),\n )\n}\n\nfunction namespaceSummary(ns: ManifestNamespace): HelpNamespaceSummary {\n const first = ns.description?.split(\"\\n\").find((l) => l.trim() !== \"\")\n return first === undefined ? { id: ns.id } : { id: ns.id, description: first.replace(/^#+\\s*/, \"\").trim() }\n}\n\nfunction commandSummary(c: ClientManifestCommand): HelpCommandSummary {\n return {\n id: c.id,\n description: c.description,\n readOnly: c.readOnly,\n destructive: c.destructive,\n requiresConfirmation: c.requiresConfirmation,\n }\n}\n\n/** mcp/help.ts commandHelp 와 같은 errors 규칙 */\nfunction commandHelp(c: ClientManifestCommand): CommandHelp {\n const errors = [\"INVALID_ARGUMENT\"]\n if (!c.readOnly || c.scopes.length > 0) errors.push(\"UNAUTHENTICATED\", \"PERMISSION_DENIED\")\n if (c.requiresConfirmation) errors.push(\"INPUT_UNAVAILABLE\", \"INPUT_DECLINED\")\n return { kind: \"command\", ...c, errors }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/client/manifest.ts"],"names":[],"mappings":"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","sourcesContent":["import { parentNamespace } from \"../ids.ts\"\nimport { COMMAND_META_KEY } from \"../mcp/constants.ts\"\nimport { isRecord, type RemoteTool } from \"../remote/client.ts\"\nimport { unknownCommand } from \"../lookup.ts\"\nimport type { Manifest, ManifestCommand, ManifestNamespace } from \"../manifest.ts\"\nimport type { ToolExposure } from \"../mcp/dispatch.ts\"\nimport type { CommandHelp, Help, HelpCommandSummary, HelpNamespaceSummary, NamespaceHelp, RootHelp } from \"../mcp/help.ts\"\n\n/**\n * 고객 CLI 번들 형태의 내장 manifest = 빌드 manifest 에서 서버 전용 항목 (file · module · 빌드 경로) 을 뺀 것.\n * help 결과는 서버 help (mcp/help.ts help()) 와 같은 모양 (split 노출의 tool 필드 제외)\n */\n\nexport type ClientManifestCommand = Omit<ManifestCommand, \"file\">\n\nexport interface ClientManifest {\n /** 서버 도구 노출 방식 (빌드 manifest tools). command = 명령어 ID 를 도구 이름으로 호출. 없음 = dispatcher (execute · split) */\n tools?: ToolExposure\n /** commands/_index.md */\n description?: string\n /** 루트 제외, ID 순 */\n namespaces: ManifestNamespace[]\n /** ID 순 */\n commands: ClientManifestCommand[]\n}\n\n/** 빌드 manifest → 내장 manifest (mext build 가 호출) */\nexport function clientManifest(\n manifest: Pick<Manifest, \"description\" | \"namespaces\" | \"commands\"> & { tools?: ToolExposure },\n): ClientManifest {\n const out: ClientManifest = {\n ...(manifest.tools !== undefined ? { tools: manifest.tools } : {}),\n namespaces: manifest.namespaces.map((n) => ({ ...n })),\n commands: manifest.commands.map((c) => {\n const { file: _file, module: _module, ...rest } = c as ManifestCommand & { module?: string }\n return rest\n }),\n }\n if (manifest.description !== undefined) out.description = manifest.description\n return out\n}\n\n/**\n * command 노출 서버의 tools/list → manifest (범용 형태 · stale 번들의 help · 플래그 파싱, §12.2).\n * 명령어 = 도구 (이름 = ID · description · inputSchema · outputSchema) + _meta[COMMAND_META_KEY] (별칭 · 안전성 · scopes ·\n * positional · examples · task, 없으면 annotations 의 readOnlyHint · destructiveHint). 네임스페이스 = ID 의 상위 경로 (설명 없음)\n */\nexport function manifestFromTools(tools: readonly RemoteTool[]): ClientManifest {\n const commands: ClientManifestCommand[] = []\n const namespaces = new Set<string>()\n for (const tool of tools) {\n const meta = isRecord(tool._meta) && isRecord(tool._meta[COMMAND_META_KEY]) ? tool._meta[COMMAND_META_KEY] : {}\n const hints = isRecord(tool.annotations) ? tool.annotations : {}\n const flag = (key: string, hint: unknown): boolean => (typeof meta[key] === \"boolean\" ? meta[key] : hint === true)\n const strings = (key: string): string[] =>\n Array.isArray(meta[key]) ? meta[key].filter((v): v is string => typeof v === \"string\") : []\n const command: ClientManifestCommand = {\n id: tool.name,\n description: tool.description ?? \"\",\n aliases: strings(\"aliases\"),\n readOnly: flag(\"readOnly\", hints.readOnlyHint),\n destructive: flag(\"destructive\", hints.readOnlyHint === true ? false : hints.destructiveHint),\n requiresConfirmation: flag(\"requiresConfirmation\", false),\n scopes: strings(\"scopes\"),\n positional: strings(\"positional\"),\n examples: Array.isArray(meta.examples) ? [...meta.examples] : [],\n inputSchema: tool.inputSchema ?? { type: \"object\" },\n }\n if (isRecord(tool.outputSchema)) command.outputSchema = tool.outputSchema\n if (isRecord(meta.task) && typeof meta.task.ttlMs === \"number\") command.task = { ttlMs: meta.task.ttlMs }\n commands.push(command)\n for (let ns = parentNamespace(tool.name); ns !== \"\"; ns = parentNamespace(ns)) namespaces.add(ns)\n }\n const byId = (a: { id: string }, b: { id: string }) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)\n return {\n tools: \"command\",\n namespaces: [...namespaces].map((id) => ({ id })).sort(byId),\n commands: commands.sort(byId),\n }\n}\n\n/** 내장 manifest 의 help (target \"\" = 루트 · 네임스페이스 · 명령어 ID · 별칭). 없는 target = UNKNOWN_COMMAND */\nexport function manifestHelp(manifest: ClientManifest, target: string): Help {\n const id = target.trim()\n const namespaces = new Map(manifest.namespaces.map((n) => [n.id, n]))\n const children = (ns: string) => ({\n namespaces: manifest.namespaces.filter((n) => parentNamespace(n.id) === ns).map(namespaceSummary),\n commands: manifest.commands.filter((c) => parentNamespace(c.id) === ns).map(commandSummary),\n })\n // 키 순서 = 서버 help (--help --json 출력이 같은 텍스트)\n if (id === \"\") {\n const out: RootHelp = { kind: \"root\", ...children(\"\") }\n if (manifest.description !== undefined) out.description = manifest.description\n return out\n }\n const ns = namespaces.get(id)\n if (ns) {\n const out: NamespaceHelp = { kind: \"namespace\", id, ...children(id) }\n if (ns.description !== undefined) out.description = ns.description\n const self = manifest.commands.find((c) => c.id === id)\n if (self) out.command = commandHelp(self)\n return out\n }\n const command = manifest.commands.find((c) => c.id === id) ?? manifest.commands.find((c) => c.aliases.includes(id))\n if (command) return commandHelp(command)\n throw unknownCommand(\n id,\n manifest.commands.flatMap((c): [string, string][] => [[c.id, c.id], ...c.aliases.map((a): [string, string] => [a, c.id])]),\n (n) => namespaces.has(n),\n )\n}\n\nfunction namespaceSummary(ns: ManifestNamespace): HelpNamespaceSummary {\n const first = ns.description?.split(\"\\n\").find((l) => l.trim() !== \"\")\n return first === undefined ? { id: ns.id } : { id: ns.id, description: first.replace(/^#+\\s*/, \"\").trim() }\n}\n\nfunction commandSummary(c: ClientManifestCommand): HelpCommandSummary {\n return {\n id: c.id,\n description: c.description,\n readOnly: c.readOnly,\n destructive: c.destructive,\n requiresConfirmation: c.requiresConfirmation,\n }\n}\n\n/** mcp/help.ts commandHelp 와 같은 errors 규칙 */\nfunction commandHelp(c: ClientManifestCommand): CommandHelp {\n const errors = [\"INVALID_ARGUMENT\"]\n if (!c.readOnly || c.scopes.length > 0) errors.push(\"UNAUTHENTICATED\", \"PERMISSION_DENIED\")\n if (c.requiresConfirmation) errors.push(\"INPUT_UNAVAILABLE\", \"INPUT_DECLINED\")\n return { kind: \"command\", ...c, errors }\n}\n"]}
|
package/dist/client/runner.d.ts
CHANGED
|
@@ -5,10 +5,12 @@ import { type CliErrorFormatter } from "../cli/output.ts";
|
|
|
5
5
|
import { type ClientManifest } from "./manifest.ts";
|
|
6
6
|
/**
|
|
7
7
|
* 원격 실행 공용 runner: mext run --url (bin = mext) 과 고객 CLI (bin = cli.bin) 가 같은 코드 경로.
|
|
8
|
-
* 서버 MCP 엔드포인트의 dispatcher 도구 (execute · split 의 query · mutate)
|
|
8
|
+
* 서버 MCP 엔드포인트의 dispatcher 도구 (execute · split 의 query · mutate) 또는 명령어별 도구 (command 노출, §12.2) 호출.
|
|
9
|
+
* 노출 방식 = 번들 형태의 내장 manifest tools, 범용 = server/discover _meta["dev.mext/tools"]. 권한 검사는 서버만.
|
|
9
10
|
* 경로 해석 · help · 플래그 파싱 = HelpSource (캐시 · 내장 manifest · 서버 help, client/cache.ts) 의 입력 스키마 (JSON Schema).
|
|
10
11
|
* 로컬 파싱 실패 (UNKNOWN_COMMAND · INVALID_ARGUMENT) = 서버 help 로 1회 재시도. tools/call 결과의 manifestHash 로 drift 감지.
|
|
11
12
|
* 토큰 = <BIN>_TOKEN, 없으면 저장된 토큰 (<bin> login). 출력 · exit code 는 로컬 모드와 같다.
|
|
13
|
+
* tasks 확장 선언 (§12.6): task 응답 = 종료까지 폴링 (client/task.ts), 결과 처리는 동기와 같다.
|
|
12
14
|
*
|
|
13
15
|
* 이 모듈 (와 import 대상) 은 고객 CLI 번들에 들어간다: Zod · MCP 서버 SDK · 핸들러 · 스캔 · 빌드 코드 import 금지.
|
|
14
16
|
*/
|
package/dist/client/runner.js
CHANGED
|
@@ -6,12 +6,14 @@ import { credentialStore, envPrefix } from "../remote/credentials.js";
|
|
|
6
6
|
import { isExpired, OAuthFlowError, refreshCredentials } from "../remote/oauth.js";
|
|
7
7
|
import { cliSpecFromJsonSchema, coerceValue, defineCliSpec, parseArgs } from "../cli/args.js";
|
|
8
8
|
import { cliPath, renderHelp } from "../cli/help.js";
|
|
9
|
+
import { askUrl } from "../cli/ask-url.js";
|
|
9
10
|
import { createLineReader, readAll } from "../cli/io.js";
|
|
10
11
|
import { CliInterrupted, emitError, EXIT, errorJson, exitCodeOf, formatError, formatJson, formatProgress, formatResult, } from "../cli/output.js";
|
|
11
|
-
import { MANIFEST_HASH_META_KEY } from "../mcp/constants.js";
|
|
12
|
+
import { MANIFEST_HASH_META_KEY, TOOLS_META_KEY } from "../mcp/constants.js";
|
|
12
13
|
import { VERSION } from "../version.js";
|
|
13
14
|
import { openSchema, schemaCacheDir, schemaCacheFile } from "./cache.js";
|
|
14
|
-
import { manifestHelp } from "./manifest.js";
|
|
15
|
+
import { manifestFromTools, manifestHelp } from "./manifest.js";
|
|
16
|
+
import { awaitTask, formatTaskStatus, isTaskResult, RemoteTaskError } from "./task.js";
|
|
15
17
|
export async function runRemote(options, argv, io) {
|
|
16
18
|
const { url, prog } = options;
|
|
17
19
|
const tokenEnv = `${envPrefix(options.bin)}_TOKEN`;
|
|
@@ -114,9 +116,13 @@ export async function runRemote(options, argv, io) {
|
|
|
114
116
|
}
|
|
115
117
|
const { command, entry } = planned;
|
|
116
118
|
const yes = lead.yes || planned.yes;
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
const
|
|
119
|
+
// command 노출 (§12.2) = 도구 이름 = 정식 ID, 인자 = input. 그 외 = dispatcher { command, args }
|
|
120
|
+
const exposed = (await exposureOf(options, schema)) === "command";
|
|
121
|
+
const tool = exposed ? { name: entry.id, inputSchema: command.inputSchema } : commandTool(dispatcherOf(url, await schema.tools()), command);
|
|
122
|
+
const input = planned.input;
|
|
123
|
+
const args = exposed ? input : { command: entry.id, args: input };
|
|
124
|
+
const onInputRequired = inputHandler(io, lines, yes, json, entry.id, controller.signal);
|
|
125
|
+
let result = await s.call((o) => s.client.callTool(tool, args, {
|
|
120
126
|
...o,
|
|
121
127
|
progressToken: "mext-cli",
|
|
122
128
|
onNotification: (method, params) => {
|
|
@@ -129,8 +135,18 @@ export async function runRemote(options, argv, io) {
|
|
|
129
135
|
update.message = params.message;
|
|
130
136
|
io.stderr.write(formatProgress(update));
|
|
131
137
|
},
|
|
132
|
-
onInputRequired
|
|
138
|
+
onInputRequired,
|
|
133
139
|
}));
|
|
140
|
+
// tasks 확장 (§12.6): 종료까지 폴링 → completed result = 동기 결과와 같은 경로 (출력 · exit code)
|
|
141
|
+
if (isTaskResult(result)) {
|
|
142
|
+
result = await awaitTask(result, {
|
|
143
|
+
client: s.client,
|
|
144
|
+
call: (fn) => s.call(fn),
|
|
145
|
+
signal: controller.signal,
|
|
146
|
+
onInputRequired,
|
|
147
|
+
onStatus: (message) => io.stderr.write(formatTaskStatus(message)),
|
|
148
|
+
});
|
|
149
|
+
}
|
|
134
150
|
// drift: 이번 결과는 그대로, 다르면 캐시 stale (다음 실행에서 서버 help)
|
|
135
151
|
schema.observe(metaHash(result));
|
|
136
152
|
if (result.isError === true)
|
|
@@ -152,6 +168,10 @@ export async function runRemote(options, argv, io) {
|
|
|
152
168
|
await schema?.save();
|
|
153
169
|
}
|
|
154
170
|
}
|
|
171
|
+
/** 서버 도구 노출 방식: 번들 형태 = 내장 manifest tools, 범용 = server/discover _meta["dev.mext/tools"] (스키마 캐시) */
|
|
172
|
+
async function exposureOf(options, schema) {
|
|
173
|
+
return options.manifest ? options.manifest.tools : schema.exposure();
|
|
174
|
+
}
|
|
155
175
|
/** 서버 help 재조회 대상 로컬 오류 */
|
|
156
176
|
function isLocalParseFailure(error) {
|
|
157
177
|
return error instanceof MextError && (error.code === "UNKNOWN_COMMAND" || error.code === "INVALID_ARGUMENT");
|
|
@@ -172,11 +192,19 @@ function openRunSchema(options, s, ctx, io) {
|
|
|
172
192
|
...(options.manifest && options.manifestHash !== undefined
|
|
173
193
|
? { embedded: { manifest: options.manifest, hash: options.manifestHash } }
|
|
174
194
|
: {}),
|
|
175
|
-
fetchHelp: serverHelpFetcher(s, ctx),
|
|
195
|
+
fetchHelp: serverHelpFetcher(s, ctx, options.manifest?.tools),
|
|
176
196
|
fetchTools: async () => {
|
|
197
|
+
// 범용 형태 = 노출 방식을 server/discover 로 (번들 = 내장 manifest, 조회 안 함).
|
|
198
|
+
// 순차: 401 → refresh 1회 규칙 (Session.call) 을 동시 요청이 나눠 쓰지 않게
|
|
177
199
|
const r = await s.call((o) => s.client.listToolsResult(o));
|
|
178
|
-
|
|
179
|
-
|
|
200
|
+
const exposure = options.manifest ? undefined : await discoverExposure(s);
|
|
201
|
+
if ((options.manifest?.tools ?? exposure) !== "command")
|
|
202
|
+
dispatcherOf(s.url, r.tools);
|
|
203
|
+
return {
|
|
204
|
+
tools: r.tools,
|
|
205
|
+
...(r.ttlMs !== undefined ? { ttlMs: r.ttlMs } : {}),
|
|
206
|
+
...(exposure !== undefined ? { exposure } : {}),
|
|
207
|
+
};
|
|
180
208
|
},
|
|
181
209
|
warn: (message) => io.stderr.write(message),
|
|
182
210
|
});
|
|
@@ -253,10 +281,37 @@ function commandTool(tools, command) {
|
|
|
253
281
|
const byName = (name) => (name === undefined ? undefined : tools.list.find((t) => t.name === name));
|
|
254
282
|
return byName(command.tool) ?? byName("execute") ?? byName(command.readOnly ? "query" : "mutate") ?? tools.helpTool;
|
|
255
283
|
}
|
|
256
|
-
/**
|
|
257
|
-
function
|
|
258
|
-
|
|
259
|
-
const
|
|
284
|
+
/** server/discover _meta["dev.mext/tools"]. 없음 · JSON-RPC 오류 (discover 없는 서버 등) = undefined (dispatcher) */
|
|
285
|
+
async function discoverExposure(s) {
|
|
286
|
+
try {
|
|
287
|
+
const result = await s.call((o) => s.client.request("server/discover", {}, o));
|
|
288
|
+
const value = isRecord(result._meta) ? result._meta[TOOLS_META_KEY] : undefined;
|
|
289
|
+
return typeof value === "string" ? value : undefined;
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
if (error instanceof RemoteRpcError)
|
|
293
|
+
return undefined;
|
|
294
|
+
throw error;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* 서버 help. dispatcher = help 호출 (tools/call), command 노출 = tools/list 로 만든 manifest 의 help (help 도구 없음).
|
|
299
|
+
* UNKNOWN_COMMAND = 캐시할 결과, 그 외 오류 = throw
|
|
300
|
+
*/
|
|
301
|
+
function serverHelpFetcher(s, ctx, embeddedExposure) {
|
|
302
|
+
return async (target, listing) => {
|
|
303
|
+
const { tools, exposure } = await listing();
|
|
304
|
+
if ((embeddedExposure ?? exposure) === "command") {
|
|
305
|
+
try {
|
|
306
|
+
return { value: { help: manifestHelp(manifestFromTools(tools), target) }, hash: undefined };
|
|
307
|
+
}
|
|
308
|
+
catch (error) {
|
|
309
|
+
if (error instanceof MextError && error.code === "UNKNOWN_COMMAND")
|
|
310
|
+
return { value: { error: error.toJSON() }, hash: undefined };
|
|
311
|
+
throw error;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
const { helpTool } = dispatcherOf(s.url, tools);
|
|
260
315
|
const args = target === "" ? { command: "help" } : { command: "help", args: { target } };
|
|
261
316
|
const result = await s.call((o) => s.client.callTool(helpTool, args, o));
|
|
262
317
|
const hash = metaHash(result);
|
|
@@ -464,10 +519,14 @@ function errorBody(error) {
|
|
|
464
519
|
if (error instanceof RemoteTransportError ||
|
|
465
520
|
error instanceof RemoteRpcError ||
|
|
466
521
|
error instanceof RemoteInputRequiredError ||
|
|
522
|
+
error instanceof RemoteTaskError ||
|
|
467
523
|
error instanceof OAuthFlowError) {
|
|
468
524
|
const body = { code: "REMOTE_ERROR", message: error.message };
|
|
469
525
|
if (error instanceof RemoteRpcError)
|
|
470
526
|
body.rpc = { code: error.code, status: error.status, data: error.data };
|
|
527
|
+
if (error instanceof RemoteTaskError) {
|
|
528
|
+
body.task = { taskId: error.taskId, status: error.status, ...(error.error ? { error: error.error } : {}) };
|
|
529
|
+
}
|
|
471
530
|
return body;
|
|
472
531
|
}
|
|
473
532
|
return errorJson(error);
|
|
@@ -483,12 +542,13 @@ function usageError(message) {
|
|
|
483
542
|
}
|
|
484
543
|
/* MRTR: InputRequiredResult → 프롬프트 → inputResponses */
|
|
485
544
|
/**
|
|
486
|
-
* elicitation/create
|
|
545
|
+
* elicitation/create 처리 (clientCapabilities = elicitation.form · url).
|
|
546
|
+
* mode url = 로컬 ctx.ask url 과 같음 (askUrl: --yes 미적용, TTY 없음 · --json = INPUT_UNAVAILABLE). accept · decline.
|
|
487
547
|
* requestedSchema 가 boolean 속성 하나 = 확인: --yes → 승인, TTY → [y/N], 그 외 INPUT_UNAVAILABLE.
|
|
488
548
|
* 그 외 form = TTY 에서 필드별 입력 (스키마 모양으로 변환), TTY 없음 = INPUT_UNAVAILABLE.
|
|
489
549
|
* 응답 = { action: "accept", content }. 이번 라운드 요청에 대한 응답만 보낸다
|
|
490
550
|
*/
|
|
491
|
-
function inputHandler(io, lines, yes, command, signal) {
|
|
551
|
+
function inputHandler(io, lines, yes, json, command, signal) {
|
|
492
552
|
const unavailable = (message, hint) => new MextError("INPUT_UNAVAILABLE", `${command} asked "${message}", but stdin is not a terminal.${hint}`, { command });
|
|
493
553
|
const ask = async (prompt) => {
|
|
494
554
|
const answer = await lines.question(prompt, signal);
|
|
@@ -505,10 +565,11 @@ function inputHandler(io, lines, yes, command, signal) {
|
|
|
505
565
|
throw new RemoteTransportError(`${command}: unsupported input request ${request.method}.`);
|
|
506
566
|
}
|
|
507
567
|
if (params.mode === "url") {
|
|
508
|
-
if (
|
|
509
|
-
throw
|
|
510
|
-
|
|
511
|
-
|
|
568
|
+
if (typeof params.url !== "string" || !/^https?:\/\//i.test(params.url)) {
|
|
569
|
+
throw new RemoteTransportError(`${command}: url input request without an http(s) url.`);
|
|
570
|
+
}
|
|
571
|
+
const accepted = await askUrl(io, lines, { command, message, url: params.url }, { json, signal });
|
|
572
|
+
out[key] = { action: accepted ? "accept" : "decline" };
|
|
512
573
|
continue;
|
|
513
574
|
}
|
|
514
575
|
const schema = isRecord(params.requestedSchema) ? params.requestedSchema : { type: "object", properties: {} };
|