@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/cli/logout.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/cli/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,SAAS,EAA0B,MAAM,0BAA0B,CAAA;AACjH,OAAO,EAAE,iBAAiB,EAAqB,MAAM,oBAAoB,CAAA;AACzE,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAA;AAEjC,OAAO,EAAE,gBAAgB,EAA2B,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/cli/logout.ts"],"names":[],"mappings":"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","sourcesContent":["import { canonicalServerUrl, credentialStore, envPrefix, type StoredCredentials } from \"../remote/credentials.ts\"\nimport { revokeCredentials, type RevokeResult } from \"../remote/oauth.ts\"\nimport { table } from \"./help.ts\"\nimport type { CliIo } from \"./io.ts\"\nimport { resolveServerUrl, usageError, type AuthCommandOptions } from \"./login.ts\"\nimport { emitError, EXIT, formatJson } from \"./output.ts\"\n\n/**\n * <bin> logout — 저장된 토큰 폐기 · 삭제. 인가 서버 메타데이터에 revocation_endpoint (RFC 7009) 가 있으면\n * refresh token → access token 순서로 폐기 요청 (best effort: 실패는 경고, 삭제는 계속), 그다음 키체인 · 파일에서 삭제.\n */\nexport function logoutCommand(options: AuthCommandOptions): (argv: readonly string[], io: CliIo) => Promise<number> {\n return (argv, io) => runLogoutWith(options, argv, io)\n}\n\n/** mext logout */\nexport const runLogout = logoutCommand({ bin: \"mext\" })\n\nasync function runLogoutWith(options: AuthCommandOptions, argv: readonly string[], io: CliIo): Promise<number> {\n let flag: string | undefined\n let json = false\n for (let i = 0; i < argv.length; i++) {\n const tok = argv[i]!\n const eq = tok.indexOf(\"=\")\n const name = tok.startsWith(\"--\") && eq > 0 ? tok.slice(0, eq) : tok\n if (name === \"-h\" || name === \"--help\") {\n io.stdout.write(logoutHelp(options))\n return EXIT.ok\n } else if (name === \"--json\") json = true\n else if (name === \"--url\") flag = eq > 0 ? tok.slice(eq + 1) : argv[++i]\n else return usage(io, options, `unknown argument ${tok}`)\n }\n const url = resolveServerUrl(options, flag, io)\n if (typeof url !== \"string\") return usage(io, options, url.error)\n const server = canonicalServerUrl(url)\n const store = credentialStore({ env: io.env, bin: options.bin })\n\n let stored: StoredCredentials | undefined\n let readError: string | undefined\n try {\n stored = await store.get(url)\n } catch (error) {\n readError = error instanceof Error ? error.message : String(error)\n }\n const revocation: RevokeResult = stored\n ? await revokeCredentials(stored, options.fetch ? { fetch: options.fetch } : {})\n : { supported: false, revoked: [], errors: [] }\n if (readError !== undefined) revocation.errors.push(`Cannot read stored credentials: ${readError}`)\n try {\n await store.delete(url)\n } catch (error) {\n const message = `Cannot remove stored credentials from ${store.location}: ${error instanceof Error ? error.message : String(error)}`\n return emitError(io, { body: { code: \"LOGOUT_FAILED\", message }, text: `error: ${message}\\n`, exitCode: EXIT.error, json }, options.formatter)\n }\n\n if (json) {\n const out: Record<string, unknown> = {\n url: server,\n loggedIn: stored !== undefined,\n storage: store.location,\n revoked: revocation.revoked,\n }\n if (revocation.errors.length > 0) out.errors = revocation.errors\n io.stdout.write(formatJson(out))\n return EXIT.ok\n }\n for (const e of revocation.errors) io.stderr.write(`warning: ${e}\\n`)\n if (stored === undefined) {\n io.stderr.write(`Not logged in to ${server}.\\n`)\n return EXIT.ok\n }\n if (revocation.revoked.length > 0) io.stderr.write(`Revoked ${revocation.revoked.join(\" and \").replace(/_/g, \" \")} at ${stored.issuer}.\\n`)\n io.stderr.write(`Logged out of ${server}. Removed credentials from ${store.location}.\\n`)\n return EXIT.ok\n}\n\nfunction usage(io: CliIo, options: AuthCommandOptions, message: string): number {\n return usageError(io, options.formatter, message, logoutHelp(options))\n}\n\nfunction logoutHelp(options: AuthCommandOptions): string {\n const { bin } = options\n const rows = [\n [\"--url <url>\", options.url ? `MCP endpoint (default: ${options.url})` : `MCP endpoint (default: ${envPrefix(bin)}_URL)`],\n [\"--json\", \"Print the result as JSON\"],\n [\"-h, --help\", \"Show help\"],\n ]\n return [\n \"Log out of a remote server: revoke the stored tokens (if the authorization server supports RFC 7009)\",\n \"and remove them from the OS keychain and credentials file.\",\n \"\",\n \"Usage:\",\n ` ${bin} logout${options.url ? \"\" : \" --url <url>\"} [flags]`,\n \"\",\n \"Flags:\",\n ...table(rows).map((l) => ` ${l}`),\n \"\",\n ].join(\"\\n\")\n}\n"]}
|
package/dist/cli/output.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export declare function formatJson(value: unknown): string;
|
|
|
34
34
|
export declare function formatProgress(update: ProgressUpdate): string;
|
|
35
35
|
/** cli.errors formatter 입력: 오류 하나 + mext 기본 출력 */
|
|
36
36
|
export interface CliErrorInfo {
|
|
37
|
-
/** MextErrorCode · EXECUTION_ERROR · INTERRUPTED · REMOTE_ERROR ·
|
|
37
|
+
/** MextErrorCode · EXECUTION_ERROR · INTERRUPTED · REMOTE_ERROR · LOGIN_FAILED · LOGOUT_FAILED · 핸들러 정의 오류 code 등 (= body.code) */
|
|
38
38
|
code: string;
|
|
39
39
|
message: string;
|
|
40
40
|
/** 오류 상세 (MextError.details · 서버 오류 본문의 code · message 외 필드) */
|
package/dist/cli/output.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ProgressUpdate } from \"../command.ts\"\nimport { CommandError, isMextError, MextBuildError, MextError } from \"../errors.ts\"\nimport { toKebab } from \"./args.ts\"\nimport { cliPath, table } from \"./help.ts\"\n\n/** exit code (spec §5) */\nexport const EXIT = {\n ok: 0,\n error: 1,\n usage: 2,\n auth: 77,\n interrupted: 130,\n} as const\n\n/** 실행 중 SIGINT (ctx.signal abort) 를 나타내는 CLI 내부 오류 */\nexport class CliInterrupted extends Error {\n constructor() {\n super(\"Interrupted.\")\n this.name = \"CliInterrupted\"\n }\n}\n\n/**\n * 오류 → exit code.\n * INVALID_ARGUMENT · UNKNOWN_COMMAND · INPUT_UNAVAILABLE = 2 · UNAUTHENTICATED · PERMISSION_DENIED = 77 · SIGINT = 130 · 그 외 = 1\n */\nexport function exitCodeOf(error: unknown): number {\n if (error instanceof CliInterrupted) return EXIT.interrupted\n if (error instanceof MextError) {\n switch (error.code) {\n case \"INVALID_ARGUMENT\":\n case \"UNKNOWN_COMMAND\":\n case \"INPUT_UNAVAILABLE\":\n return EXIT.usage\n case \"UNAUTHENTICATED\":\n case \"PERMISSION_DENIED\":\n return EXIT.auth\n }\n }\n return EXIT.error\n}\n\n/**\n * --json 오류 본문. MextError · CommandError = toJSON(), 빌드 오류 = BUILD_ERROR + issues,\n * SIGINT = INTERRUPTED, 핸들러 예외 = EXECUTION_ERROR\n */\nexport function errorJson(error: unknown): Record<string, unknown> {\n if (error instanceof MextError || error instanceof CommandError) return error.toJSON()\n if (error instanceof MextBuildError) return { code: \"BUILD_ERROR\", message: error.message, issues: error.issues }\n if (error instanceof CliInterrupted) return { code: \"INTERRUPTED\", message: error.message }\n return { code: \"EXECUTION_ERROR\", message: error instanceof Error ? error.message : String(error) }\n}\n\n/** 사람용 오류 텍스트 (끝 줄바꿈 포함) */\nexport function formatError(error: unknown, prog: string): string {\n const lines: string[] = []\n if (isMextError(error, \"INVALID_ARGUMENT\")) {\n const d = error.details\n lines.push(d.command === \"\" ? \"error: invalid arguments\" : `error: invalid arguments for ${cliPath(d.command)}`)\n const rows = d.issues.map((i) => {\n if (i.path === \"\") return [i.message]\n return [flagOf(i.path), d.missing_fields.includes(i.path) ? \"required\" : i.message]\n })\n lines.push(...table(rows.filter((r) => r.length === 2)).map((l) => ` ${l}`))\n lines.push(...rows.filter((r) => r.length === 1).map((r) => ` ${r[0]}`))\n if (d.command !== \"\") lines.push(`Run \"${prog} ${cliPath(d.command)} --help\" for usage.`)\n } else if (isMextError(error, \"UNKNOWN_COMMAND\")) {\n const d = error.details\n if (d.command === \"\") lines.push(\"error: no command given\")\n else if (error.message.startsWith(\"Unknown command\")) lines.push(`error: unknown command \"${cliPath(d.command)}\"`)\n else lines.push(`error: ${error.message}`)\n if (d.suggested.length > 0) lines.push(`Did you mean: ${d.suggested.map((s) => `${prog} ${cliPath(s)}`).join(\", \")}?`)\n lines.push(`Run \"${usageCommand(prog, d.usage)}\" for available commands.`)\n } else if (isMextError(error, \"PERMISSION_DENIED\")) {\n const d = error.details\n lines.push(`error: ${error.message}`)\n lines.push(` required scopes: ${d.required_scopes.join(\", \") || \"(none)\"}`)\n lines.push(` held scopes: ${d.held_scopes.join(\", \") || \"(none)\"}`)\n } else if (isMextError(error, \"UNAUTHENTICATED\")) {\n lines.push(`error: ${error.message}`)\n if (error.details.login !== undefined) lines.push(`Run \"${error.details.login}\" to log in.`)\n } else if (isMextError(error, \"INPUT_UNAVAILABLE\")) {\n lines.push(`error: ${error.message}`)\n } else if (error instanceof Error) {\n lines.push(`error: ${error.message}`)\n } else {\n lines.push(`error: ${String(error)}`)\n }\n return `${lines.join(\"\\n\")}\\n`\n}\n\n/** \"help\" → \"mext run help\" · \"help users\" → \"mext run users --help\" */\nfunction usageCommand(prog: string, usage: string): string {\n const target = usage.replace(/^help\\s*/, \"\")\n return target === \"\" ? `${prog} help` : `${prog} ${cliPath(target)} --help`\n}\n\n/** 입력 경로 → 플래그 표기 (\"filter.minAge\" → \"--filter.min-age\") */\nfunction flagOf(path: string): string {\n return `--${path\n .split(\".\")\n .map((s) => (/^\\d+$/.test(s) ? s : toKebab(s)))\n .join(\".\")}`\n}\n\n/**\n * 사람용 결과 텍스트 (끝 줄바꿈 포함, undefined = 빈 문자열).\n * 문자열 = 그대로 · 원시 값 = String · 객체 배열 = 표 · 원시 배열 = 줄마다 · 객체 = 키 값 정렬. 중첩 값은 JSON 한 줄\n */\nexport function formatResult(value: unknown): string {\n if (value === undefined) return \"\"\n if (value === null) return \"null\\n\"\n if (typeof value === \"string\") return value.endsWith(\"\\n\") ? value : `${value}\\n`\n if (Array.isArray(value)) {\n if (value.length === 0) return \"(empty)\\n\"\n if (value.every(isRecord)) {\n const columns: string[] = []\n for (const row of value) for (const k of Object.keys(row)) if (!columns.includes(k)) columns.push(k)\n return lines(table([columns, ...value.map((row) => columns.map((c) => cell(row[c])))]))\n }\n return lines(value.map(cell))\n }\n if (isRecord(value)) {\n const entries = Object.entries(value).filter(([, v]) => v !== undefined)\n if (entries.length === 0) return \"(empty)\\n\"\n return lines(table(entries.map(([k, v]) => [k, cell(v)])))\n }\n return `${cell(value)}\\n`\n}\n\n/** --json 결과 */\nexport function formatJson(value: unknown): string {\n return `${JSON.stringify(value === undefined ? null : value, null, 2)}\\n`\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value) && !(value instanceof Date)\n}\n\nfunction cell(value: unknown): string {\n if (value === undefined || value === null) return \"\"\n if (typeof value === \"string\") return value\n if (typeof value === \"number\" || typeof value === \"boolean\" || typeof value === \"bigint\") return String(value)\n if (value instanceof Date) return value.toISOString()\n return JSON.stringify(value) ?? \"\"\n}\n\nfunction lines(list: string[]): string {\n return `${list.join(\"\\n\")}\\n`\n}\n\n/** ctx.progress → stderr 한 줄 */\nexport function formatProgress(update: ProgressUpdate): string {\n const head = update.total !== undefined ? `[${update.progress}/${update.total}]` : `[${update.progress}]`\n return `${update.message ? `${head} ${update.message}` : head}\\n`\n}\n\n/* ---------------------------------------------------------------- 오류 출력 커스텀 (cli.errors, spec §5) */\n\n/** cli.errors formatter 입력: 오류 하나 + mext 기본 출력 */\nexport interface CliErrorInfo {\n /** MextErrorCode · EXECUTION_ERROR · INTERRUPTED · REMOTE_ERROR · 서버 핸들러 오류 code 등 (= body.code) */\n code: string\n message: string\n /** 오류 상세 (MextError.details · 서버 오류 본문의 code · message 외 필드) */\n details: Record<string, unknown>\n /** INVALID_ARGUMENT issues 의 \"경로: 메시지\" (경로 없으면 메시지). 그 외 [] */\n reasons: string[]\n /** mext 기본 --json 오류 본문 */\n body: Record<string, unknown>\n /** mext 기본 사람용 텍스트 (끝 줄바꿈 포함) */\n text: string\n /** mext 기본 exit code (0 · 1 · 2 · 77 · 130) */\n exitCode: number\n /** --json 지정 여부 */\n json: boolean\n}\n\n/** formatter 출력. 지정한 필드만 기본값 대체 (stderr 기본 = json ? body JSON : text, stdout 기본 = 없음) */\nexport interface CliErrorOutput {\n exitCode?: number\n stderr?: string\n stdout?: string\n}\n\n/** cli.errors 모듈의 default export. undefined 반환 = mext 기본 */\nexport type CliErrorFormatter = (error: CliErrorInfo) => CliErrorOutput | undefined | void\n\nexport interface CliErrorWriter {\n stdout: { write(chunk: string): unknown }\n stderr: { write(chunk: string): unknown }\n}\n\n/**\n * 오류 출력 (기본 = json ? body : text) + formatter 적용 → exit code.\n * formatter 예외 · 잘못된 exitCode = 기본값 + stderr 경고 1줄\n */\nexport function emitError(\n io: CliErrorWriter,\n error: { body: Record<string, unknown>; text: string; exitCode: number; json: boolean },\n formatter: CliErrorFormatter | undefined,\n): number {\n const fallback = error.json ? formatJson(error.body) : error.text\n if (!formatter) {\n io.stderr.write(fallback)\n return error.exitCode\n }\n const { code, message, ...details } = error.body\n const info: CliErrorInfo = {\n code: typeof code === \"string\" ? code : \"EXECUTION_ERROR\",\n message: typeof message === \"string\" ? message : String(message ?? \"\"),\n details,\n reasons: reasonsOf(details),\n body: error.body,\n text: error.text,\n exitCode: error.exitCode,\n json: error.json,\n }\n let out: CliErrorOutput | undefined | void\n try {\n out = formatter(info)\n } catch (e) {\n io.stderr.write(fallback)\n io.stderr.write(`warning: cli.errors formatter failed: ${e instanceof Error ? e.message : String(e)}\\n`)\n return error.exitCode\n }\n if (out === undefined || out === null) {\n io.stderr.write(fallback)\n return error.exitCode\n }\n if (out.stdout !== undefined) io.stdout.write(out.stdout)\n io.stderr.write(out.stderr ?? fallback)\n if (out.exitCode === undefined) return error.exitCode\n if (!Number.isInteger(out.exitCode) || out.exitCode < 0 || out.exitCode > 255) {\n io.stderr.write(`warning: cli.errors formatter returned an invalid exitCode (${String(out.exitCode)})\\n`)\n return error.exitCode\n }\n return out.exitCode\n}\n\n/** INVALID_ARGUMENT details.issues → \"경로: 메시지\" */\nfunction reasonsOf(details: Record<string, unknown>): string[] {\n const issues = details.issues\n if (!Array.isArray(issues)) return []\n return issues.flatMap((i) => {\n if (!isRecord(i) || typeof i.message !== \"string\") return []\n return [typeof i.path === \"string\" && i.path !== \"\" ? `${i.path}: ${i.message}` : i.message]\n })\n}\n"]}
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ProgressUpdate } from \"../command.ts\"\nimport { CommandError, isMextError, MextBuildError, MextError } from \"../errors.ts\"\nimport { toKebab } from \"./args.ts\"\nimport { cliPath, table } from \"./help.ts\"\n\n/** exit code (spec §5) */\nexport const EXIT = {\n ok: 0,\n error: 1,\n usage: 2,\n auth: 77,\n interrupted: 130,\n} as const\n\n/** 실행 중 SIGINT (ctx.signal abort) 를 나타내는 CLI 내부 오류 */\nexport class CliInterrupted extends Error {\n constructor() {\n super(\"Interrupted.\")\n this.name = \"CliInterrupted\"\n }\n}\n\n/**\n * 오류 → exit code.\n * INVALID_ARGUMENT · UNKNOWN_COMMAND · INPUT_UNAVAILABLE = 2 · UNAUTHENTICATED · PERMISSION_DENIED = 77 · SIGINT = 130 · 그 외 = 1\n */\nexport function exitCodeOf(error: unknown): number {\n if (error instanceof CliInterrupted) return EXIT.interrupted\n if (error instanceof MextError) {\n switch (error.code) {\n case \"INVALID_ARGUMENT\":\n case \"UNKNOWN_COMMAND\":\n case \"INPUT_UNAVAILABLE\":\n return EXIT.usage\n case \"UNAUTHENTICATED\":\n case \"PERMISSION_DENIED\":\n return EXIT.auth\n }\n }\n return EXIT.error\n}\n\n/**\n * --json 오류 본문. MextError · CommandError = toJSON(), 빌드 오류 = BUILD_ERROR + issues,\n * SIGINT = INTERRUPTED, 핸들러 예외 = EXECUTION_ERROR\n */\nexport function errorJson(error: unknown): Record<string, unknown> {\n if (error instanceof MextError || error instanceof CommandError) return error.toJSON()\n if (error instanceof MextBuildError) return { code: \"BUILD_ERROR\", message: error.message, issues: error.issues }\n if (error instanceof CliInterrupted) return { code: \"INTERRUPTED\", message: error.message }\n return { code: \"EXECUTION_ERROR\", message: error instanceof Error ? error.message : String(error) }\n}\n\n/** 사람용 오류 텍스트 (끝 줄바꿈 포함) */\nexport function formatError(error: unknown, prog: string): string {\n const lines: string[] = []\n if (isMextError(error, \"INVALID_ARGUMENT\")) {\n const d = error.details\n lines.push(d.command === \"\" ? \"error: invalid arguments\" : `error: invalid arguments for ${cliPath(d.command)}`)\n const rows = d.issues.map((i) => {\n if (i.path === \"\") return [i.message]\n return [flagOf(i.path), d.missing_fields.includes(i.path) ? \"required\" : i.message]\n })\n lines.push(...table(rows.filter((r) => r.length === 2)).map((l) => ` ${l}`))\n lines.push(...rows.filter((r) => r.length === 1).map((r) => ` ${r[0]}`))\n if (d.command !== \"\") lines.push(`Run \"${prog} ${cliPath(d.command)} --help\" for usage.`)\n } else if (isMextError(error, \"UNKNOWN_COMMAND\")) {\n const d = error.details\n if (d.command === \"\") lines.push(\"error: no command given\")\n else if (error.message.startsWith(\"Unknown command\")) lines.push(`error: unknown command \"${cliPath(d.command)}\"`)\n else lines.push(`error: ${error.message}`)\n if (d.suggested.length > 0) lines.push(`Did you mean: ${d.suggested.map((s) => `${prog} ${cliPath(s)}`).join(\", \")}?`)\n lines.push(`Run \"${usageCommand(prog, d.usage)}\" for available commands.`)\n } else if (isMextError(error, \"PERMISSION_DENIED\")) {\n const d = error.details\n lines.push(`error: ${error.message}`)\n lines.push(` required scopes: ${d.required_scopes.join(\", \") || \"(none)\"}`)\n lines.push(` held scopes: ${d.held_scopes.join(\", \") || \"(none)\"}`)\n } else if (isMextError(error, \"UNAUTHENTICATED\")) {\n lines.push(`error: ${error.message}`)\n if (error.details.login !== undefined) lines.push(`Run \"${error.details.login}\" to log in.`)\n } else if (isMextError(error, \"INPUT_UNAVAILABLE\")) {\n lines.push(`error: ${error.message}`)\n } else if (error instanceof Error) {\n lines.push(`error: ${error.message}`)\n } else {\n lines.push(`error: ${String(error)}`)\n }\n return `${lines.join(\"\\n\")}\\n`\n}\n\n/** \"help\" → \"mext run help\" · \"help users\" → \"mext run users --help\" */\nfunction usageCommand(prog: string, usage: string): string {\n const target = usage.replace(/^help\\s*/, \"\")\n return target === \"\" ? `${prog} help` : `${prog} ${cliPath(target)} --help`\n}\n\n/** 입력 경로 → 플래그 표기 (\"filter.minAge\" → \"--filter.min-age\") */\nfunction flagOf(path: string): string {\n return `--${path\n .split(\".\")\n .map((s) => (/^\\d+$/.test(s) ? s : toKebab(s)))\n .join(\".\")}`\n}\n\n/**\n * 사람용 결과 텍스트 (끝 줄바꿈 포함, undefined = 빈 문자열).\n * 문자열 = 그대로 · 원시 값 = String · 객체 배열 = 표 · 원시 배열 = 줄마다 · 객체 = 키 값 정렬. 중첩 값은 JSON 한 줄\n */\nexport function formatResult(value: unknown): string {\n if (value === undefined) return \"\"\n if (value === null) return \"null\\n\"\n if (typeof value === \"string\") return value.endsWith(\"\\n\") ? value : `${value}\\n`\n if (Array.isArray(value)) {\n if (value.length === 0) return \"(empty)\\n\"\n if (value.every(isRecord)) {\n const columns: string[] = []\n for (const row of value) for (const k of Object.keys(row)) if (!columns.includes(k)) columns.push(k)\n return lines(table([columns, ...value.map((row) => columns.map((c) => cell(row[c])))]))\n }\n return lines(value.map(cell))\n }\n if (isRecord(value)) {\n const entries = Object.entries(value).filter(([, v]) => v !== undefined)\n if (entries.length === 0) return \"(empty)\\n\"\n return lines(table(entries.map(([k, v]) => [k, cell(v)])))\n }\n return `${cell(value)}\\n`\n}\n\n/** --json 결과 */\nexport function formatJson(value: unknown): string {\n return `${JSON.stringify(value === undefined ? null : value, null, 2)}\\n`\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value) && !(value instanceof Date)\n}\n\nfunction cell(value: unknown): string {\n if (value === undefined || value === null) return \"\"\n if (typeof value === \"string\") return value\n if (typeof value === \"number\" || typeof value === \"boolean\" || typeof value === \"bigint\") return String(value)\n if (value instanceof Date) return value.toISOString()\n return JSON.stringify(value) ?? \"\"\n}\n\nfunction lines(list: string[]): string {\n return `${list.join(\"\\n\")}\\n`\n}\n\n/** ctx.progress → stderr 한 줄 */\nexport function formatProgress(update: ProgressUpdate): string {\n const head = update.total !== undefined ? `[${update.progress}/${update.total}]` : `[${update.progress}]`\n return `${update.message ? `${head} ${update.message}` : head}\\n`\n}\n\n/* ---------------------------------------------------------------- 오류 출력 커스텀 (cli.errors, spec §5) */\n\n/** cli.errors formatter 입력: 오류 하나 + mext 기본 출력 */\nexport interface CliErrorInfo {\n /** MextErrorCode · EXECUTION_ERROR · INTERRUPTED · REMOTE_ERROR · LOGIN_FAILED · LOGOUT_FAILED · 핸들러 정의 오류 code 등 (= body.code) */\n code: string\n message: string\n /** 오류 상세 (MextError.details · 서버 오류 본문의 code · message 외 필드) */\n details: Record<string, unknown>\n /** INVALID_ARGUMENT issues 의 \"경로: 메시지\" (경로 없으면 메시지). 그 외 [] */\n reasons: string[]\n /** mext 기본 --json 오류 본문 */\n body: Record<string, unknown>\n /** mext 기본 사람용 텍스트 (끝 줄바꿈 포함) */\n text: string\n /** mext 기본 exit code (0 · 1 · 2 · 77 · 130) */\n exitCode: number\n /** --json 지정 여부 */\n json: boolean\n}\n\n/** formatter 출력. 지정한 필드만 기본값 대체 (stderr 기본 = json ? body JSON : text, stdout 기본 = 없음) */\nexport interface CliErrorOutput {\n exitCode?: number\n stderr?: string\n stdout?: string\n}\n\n/** cli.errors 모듈의 default export. undefined 반환 = mext 기본 */\nexport type CliErrorFormatter = (error: CliErrorInfo) => CliErrorOutput | undefined | void\n\nexport interface CliErrorWriter {\n stdout: { write(chunk: string): unknown }\n stderr: { write(chunk: string): unknown }\n}\n\n/**\n * 오류 출력 (기본 = json ? body : text) + formatter 적용 → exit code.\n * formatter 예외 · 잘못된 exitCode = 기본값 + stderr 경고 1줄\n */\nexport function emitError(\n io: CliErrorWriter,\n error: { body: Record<string, unknown>; text: string; exitCode: number; json: boolean },\n formatter: CliErrorFormatter | undefined,\n): number {\n const fallback = error.json ? formatJson(error.body) : error.text\n if (!formatter) {\n io.stderr.write(fallback)\n return error.exitCode\n }\n const { code, message, ...details } = error.body\n const info: CliErrorInfo = {\n code: typeof code === \"string\" ? code : \"EXECUTION_ERROR\",\n message: typeof message === \"string\" ? message : String(message ?? \"\"),\n details,\n reasons: reasonsOf(details),\n body: error.body,\n text: error.text,\n exitCode: error.exitCode,\n json: error.json,\n }\n let out: CliErrorOutput | undefined | void\n try {\n out = formatter(info)\n } catch (e) {\n io.stderr.write(fallback)\n io.stderr.write(`warning: cli.errors formatter failed: ${e instanceof Error ? e.message : String(e)}\\n`)\n return error.exitCode\n }\n if (out === undefined || out === null) {\n io.stderr.write(fallback)\n return error.exitCode\n }\n if (out.stdout !== undefined) io.stdout.write(out.stdout)\n io.stderr.write(out.stderr ?? fallback)\n if (out.exitCode === undefined) return error.exitCode\n if (!Number.isInteger(out.exitCode) || out.exitCode < 0 || out.exitCode > 255) {\n io.stderr.write(`warning: cli.errors formatter returned an invalid exitCode (${String(out.exitCode)})\\n`)\n return error.exitCode\n }\n return out.exitCode\n}\n\n/** INVALID_ARGUMENT details.issues → \"경로: 메시지\" */\nfunction reasonsOf(details: Record<string, unknown>): string[] {\n const issues = details.issues\n if (!Array.isArray(issues)) return []\n return issues.flatMap((i) => {\n if (!isRecord(i) || typeof i.message !== \"string\") return []\n return [typeof i.path === \"string\" && i.path !== \"\" ? `${i.path}: ${i.message}` : i.message]\n })\n}\n"]}
|
package/dist/cli/run.js
CHANGED
|
@@ -7,6 +7,7 @@ import { help } from "../mcp/help.js";
|
|
|
7
7
|
import { loadCommand, resolveCommand } from "../registry.js";
|
|
8
8
|
import { loadRegistry } from "../scan.js";
|
|
9
9
|
import { analyzeInput, assertCliConvertible, coerceValue, defineCliSpec, parseArgs } from "./args.js";
|
|
10
|
+
import { askUrl } from "./ask-url.js";
|
|
10
11
|
import { cliPath, renderHelp } from "./help.js";
|
|
11
12
|
import { createLineReader, readAll } from "./io.js";
|
|
12
13
|
import { CliInterrupted, emitError, EXIT, errorJson, exitCodeOf, formatError, formatJson, formatProgress, formatResult, } from "./output.js";
|
|
@@ -112,7 +113,7 @@ export async function runLocalCommand(argv, io, source) {
|
|
|
112
113
|
principal,
|
|
113
114
|
signal: controller.signal,
|
|
114
115
|
progress: (update) => io.stderr.write(formatProgress(update)),
|
|
115
|
-
ask: askHandler(io, lines, yes, controller.signal),
|
|
116
|
+
ask: askHandler(io, lines, yes, json, controller.signal),
|
|
116
117
|
app,
|
|
117
118
|
instrumentation,
|
|
118
119
|
transport: "local",
|
|
@@ -209,10 +210,13 @@ function usageError(message) {
|
|
|
209
210
|
}
|
|
210
211
|
/**
|
|
211
212
|
* ctx.ask. --yes = confirm 승인. TTY 없음 = 즉시 INPUT_UNAVAILABLE.
|
|
212
|
-
* TTY = stderr 프롬프트 + stdin 한 줄 (confirm = y/yes, input = 필드별 입력을 스키마 모양으로 변환)
|
|
213
|
+
* TTY = stderr 프롬프트 + stdin 한 줄 (confirm = y/yes, input = 필드별 입력을 스키마 모양으로 변환).
|
|
214
|
+
* url = askUrl (--yes 미적용, --json = INPUT_UNAVAILABLE)
|
|
213
215
|
*/
|
|
214
|
-
function askHandler(io, lines, yes, signal) {
|
|
216
|
+
function askHandler(io, lines, yes, json, signal) {
|
|
215
217
|
return async (request) => {
|
|
218
|
+
if (request.kind === "url")
|
|
219
|
+
return askUrl(io, lines, request, { json, signal });
|
|
216
220
|
if (request.kind === "confirm" && yes)
|
|
217
221
|
return true;
|
|
218
222
|
if (!io.isTTY) {
|
package/dist/cli/run.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"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","sourcesContent":["import { createApp, loadCliErrorFormatter, loadConfig, resolveCommandsDir, resolveLocalPrincipal, type MextConfig } from \"../config.ts\"\nimport { MextError } from \"../errors.ts\"\nimport { isSegment } from \"../ids.ts\"\nimport { loadProjectInstrumentation, type Instrumentation } from \"../instrumentation.ts\"\nimport { authorize, findCommand, invoke, type AskHandler } from \"../invoke.ts\"\nimport type { ToolExposure } from \"../mcp/dispatch.ts\"\nimport { help } from \"../mcp/help.ts\"\nimport { loadCommand, resolveCommand, type RegisteredCommand, type Registry } from \"../registry.ts\"\nimport { loadRegistry } from \"../scan.ts\"\nimport { analyzeInput, assertCliConvertible, coerceValue, defineCliSpec, parseArgs } from \"./args.ts\"\nimport { cliPath, renderHelp } from \"./help.ts\"\nimport { createLineReader, readAll, type CliIo, type LineReader } from \"./io.ts\"\nimport {\n CliInterrupted,\n emitError,\n EXIT,\n errorJson,\n exitCodeOf,\n formatError,\n formatJson,\n formatProgress,\n formatResult,\n type CliErrorFormatter,\n} from \"./output.ts\"\nimport { remoteTarget, runRemoteCommand } from \"./remote.ts\"\n\nexport const RUN_PROG = \"mext run\"\n\n/** 로컬 실행에 필요한 것: 계측 · 설정 · Registry (+ cli.errors formatter) */\nexport interface LocalRunLoaded {\n instrumentation: Instrumentation\n config: MextConfig\n registry: Registry\n}\n\n/**\n * 로컬 실행 코어의 입력. mext run = 소스 (commands/ · mext.config.ts), 로컬 bin = .mext/ 빌드 (start.ts runLocalBin)\n */\nexport interface LocalRunSource {\n /** help · 오류 안내의 명령 이름 (\"mext run\" · \"<bin>\") */\n prog: string\n /** 루트 help 뒤에 붙일 텍스트 (로컬 bin 내장 명령) */\n footer?: string\n /** instrumentation register → 설정 → formatter (setFormatter 로 즉시 전달, 이후 오류에 적용) → Registry */\n load(setFormatter: (formatter: CliErrorFormatter | undefined) => void): Promise<LocalRunLoaded>\n}\n\n/** mext run 의 소스: 도입 프로젝트 (cwd) 의 instrumentation.ts · mext.config.ts · cli.errors · commands/ */\nexport function projectSource(cwd: string): LocalRunSource {\n return {\n prog: RUN_PROG,\n async load(setFormatter) {\n // instrumentation.ts register() = 설정 · 명령어 모듈 import 전 (프로세스당 1회)\n const instrumentation = await loadProjectInstrumentation(cwd)\n const config = await loadConfig(cwd)\n setFormatter(await loadCliErrorFormatter(cwd, config))\n const registry = await loadRegistry(resolveCommandsDir(cwd, config))\n assertCliConvertible(registry)\n return { instrumentation, config, registry }\n },\n }\n}\n\n/**\n * mext run <ns> <cmd> [flags] — 로컬 실행 (ctx.principal.kind = local, mext.config.ts 의 localPrincipal 로 변경 가능).\n * mext run help [target] · mext run [<ns> [<cmd>]] --help · --json · --yes.\n * --url <url> (또는 MEXT_URL) = 원격 실행 (cli/remote.ts)\n */\nexport async function runCommand(argv: readonly string[], io: CliIo): Promise<number> {\n const remote = remoteTarget(argv, io.env)\n if (remote) return runRemoteCommand(remote, io)\n return runLocalCommand(argv, io, projectSource(io.cwd))\n}\n\n/**\n * 로컬 실행 코어 (mext run · 로컬 bin 공통). argv = 명령 경로 · 플래그 (help [target] 포함). 반환 = exit code\n */\nexport async function runLocalCommand(argv: readonly string[], io: CliIo, source: LocalRunSource): Promise<number> {\n const prog = source.prog\n const lead = { json: false, yes: false, help: false }\n let i = 0\n for (; i < argv.length; i++) {\n const tok = argv[i]!\n if (!tok.startsWith(\"-\") || tok === \"-\") break\n if (tok === \"--json\") lead.json = true\n else if (tok === \"--yes\") lead.yes = true\n else if (tok === \"--help\" || tok === \"-h\") lead.help = true\n else {\n return report(usageError(`unknown flag ${tok} before the command`), io, prog, argv.includes(\"--json\"))\n }\n }\n const rest = argv.slice(i)\n const beforeDashDash = rest.indexOf(\"--\") < 0 ? rest : rest.slice(0, rest.indexOf(\"--\"))\n const json = lead.json || beforeDashDash.includes(\"--json\")\n\n const lines = createLineReader(io)\n let formatter: CliErrorFormatter | undefined\n try {\n const { instrumentation, config, registry } = await source.load((f) => (formatter = f))\n\n // mext run help [target...]\n if (rest[0] === \"help\") {\n const targetTokens = rest.slice(1).filter((t) => !t.startsWith(\"-\"))\n const { id, consumed } = resolvePath(registry, targetTokens)\n if (consumed < targetTokens.length) throw unknownAt(registry, id, targetTokens.slice(consumed))\n await prepareCliSpec(resolveCommand(registry, id))\n return printHelp(registry, id, io, prog, json, config.tools, source.footer)\n }\n\n const { id, consumed } = resolvePath(registry, rest)\n const entry = id === \"\" ? undefined : resolveCommand(registry, id)\n const next = rest[consumed]\n const acceptsPositional = entry !== undefined && entry.command.positional.length > 0\n if (registry.namespaces.has(id) && next !== undefined && !next.startsWith(\"-\") && !acceptsPositional) {\n throw unknownAt(registry, id, rest.slice(consumed))\n }\n if (entry === undefined && next !== undefined && !next.startsWith(\"-\")) {\n throw unknownAt(registry, id, rest.slice(consumed))\n }\n\n await prepareCliSpec(entry)\n const help = lead.help || beforeDashDash.includes(\"--help\") || beforeDashDash.includes(\"-h\")\n if (help) return printHelp(registry, id, io, prog, json, config.tools, source.footer)\n\n if (!entry) {\n // 네임스페이스 (루트 포함) 만 지정 = 명령어 없음\n const error = new MextError(\n \"UNKNOWN_COMMAND\",\n id === \"\" ? \"No command given.\" : `\"${cliPath(id)}\" is a namespace. Specify a command.`,\n { command: id, suggested: [], usage: id === \"\" ? \"help\" : `help ${id}` },\n )\n if (json) return report(error, io, prog, true, formatter)\n const text = `${formatError(error, prog)}\\n${helpText(registry, id, prog, source.footer)}`\n return emitError(io, { body: errorJson(error), text, exitCode: EXIT.usage, json: false }, formatter)\n }\n\n const principal = await resolveLocalPrincipal(config)\n authorize(entry, principal) // 권한 → 입력 검증 순서 (invoke 와 같음)\n const parsed = await parseArgs(entry, rest.slice(consumed), { readStdin: () => readAll(io.stdin) })\n const yes = lead.yes || parsed.yes\n const app = await createApp(config)\n\n const controller = new AbortController()\n const onAbort = (): void => controller.abort(io.signal?.reason)\n if (io.signal?.aborted) onAbort()\n io.signal?.addEventListener(\"abort\", onAbort, { once: true })\n try {\n const result = await invoke(registry, entry.id, parsed.input, {\n principal,\n signal: controller.signal,\n progress: (update) => io.stderr.write(formatProgress(update)),\n ask: askHandler(io, lines, yes, controller.signal),\n app,\n instrumentation,\n transport: \"local\",\n })\n if (controller.signal.aborted) throw new CliInterrupted()\n io.stdout.write(json ? formatJson(result.value) : formatResult(result.value))\n return EXIT.ok\n } catch (error) {\n if (controller.signal.aborted) throw new CliInterrupted()\n throw error\n } finally {\n io.signal?.removeEventListener(\"abort\", onAbort)\n }\n } catch (error) {\n return report(error, io, prog, json, formatter)\n } finally {\n lines.close()\n }\n}\n\n/**\n * lazy Registry (로컬 bin 의 .mext/) 명령어 = 모듈 로드 후 Zod 입력 분석으로 CLI 필드 지정 (mext run 과 같은 파서).\n * 대상 명령어 하나만 로드. eager Registry (mext run) = 그대로\n */\nasync function prepareCliSpec(entry: RegisteredCommand | undefined): Promise<void> {\n if (!entry?.load) return\n const command = await loadCommand(entry)\n defineCliSpec(entry, analyzeInput(command.input, entry.inputSchema, entry.command.positional).spec)\n}\n\n/** 앞쪽 경로 토큰 → 가장 긴 네임스페이스 · 명령어 (별칭 포함) ID */\nexport function resolvePath(registry: Registry, tokens: readonly string[]): { id: string; consumed: number } {\n let id = \"\"\n let consumed = 0\n for (const tok of tokens) {\n if (!isSegment(tok)) break\n const candidate = id === \"\" ? tok : `${id}.${tok}`\n if (!registry.namespaces.has(candidate) && !resolveCommand(registry, candidate)) break\n id = candidate\n consumed++\n }\n return { id, consumed }\n}\n\n/** 해석되지 않은 경로 토큰 → UNKNOWN_COMMAND (suggested · usage) */\nfunction unknownAt(registry: Registry, id: string, tail: readonly string[]): MextError {\n const segs: string[] = []\n for (const t of tail) {\n if (t.startsWith(\"-\") || (segs.length > 0 && !isSegment(t))) break\n segs.push(t)\n if (!isSegment(t)) break\n }\n const unknown = [id, ...segs].filter((s) => s !== \"\").join(\".\")\n try {\n findCommand(registry, unknown)\n } catch (error) {\n if (error instanceof MextError) return error\n throw error\n }\n return new MextError(\"UNKNOWN_COMMAND\", `Unknown command \"${unknown}\".`, { command: unknown, suggested: [], usage: \"help\" })\n}\n\n/** --help --json = MCP help 의 structuredContent 와 같은 데이터 (mext mcp 의 tools 노출 기준) */\nfunction printHelp(\n registry: Registry,\n id: string,\n io: CliIo,\n prog: string,\n json: boolean,\n tools: ToolExposure | undefined,\n footer: string | undefined,\n): number {\n const toolFor = tools === \"split\" ? (e: RegisteredCommand) => (e.command.readOnly ? \"query\" : \"mutate\") : undefined\n io.stdout.write(json ? formatJson(help(registry, id, toolFor ? { toolFor } : {})) : helpText(registry, id, prog, footer))\n return EXIT.ok\n}\n\n/** 사람용 help. 루트면 footer 를 붙인다 */\nfunction helpText(registry: Registry, id: string, prog: string, footer: string | undefined): string {\n const text = renderHelp(registry, id, { prog })\n return id === \"\" && footer ? `${text}\\n${footer}` : text\n}\n\nfunction report(error: unknown, io: CliIo, prog: string, json: boolean, formatter?: CliErrorFormatter): number {\n return emitError(io, { body: errorJson(error), text: formatError(error, prog), exitCode: exitCodeOf(error), json }, formatter)\n}\n\nfunction usageError(message: string): MextError<\"INVALID_ARGUMENT\"> {\n return new MextError(\"INVALID_ARGUMENT\", message, {\n command: \"\",\n missing_fields: [],\n issues: [{ path: \"\", code: \"unknown_flag\", message }],\n expected_schema: {},\n examples: [],\n })\n}\n\n\n/**\n * ctx.ask. --yes = confirm 승인. TTY 없음 = 즉시 INPUT_UNAVAILABLE.\n * TTY = stderr 프롬프트 + stdin 한 줄 (confirm = y/yes, input = 필드별 입력을 스키마 모양으로 변환)\n */\nfunction askHandler(io: CliIo, lines: LineReader, yes: boolean, signal: AbortSignal): AskHandler {\n return async (request) => {\n if (request.kind === \"confirm\" && yes) return true\n if (!io.isTTY) {\n const hint = request.kind === \"confirm\" ? \" Pass --yes to approve.\" : \" Run it in an interactive terminal.\"\n throw new MextError(\n \"INPUT_UNAVAILABLE\",\n `${request.command} asked \"${request.message}\", but stdin is not a terminal.${hint}`,\n { command: request.command },\n )\n }\n if (request.kind === \"confirm\") {\n const answer = await lines.question(`${request.message} [y/N] `, signal)\n if (signal.aborted) throw new CliInterrupted()\n return /^y(es)?$/i.test((answer ?? \"\").trim())\n }\n io.stderr.write(`${request.message}\\n`)\n const { spec } = analyzeInput(request.schema, request.requestedSchema)\n const out: Record<string, unknown> = {}\n for (const f of spec.fields) {\n const answer = await lines.question(` ${f.key}${f.required ? \"\" : \" (optional)\"}: `, signal)\n if (signal.aborted) throw new CliInterrupted()\n if (answer === undefined || answer === \"\") continue\n if (f.kind.type === \"array\") {\n const kind = f.kind\n out[f.key] = answer.split(\",\").map((s) => {\n const r = coerceValue(kind, s.trim())\n return r.ok ? r.value : s\n })\n continue\n }\n const r = coerceValue(f.kind, answer)\n out[f.key] = r.ok ? r.value : answer\n }\n return out\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"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","sourcesContent":["import { createApp, loadCliErrorFormatter, loadConfig, resolveCommandsDir, resolveLocalPrincipal, type MextConfig } from \"../config.ts\"\nimport { MextError } from \"../errors.ts\"\nimport { isSegment } from \"../ids.ts\"\nimport { loadProjectInstrumentation, type Instrumentation } from \"../instrumentation.ts\"\nimport { authorize, findCommand, invoke, type AskHandler } from \"../invoke.ts\"\nimport type { ToolExposure } from \"../mcp/dispatch.ts\"\nimport { help } from \"../mcp/help.ts\"\nimport { loadCommand, resolveCommand, type RegisteredCommand, type Registry } from \"../registry.ts\"\nimport { loadRegistry } from \"../scan.ts\"\nimport { analyzeInput, assertCliConvertible, coerceValue, defineCliSpec, parseArgs } from \"./args.ts\"\nimport { askUrl } from \"./ask-url.ts\"\nimport { cliPath, renderHelp } from \"./help.ts\"\nimport { createLineReader, readAll, type CliIo, type LineReader } from \"./io.ts\"\nimport {\n CliInterrupted,\n emitError,\n EXIT,\n errorJson,\n exitCodeOf,\n formatError,\n formatJson,\n formatProgress,\n formatResult,\n type CliErrorFormatter,\n} from \"./output.ts\"\nimport { remoteTarget, runRemoteCommand } from \"./remote.ts\"\n\nexport const RUN_PROG = \"mext run\"\n\n/** 로컬 실행에 필요한 것: 계측 · 설정 · Registry (+ cli.errors formatter) */\nexport interface LocalRunLoaded {\n instrumentation: Instrumentation\n config: MextConfig\n registry: Registry\n}\n\n/**\n * 로컬 실행 코어의 입력. mext run = 소스 (commands/ · mext.config.ts), 로컬 bin = .mext/ 빌드 (start.ts runLocalBin)\n */\nexport interface LocalRunSource {\n /** help · 오류 안내의 명령 이름 (\"mext run\" · \"<bin>\") */\n prog: string\n /** 루트 help 뒤에 붙일 텍스트 (로컬 bin 내장 명령) */\n footer?: string\n /** instrumentation register → 설정 → formatter (setFormatter 로 즉시 전달, 이후 오류에 적용) → Registry */\n load(setFormatter: (formatter: CliErrorFormatter | undefined) => void): Promise<LocalRunLoaded>\n}\n\n/** mext run 의 소스: 도입 프로젝트 (cwd) 의 instrumentation.ts · mext.config.ts · cli.errors · commands/ */\nexport function projectSource(cwd: string): LocalRunSource {\n return {\n prog: RUN_PROG,\n async load(setFormatter) {\n // instrumentation.ts register() = 설정 · 명령어 모듈 import 전 (프로세스당 1회)\n const instrumentation = await loadProjectInstrumentation(cwd)\n const config = await loadConfig(cwd)\n setFormatter(await loadCliErrorFormatter(cwd, config))\n const registry = await loadRegistry(resolveCommandsDir(cwd, config))\n assertCliConvertible(registry)\n return { instrumentation, config, registry }\n },\n }\n}\n\n/**\n * mext run <ns> <cmd> [flags] — 로컬 실행 (ctx.principal.kind = local, mext.config.ts 의 localPrincipal 로 변경 가능).\n * mext run help [target] · mext run [<ns> [<cmd>]] --help · --json · --yes.\n * --url <url> (또는 MEXT_URL) = 원격 실행 (cli/remote.ts)\n */\nexport async function runCommand(argv: readonly string[], io: CliIo): Promise<number> {\n const remote = remoteTarget(argv, io.env)\n if (remote) return runRemoteCommand(remote, io)\n return runLocalCommand(argv, io, projectSource(io.cwd))\n}\n\n/**\n * 로컬 실행 코어 (mext run · 로컬 bin 공통). argv = 명령 경로 · 플래그 (help [target] 포함). 반환 = exit code\n */\nexport async function runLocalCommand(argv: readonly string[], io: CliIo, source: LocalRunSource): Promise<number> {\n const prog = source.prog\n const lead = { json: false, yes: false, help: false }\n let i = 0\n for (; i < argv.length; i++) {\n const tok = argv[i]!\n if (!tok.startsWith(\"-\") || tok === \"-\") break\n if (tok === \"--json\") lead.json = true\n else if (tok === \"--yes\") lead.yes = true\n else if (tok === \"--help\" || tok === \"-h\") lead.help = true\n else {\n return report(usageError(`unknown flag ${tok} before the command`), io, prog, argv.includes(\"--json\"))\n }\n }\n const rest = argv.slice(i)\n const beforeDashDash = rest.indexOf(\"--\") < 0 ? rest : rest.slice(0, rest.indexOf(\"--\"))\n const json = lead.json || beforeDashDash.includes(\"--json\")\n\n const lines = createLineReader(io)\n let formatter: CliErrorFormatter | undefined\n try {\n const { instrumentation, config, registry } = await source.load((f) => (formatter = f))\n\n // mext run help [target...]\n if (rest[0] === \"help\") {\n const targetTokens = rest.slice(1).filter((t) => !t.startsWith(\"-\"))\n const { id, consumed } = resolvePath(registry, targetTokens)\n if (consumed < targetTokens.length) throw unknownAt(registry, id, targetTokens.slice(consumed))\n await prepareCliSpec(resolveCommand(registry, id))\n return printHelp(registry, id, io, prog, json, config.tools, source.footer)\n }\n\n const { id, consumed } = resolvePath(registry, rest)\n const entry = id === \"\" ? undefined : resolveCommand(registry, id)\n const next = rest[consumed]\n const acceptsPositional = entry !== undefined && entry.command.positional.length > 0\n if (registry.namespaces.has(id) && next !== undefined && !next.startsWith(\"-\") && !acceptsPositional) {\n throw unknownAt(registry, id, rest.slice(consumed))\n }\n if (entry === undefined && next !== undefined && !next.startsWith(\"-\")) {\n throw unknownAt(registry, id, rest.slice(consumed))\n }\n\n await prepareCliSpec(entry)\n const help = lead.help || beforeDashDash.includes(\"--help\") || beforeDashDash.includes(\"-h\")\n if (help) return printHelp(registry, id, io, prog, json, config.tools, source.footer)\n\n if (!entry) {\n // 네임스페이스 (루트 포함) 만 지정 = 명령어 없음\n const error = new MextError(\n \"UNKNOWN_COMMAND\",\n id === \"\" ? \"No command given.\" : `\"${cliPath(id)}\" is a namespace. Specify a command.`,\n { command: id, suggested: [], usage: id === \"\" ? \"help\" : `help ${id}` },\n )\n if (json) return report(error, io, prog, true, formatter)\n const text = `${formatError(error, prog)}\\n${helpText(registry, id, prog, source.footer)}`\n return emitError(io, { body: errorJson(error), text, exitCode: EXIT.usage, json: false }, formatter)\n }\n\n const principal = await resolveLocalPrincipal(config)\n authorize(entry, principal) // 권한 → 입력 검증 순서 (invoke 와 같음)\n const parsed = await parseArgs(entry, rest.slice(consumed), { readStdin: () => readAll(io.stdin) })\n const yes = lead.yes || parsed.yes\n const app = await createApp(config)\n\n const controller = new AbortController()\n const onAbort = (): void => controller.abort(io.signal?.reason)\n if (io.signal?.aborted) onAbort()\n io.signal?.addEventListener(\"abort\", onAbort, { once: true })\n try {\n const result = await invoke(registry, entry.id, parsed.input, {\n principal,\n signal: controller.signal,\n progress: (update) => io.stderr.write(formatProgress(update)),\n ask: askHandler(io, lines, yes, json, controller.signal),\n app,\n instrumentation,\n transport: \"local\",\n })\n if (controller.signal.aborted) throw new CliInterrupted()\n io.stdout.write(json ? formatJson(result.value) : formatResult(result.value))\n return EXIT.ok\n } catch (error) {\n if (controller.signal.aborted) throw new CliInterrupted()\n throw error\n } finally {\n io.signal?.removeEventListener(\"abort\", onAbort)\n }\n } catch (error) {\n return report(error, io, prog, json, formatter)\n } finally {\n lines.close()\n }\n}\n\n/**\n * lazy Registry (로컬 bin 의 .mext/) 명령어 = 모듈 로드 후 Zod 입력 분석으로 CLI 필드 지정 (mext run 과 같은 파서).\n * 대상 명령어 하나만 로드. eager Registry (mext run) = 그대로\n */\nasync function prepareCliSpec(entry: RegisteredCommand | undefined): Promise<void> {\n if (!entry?.load) return\n const command = await loadCommand(entry)\n defineCliSpec(entry, analyzeInput(command.input, entry.inputSchema, entry.command.positional).spec)\n}\n\n/** 앞쪽 경로 토큰 → 가장 긴 네임스페이스 · 명령어 (별칭 포함) ID */\nexport function resolvePath(registry: Registry, tokens: readonly string[]): { id: string; consumed: number } {\n let id = \"\"\n let consumed = 0\n for (const tok of tokens) {\n if (!isSegment(tok)) break\n const candidate = id === \"\" ? tok : `${id}.${tok}`\n if (!registry.namespaces.has(candidate) && !resolveCommand(registry, candidate)) break\n id = candidate\n consumed++\n }\n return { id, consumed }\n}\n\n/** 해석되지 않은 경로 토큰 → UNKNOWN_COMMAND (suggested · usage) */\nfunction unknownAt(registry: Registry, id: string, tail: readonly string[]): MextError {\n const segs: string[] = []\n for (const t of tail) {\n if (t.startsWith(\"-\") || (segs.length > 0 && !isSegment(t))) break\n segs.push(t)\n if (!isSegment(t)) break\n }\n const unknown = [id, ...segs].filter((s) => s !== \"\").join(\".\")\n try {\n findCommand(registry, unknown)\n } catch (error) {\n if (error instanceof MextError) return error\n throw error\n }\n return new MextError(\"UNKNOWN_COMMAND\", `Unknown command \"${unknown}\".`, { command: unknown, suggested: [], usage: \"help\" })\n}\n\n/** --help --json = MCP help 의 structuredContent 와 같은 데이터 (mext mcp 의 tools 노출 기준) */\nfunction printHelp(\n registry: Registry,\n id: string,\n io: CliIo,\n prog: string,\n json: boolean,\n tools: ToolExposure | undefined,\n footer: string | undefined,\n): number {\n const toolFor = tools === \"split\" ? (e: RegisteredCommand) => (e.command.readOnly ? \"query\" : \"mutate\") : undefined\n io.stdout.write(json ? formatJson(help(registry, id, toolFor ? { toolFor } : {})) : helpText(registry, id, prog, footer))\n return EXIT.ok\n}\n\n/** 사람용 help. 루트면 footer 를 붙인다 */\nfunction helpText(registry: Registry, id: string, prog: string, footer: string | undefined): string {\n const text = renderHelp(registry, id, { prog })\n return id === \"\" && footer ? `${text}\\n${footer}` : text\n}\n\nfunction report(error: unknown, io: CliIo, prog: string, json: boolean, formatter?: CliErrorFormatter): number {\n return emitError(io, { body: errorJson(error), text: formatError(error, prog), exitCode: exitCodeOf(error), json }, formatter)\n}\n\nfunction usageError(message: string): MextError<\"INVALID_ARGUMENT\"> {\n return new MextError(\"INVALID_ARGUMENT\", message, {\n command: \"\",\n missing_fields: [],\n issues: [{ path: \"\", code: \"unknown_flag\", message }],\n expected_schema: {},\n examples: [],\n })\n}\n\n\n/**\n * ctx.ask. --yes = confirm 승인. TTY 없음 = 즉시 INPUT_UNAVAILABLE.\n * TTY = stderr 프롬프트 + stdin 한 줄 (confirm = y/yes, input = 필드별 입력을 스키마 모양으로 변환).\n * url = askUrl (--yes 미적용, --json = INPUT_UNAVAILABLE)\n */\nfunction askHandler(io: CliIo, lines: LineReader, yes: boolean, json: boolean, signal: AbortSignal): AskHandler {\n return async (request) => {\n if (request.kind === \"url\") return askUrl(io, lines, request, { json, signal })\n if (request.kind === \"confirm\" && yes) return true\n if (!io.isTTY) {\n const hint = request.kind === \"confirm\" ? \" Pass --yes to approve.\" : \" Run it in an interactive terminal.\"\n throw new MextError(\n \"INPUT_UNAVAILABLE\",\n `${request.command} asked \"${request.message}\", but stdin is not a terminal.${hint}`,\n { command: request.command },\n )\n }\n if (request.kind === \"confirm\") {\n const answer = await lines.question(`${request.message} [y/N] `, signal)\n if (signal.aborted) throw new CliInterrupted()\n return /^y(es)?$/i.test((answer ?? \"\").trim())\n }\n io.stderr.write(`${request.message}\\n`)\n const { spec } = analyzeInput(request.schema, request.requestedSchema)\n const out: Record<string, unknown> = {}\n for (const f of spec.fields) {\n const answer = await lines.question(` ${f.key}${f.required ? \"\" : \" (optional)\"}: `, signal)\n if (signal.aborted) throw new CliInterrupted()\n if (answer === undefined || answer === \"\") continue\n if (f.kind.type === \"array\") {\n const kind = f.kind\n out[f.key] = answer.split(\",\").map((s) => {\n const r = coerceValue(kind, s.trim())\n return r.ok ? r.value : s\n })\n continue\n }\n const r = coerceValue(f.kind, answer)\n out[f.key] = r.ok ? r.value : answer\n }\n return out\n }\n}\n"]}
|
package/dist/client/cache.d.ts
CHANGED
|
@@ -49,6 +49,8 @@ export interface SchemaCacheEntry {
|
|
|
49
49
|
stale?: true;
|
|
50
50
|
/** tools/list 결과 */
|
|
51
51
|
tools: RemoteTool[];
|
|
52
|
+
/** server/discover _meta["dev.mext/tools"] (범용 형태). 없음 = dispatcher (execute · split) */
|
|
53
|
+
exposure?: string;
|
|
52
54
|
/** help 대상 ("" = 루트) → 결과 */
|
|
53
55
|
help: Record<string, CachedHelp>;
|
|
54
56
|
}
|
|
@@ -62,6 +64,11 @@ export declare function readSchemaCache(file: string, url: string, client: Cache
|
|
|
62
64
|
export declare function writeSchemaCache(file: string, entry: SchemaCacheEntry): Promise<void>;
|
|
63
65
|
export declare function isFresh(entry: SchemaCacheEntry, now: number): boolean;
|
|
64
66
|
export type SchemaMode = "cache" | "embedded" | "server";
|
|
67
|
+
/** 서버 도구 목록 + 노출 방식 (command = 명령어별 도구, 없음 = dispatcher) */
|
|
68
|
+
export interface ToolListing {
|
|
69
|
+
tools: RemoteTool[];
|
|
70
|
+
exposure?: string;
|
|
71
|
+
}
|
|
65
72
|
export interface FetchedHelp {
|
|
66
73
|
value: CachedHelp;
|
|
67
74
|
/** 응답 _meta["dev.mext/manifestHash"] */
|
|
@@ -77,12 +84,13 @@ export interface SchemaOptions {
|
|
|
77
84
|
manifest: ClientManifest;
|
|
78
85
|
hash: string;
|
|
79
86
|
};
|
|
80
|
-
/** 서버 help (tools/call help). UNKNOWN_COMMAND 는 value.error, 그 외 오류 = throw */
|
|
81
|
-
fetchHelp(target: string,
|
|
82
|
-
/** 서버 tools/list */
|
|
87
|
+
/** 서버 help (tools/call help · command 노출 = tools/list). UNKNOWN_COMMAND 는 value.error, 그 외 오류 = throw */
|
|
88
|
+
fetchHelp(target: string, listing: () => Promise<ToolListing>): Promise<FetchedHelp>;
|
|
89
|
+
/** 서버 tools/list (범용 형태 = + server/discover 의 노출 방식) */
|
|
83
90
|
fetchTools(): Promise<{
|
|
84
91
|
tools: RemoteTool[];
|
|
85
92
|
ttlMs?: number;
|
|
93
|
+
exposure?: string;
|
|
86
94
|
}>;
|
|
87
95
|
/** 오프라인 help 안내 (stderr) */
|
|
88
96
|
warn(message: string): void;
|
|
@@ -94,8 +102,10 @@ export interface Schema {
|
|
|
94
102
|
help(target: string): Promise<Help>;
|
|
95
103
|
/** 로컬 (cache · embedded) 파싱 실패 후 서버 help 로 전환. 이미 server = false (재시도 안 함) */
|
|
96
104
|
refetch(): boolean;
|
|
97
|
-
/**
|
|
105
|
+
/** 도구 목록 (유효 캐시 = 네트워크 없음) */
|
|
98
106
|
tools(): Promise<RemoteTool[]>;
|
|
107
|
+
/** fetchTools 의 노출 방식 (유효 캐시 = 네트워크 없음). 없음 = dispatcher */
|
|
108
|
+
exposure(): Promise<string | undefined>;
|
|
99
109
|
/** tools/call 결과 _meta 의 manifestHash 관찰. 이번 help 의 해시와 다르면 stale */
|
|
100
110
|
observe(hash: string | undefined): void;
|
|
101
111
|
/** 바뀐 내용이 있으면 캐시 파일 쓰기 (실패 무시) */
|
package/dist/client/cache.js
CHANGED
|
@@ -54,6 +54,8 @@ export async function readSchemaCache(file, url, client) {
|
|
|
54
54
|
return undefined;
|
|
55
55
|
if (value.manifestHash !== undefined && typeof value.manifestHash !== "string")
|
|
56
56
|
return undefined;
|
|
57
|
+
if (value.exposure !== undefined && typeof value.exposure !== "string")
|
|
58
|
+
return undefined;
|
|
57
59
|
return value;
|
|
58
60
|
}
|
|
59
61
|
/** 원자적 쓰기 (임시 파일 → rename). 실패는 호출자가 무시 (캐시는 최선) */
|
|
@@ -85,6 +87,7 @@ export async function openSchema(options) {
|
|
|
85
87
|
let hash = cached ? cached.manifestHash : mode === "embedded" ? embedded.hash : undefined;
|
|
86
88
|
let help = cached ? { ...cached.help } : {};
|
|
87
89
|
let tools = cached?.tools;
|
|
90
|
+
let exposure = cached?.exposure;
|
|
88
91
|
let fetchedAt = cached?.fetchedAt ?? started;
|
|
89
92
|
let ttlMs = cached?.ttlMs ?? 0;
|
|
90
93
|
let stale = false;
|
|
@@ -92,17 +95,19 @@ export async function openSchema(options) {
|
|
|
92
95
|
let refetched = false;
|
|
93
96
|
let warned = false;
|
|
94
97
|
let pendingTools;
|
|
98
|
+
const listing = (list) => (exposure === undefined ? { tools: list } : { tools: list, exposure });
|
|
95
99
|
const loadTools = () => {
|
|
96
100
|
if (tools)
|
|
97
|
-
return Promise.resolve(tools);
|
|
101
|
+
return Promise.resolve(listing(tools));
|
|
98
102
|
return (pendingTools ??= options
|
|
99
103
|
.fetchTools()
|
|
100
104
|
.then((r) => {
|
|
101
105
|
tools = r.tools;
|
|
106
|
+
exposure = r.exposure;
|
|
102
107
|
ttlMs = r.ttlMs ?? 0;
|
|
103
108
|
fetchedAt = clock();
|
|
104
109
|
dirty = true;
|
|
105
|
-
return r.tools;
|
|
110
|
+
return listing(r.tools);
|
|
106
111
|
})
|
|
107
112
|
.finally(() => {
|
|
108
113
|
pendingTools = undefined;
|
|
@@ -167,7 +172,8 @@ export async function openSchema(options) {
|
|
|
167
172
|
hash = undefined;
|
|
168
173
|
return true;
|
|
169
174
|
},
|
|
170
|
-
tools: loadTools,
|
|
175
|
+
tools: async () => (await loadTools()).tools,
|
|
176
|
+
exposure: async () => (await loadTools()).exposure,
|
|
171
177
|
observe(observed) {
|
|
172
178
|
if (observed === undefined)
|
|
173
179
|
return;
|
|
@@ -193,6 +199,7 @@ export async function openSchema(options) {
|
|
|
193
199
|
ttlMs,
|
|
194
200
|
...(stale ? { stale: true } : {}),
|
|
195
201
|
tools,
|
|
202
|
+
...(exposure !== undefined ? { exposure } : {}),
|
|
196
203
|
help,
|
|
197
204
|
};
|
|
198
205
|
await writeSchemaCache(options.file, entry).catch(() => { });
|
package/dist/client/cache.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/client/cache.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, randomBytes } from \"node:crypto\"\nimport { mkdir, readFile, rename, rm, writeFile } from \"node:fs/promises\"\nimport { join } from \"node:path\"\nimport { MextError, type MextErrorCode } from \"../errors.ts\"\nimport type { Help } from \"../mcp/help.ts\"\nimport { isRecord, RemoteTransportError, type RemoteTool } from \"../remote/client.ts\"\nimport { canonicalServerUrl, envPrefix } from \"../remote/credentials.ts\"\nimport { manifestHelp, type ClientManifest } from \"./manifest.ts\"\n\n/**\n * 원격 스키마 캐시 · drift 감지 (§5 스키마 drift). 고객 CLI · mext run --url 공용 (번들 포함, Node 내장만 import).\n *\n * D4. 파일 = <cache dir>/<sha256(정규화 서버 URL) 앞 16 hex>.json, 쓰기 = 같은 폴더 임시 파일 → rename (원자적).\n * cache dir = <BIN>_CACHE_DIR → $XDG_CACHE_HOME/<bin> → $HOME/.cache/<bin>. 셋 다 없음 = 캐시 없음.\n * 내용 = SchemaCacheEntry. url · client (bin · version · mext 버전) 가 다르면 무효, 수명 = tools/list ttlMs.\n *\n * 이번 실행의 help 출처 (mode):\n * cache 유효 캐시 (수명 안 · stale 아님). help = 캐시 → (해시 = 내장 manifest 면) 내장 manifest → 서버 (캐시에 추가)\n * embedded 번들 형태 · 유효 캐시 없음 · 서버가 내장 manifest 와 다르다는 기록 없음. help = 내장 manifest\n * server 그 외 (범용 · stale · 서버가 내장 manifest 와 다름). help = 서버 (tools/list + help), 캐시 새로 씀\n * tools/call 결과 _meta 의 manifestHash ≠ 이번 help 의 해시 = stale 표시 (이번 결과는 그대로, 다음 실행이 server).\n * 로컬 파싱 실패 = refetch() 로 server 전환 후 1회 재시도 (runner). 오프라인 = 남은 캐시 · 내장 manifest 로 help 만\n */\n\nexport const SCHEMA_CACHE_FORMAT = 1\n\n/** 캐시 무효화 단위. 하나라도 다르면 캐시 무시 */\nexport interface CacheClient {\n /** 실행 파일 이름 (clientInfo.name) */\n bin: string\n /** clientInfo.version (고객 CLI = cli.version, mext = mext 버전) */\n version: string\n /** 클라이언트 런타임의 @obov/mext 버전 (help 해석 코드) */\n mext: string\n}\n\n/** help 결과 또는 UNKNOWN_COMMAND (경로 해석이 가장 긴 접두부터 시도하므로 없는 대상도 기록) */\nexport type CachedHelp = { help: Help } | { error: Record<string, unknown> & { code: string; message: string } }\n\nexport interface SchemaCacheEntry {\n format: typeof SCHEMA_CACHE_FORMAT\n /** 정규화 서버 URL (파일 이름 해시 충돌 확인) */\n url: string\n client: CacheClient\n /** help · tools 가 속한 서버 manifestHash. 없음 = 서버가 보내지 않음 */\n manifestHash?: string\n /** tools/list 받은 시각 (epoch ms) */\n fetchedAt: number\n /** tools/list ttlMs. 0 = 매 실행 재조회 (오프라인 help 용으로만 남김) */\n ttlMs: number\n /** 서버 manifestHash 가 help 와 다름을 관찰. 다음 실행에서 서버 help 재조회 */\n stale?: true\n /** tools/list 결과 */\n tools: RemoteTool[]\n /** help 대상 (\"\" = 루트) → 결과 */\n help: Record<string, CachedHelp>\n}\n\n/** <BIN>_CACHE_DIR → $XDG_CACHE_HOME/<bin> → $HOME/.cache/<bin> (USERPROFILE). 없으면 undefined (캐시 없음) */\nexport function schemaCacheDir(bin: string, env: Record<string, string | undefined>): string | undefined {\n const forced = env[`${envPrefix(bin)}_CACHE_DIR`]\n if (forced) return forced\n if (env.XDG_CACHE_HOME) return join(env.XDG_CACHE_HOME, bin)\n const home = env.HOME || env.USERPROFILE\n return home ? join(home, \".cache\", bin) : undefined\n}\n\n/** <dir>/<sha256(canonicalServerUrl(url)) 앞 16 hex>.json */\nexport function schemaCacheFile(dir: string, url: string): string {\n return join(dir, `${createHash(\"sha256\").update(canonicalServerUrl(url)).digest(\"hex\").slice(0, 16)}.json`)\n}\n\n/** 읽기 + 형식 · url · client 확인. 없음 · 깨짐 · 불일치 = undefined */\nexport async function readSchemaCache(file: string, url: string, client: CacheClient): Promise<SchemaCacheEntry | undefined> {\n let value: unknown\n try {\n value = JSON.parse(await readFile(file, \"utf8\"))\n } catch {\n return undefined\n }\n if (!isRecord(value) || value.format !== SCHEMA_CACHE_FORMAT || value.url !== canonicalServerUrl(url)) return undefined\n const c = value.client\n if (!isRecord(c) || c.bin !== client.bin || c.version !== client.version || c.mext !== client.mext) return undefined\n if (typeof value.fetchedAt !== \"number\" || typeof value.ttlMs !== \"number\") return undefined\n if (!Array.isArray(value.tools) || !isRecord(value.help)) return undefined\n if (value.manifestHash !== undefined && typeof value.manifestHash !== \"string\") return undefined\n return value as unknown as SchemaCacheEntry\n}\n\n/** 원자적 쓰기 (임시 파일 → rename). 실패는 호출자가 무시 (캐시는 최선) */\nexport async function writeSchemaCache(file: string, entry: SchemaCacheEntry): Promise<void> {\n const dir = join(file, \"..\")\n await mkdir(dir, { recursive: true })\n const tmp = `${file}.${process.pid}.${randomBytes(4).toString(\"hex\")}.tmp`\n try {\n await writeFile(tmp, `${JSON.stringify(entry)}\\n`)\n await rename(tmp, file)\n } catch (error) {\n await rm(tmp, { force: true }).catch(() => {})\n throw error\n }\n}\n\nexport function isFresh(entry: SchemaCacheEntry, now: number): boolean {\n return entry.stale !== true && entry.ttlMs > 0 && now >= entry.fetchedAt && now < entry.fetchedAt + entry.ttlMs\n}\n\n/* 실행 하나의 스키마 상태 */\n\nexport type SchemaMode = \"cache\" | \"embedded\" | \"server\"\n\nexport interface FetchedHelp {\n value: CachedHelp\n /** 응답 _meta[\"dev.mext/manifestHash\"] */\n hash: string | undefined\n}\n\nexport interface SchemaOptions {\n /** 캐시 파일. undefined = 캐시 없음 (읽기 · 쓰기 안 함) */\n file: string | undefined\n url: string\n client: CacheClient\n /** 번들 형태의 내장 manifest + 빌드 시 manifestHash */\n embedded?: { manifest: ClientManifest; hash: string }\n /** 서버 help (tools/call help). UNKNOWN_COMMAND 는 value.error, 그 외 오류 = throw */\n fetchHelp(target: string, tools: () => Promise<RemoteTool[]>): Promise<FetchedHelp>\n /** 서버 tools/list */\n fetchTools(): Promise<{ tools: RemoteTool[]; ttlMs?: number }>\n /** 오프라인 help 안내 (stderr) */\n warn(message: string): void\n now?: () => number\n}\n\nexport interface Schema {\n readonly mode: SchemaMode\n /** HelpSource: 대상 → help. 없는 대상 = MextError UNKNOWN_COMMAND */\n help(target: string): Promise<Help>\n /** 로컬 (cache · embedded) 파싱 실패 후 서버 help 로 전환. 이미 server = false (재시도 안 함) */\n refetch(): boolean\n /** dispatcher 도구 목록 (유효 캐시 = 네트워크 없음) */\n tools(): Promise<RemoteTool[]>\n /** tools/call 결과 _meta 의 manifestHash 관찰. 이번 help 의 해시와 다르면 stale */\n observe(hash: string | undefined): void\n /** 바뀐 내용이 있으면 캐시 파일 쓰기 (실패 무시) */\n save(): Promise<void>\n}\n\nexport async function openSchema(options: SchemaOptions): Promise<Schema> {\n const clock = options.now ?? Date.now\n const started = clock()\n const { embedded } = options\n const previous = options.file ? await readSchemaCache(options.file, options.url, options.client) : undefined\n const diverged =\n previous !== undefined &&\n (previous.stale === true || (embedded !== undefined && previous.manifestHash !== undefined && previous.manifestHash !== embedded.hash))\n let mode: SchemaMode =\n previous !== undefined && isFresh(previous, started) ? \"cache\" : embedded && !diverged ? \"embedded\" : \"server\"\n const cached = mode === \"cache\" ? previous : undefined\n\n let hash = cached ? cached.manifestHash : mode === \"embedded\" ? embedded!.hash : undefined\n let help: Record<string, CachedHelp> = cached ? { ...cached.help } : {}\n let tools: RemoteTool[] | undefined = cached?.tools\n let fetchedAt = cached?.fetchedAt ?? started\n let ttlMs = cached?.ttlMs ?? 0\n let stale = false\n let dirty = false\n let refetched = false\n let warned = false\n let pendingTools: Promise<RemoteTool[]> | undefined\n\n const loadTools = (): Promise<RemoteTool[]> => {\n if (tools) return Promise.resolve(tools)\n return (pendingTools ??= options\n .fetchTools()\n .then((r) => {\n tools = r.tools\n ttlMs = r.ttlMs ?? 0\n fetchedAt = clock()\n dirty = true\n return r.tools\n })\n .finally(() => {\n pendingTools = undefined\n }))\n }\n\n const local = (target: string): Help | undefined => {\n const hit = help[target]\n if (hit) return unpack(hit)\n if (embedded && mode !== \"server\" && hash === embedded.hash) return manifestHelp(embedded.manifest, target)\n return undefined\n }\n\n return {\n get mode() {\n return mode\n },\n async help(target) {\n const found = local(target)\n if (found) return found\n let fetched: FetchedHelp\n try {\n fetched = await options.fetchHelp(target, loadTools)\n } catch (error) {\n // 오프라인: 남은 캐시 (수명 지남 · stale) → 내장 manifest. refetch 중이면 runner 가 원래 로컬 오류를 낸다\n if (error instanceof RemoteTransportError && !refetched) {\n const old = previous?.help[target]\n if (old || embedded) {\n if (!warned) options.warn(`warning: ${error.message} Showing ${old ? \"cached\" : \"built-in\"} help.\\n`)\n warned = true\n return old ? unpack(old) : manifestHelp(embedded!.manifest, target)\n }\n }\n throw error\n }\n if (fetched.hash !== undefined) {\n if (hash === undefined) hash = fetched.hash\n else if (fetched.hash !== hash) {\n if (mode === \"server\") {\n // 실행 중 서버 교체: 이전 응답 버림\n help = {}\n hash = fetched.hash\n } else stale = true\n }\n }\n help[target] = fetched.value\n dirty = true\n return unpack(fetched.value)\n },\n refetch() {\n if (mode === \"server\") return false\n mode = \"server\"\n refetched = true\n help = {}\n hash = undefined\n return true\n },\n tools: loadTools,\n observe(observed) {\n if (observed === undefined) return\n if (hash === undefined) {\n hash = observed\n dirty = true\n } else if (observed !== hash) {\n hash = observed\n stale = true\n dirty = true\n }\n },\n async save() {\n if (!options.file || !dirty || !tools) return\n const entry: SchemaCacheEntry = {\n format: SCHEMA_CACHE_FORMAT,\n url: canonicalServerUrl(options.url),\n client: options.client,\n ...(hash !== undefined ? { manifestHash: hash } : {}),\n fetchedAt,\n ttlMs,\n ...(stale ? { stale: true as const } : {}),\n tools,\n help,\n }\n await writeSchemaCache(options.file, entry).catch(() => {})\n },\n }\n}\n\nfunction unpack(cached: CachedHelp): Help {\n if (\"help\" in cached) return cached.help\n const { code, message, ...details } = cached.error\n throw new MextError(code as MextErrorCode, message, details as never)\n}\n"]}
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/client/cache.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, randomBytes } from \"node:crypto\"\nimport { mkdir, readFile, rename, rm, writeFile } from \"node:fs/promises\"\nimport { join } from \"node:path\"\nimport { MextError, type MextErrorCode } from \"../errors.ts\"\nimport type { Help } from \"../mcp/help.ts\"\nimport { isRecord, RemoteTransportError, type RemoteTool } from \"../remote/client.ts\"\nimport { canonicalServerUrl, envPrefix } from \"../remote/credentials.ts\"\nimport { manifestHelp, type ClientManifest } from \"./manifest.ts\"\n\n/**\n * 원격 스키마 캐시 · drift 감지 (§5 스키마 drift). 고객 CLI · mext run --url 공용 (번들 포함, Node 내장만 import).\n *\n * D4. 파일 = <cache dir>/<sha256(정규화 서버 URL) 앞 16 hex>.json, 쓰기 = 같은 폴더 임시 파일 → rename (원자적).\n * cache dir = <BIN>_CACHE_DIR → $XDG_CACHE_HOME/<bin> → $HOME/.cache/<bin>. 셋 다 없음 = 캐시 없음.\n * 내용 = SchemaCacheEntry. url · client (bin · version · mext 버전) 가 다르면 무효, 수명 = tools/list ttlMs.\n *\n * 이번 실행의 help 출처 (mode):\n * cache 유효 캐시 (수명 안 · stale 아님). help = 캐시 → (해시 = 내장 manifest 면) 내장 manifest → 서버 (캐시에 추가)\n * embedded 번들 형태 · 유효 캐시 없음 · 서버가 내장 manifest 와 다르다는 기록 없음. help = 내장 manifest\n * server 그 외 (범용 · stale · 서버가 내장 manifest 와 다름). help = 서버 (tools/list + help), 캐시 새로 씀\n * tools/call 결과 _meta 의 manifestHash ≠ 이번 help 의 해시 = stale 표시 (이번 결과는 그대로, 다음 실행이 server).\n * 로컬 파싱 실패 = refetch() 로 server 전환 후 1회 재시도 (runner). 오프라인 = 남은 캐시 · 내장 manifest 로 help 만\n */\n\nexport const SCHEMA_CACHE_FORMAT = 1\n\n/** 캐시 무효화 단위. 하나라도 다르면 캐시 무시 */\nexport interface CacheClient {\n /** 실행 파일 이름 (clientInfo.name) */\n bin: string\n /** clientInfo.version (고객 CLI = cli.version, mext = mext 버전) */\n version: string\n /** 클라이언트 런타임의 @obov/mext 버전 (help 해석 코드) */\n mext: string\n}\n\n/** help 결과 또는 UNKNOWN_COMMAND (경로 해석이 가장 긴 접두부터 시도하므로 없는 대상도 기록) */\nexport type CachedHelp = { help: Help } | { error: Record<string, unknown> & { code: string; message: string } }\n\nexport interface SchemaCacheEntry {\n format: typeof SCHEMA_CACHE_FORMAT\n /** 정규화 서버 URL (파일 이름 해시 충돌 확인) */\n url: string\n client: CacheClient\n /** help · tools 가 속한 서버 manifestHash. 없음 = 서버가 보내지 않음 */\n manifestHash?: string\n /** tools/list 받은 시각 (epoch ms) */\n fetchedAt: number\n /** tools/list ttlMs. 0 = 매 실행 재조회 (오프라인 help 용으로만 남김) */\n ttlMs: number\n /** 서버 manifestHash 가 help 와 다름을 관찰. 다음 실행에서 서버 help 재조회 */\n stale?: true\n /** tools/list 결과 */\n tools: RemoteTool[]\n /** server/discover _meta[\"dev.mext/tools\"] (범용 형태). 없음 = dispatcher (execute · split) */\n exposure?: string\n /** help 대상 (\"\" = 루트) → 결과 */\n help: Record<string, CachedHelp>\n}\n\n/** <BIN>_CACHE_DIR → $XDG_CACHE_HOME/<bin> → $HOME/.cache/<bin> (USERPROFILE). 없으면 undefined (캐시 없음) */\nexport function schemaCacheDir(bin: string, env: Record<string, string | undefined>): string | undefined {\n const forced = env[`${envPrefix(bin)}_CACHE_DIR`]\n if (forced) return forced\n if (env.XDG_CACHE_HOME) return join(env.XDG_CACHE_HOME, bin)\n const home = env.HOME || env.USERPROFILE\n return home ? join(home, \".cache\", bin) : undefined\n}\n\n/** <dir>/<sha256(canonicalServerUrl(url)) 앞 16 hex>.json */\nexport function schemaCacheFile(dir: string, url: string): string {\n return join(dir, `${createHash(\"sha256\").update(canonicalServerUrl(url)).digest(\"hex\").slice(0, 16)}.json`)\n}\n\n/** 읽기 + 형식 · url · client 확인. 없음 · 깨짐 · 불일치 = undefined */\nexport async function readSchemaCache(file: string, url: string, client: CacheClient): Promise<SchemaCacheEntry | undefined> {\n let value: unknown\n try {\n value = JSON.parse(await readFile(file, \"utf8\"))\n } catch {\n return undefined\n }\n if (!isRecord(value) || value.format !== SCHEMA_CACHE_FORMAT || value.url !== canonicalServerUrl(url)) return undefined\n const c = value.client\n if (!isRecord(c) || c.bin !== client.bin || c.version !== client.version || c.mext !== client.mext) return undefined\n if (typeof value.fetchedAt !== \"number\" || typeof value.ttlMs !== \"number\") return undefined\n if (!Array.isArray(value.tools) || !isRecord(value.help)) return undefined\n if (value.manifestHash !== undefined && typeof value.manifestHash !== \"string\") return undefined\n if (value.exposure !== undefined && typeof value.exposure !== \"string\") return undefined\n return value as unknown as SchemaCacheEntry\n}\n\n/** 원자적 쓰기 (임시 파일 → rename). 실패는 호출자가 무시 (캐시는 최선) */\nexport async function writeSchemaCache(file: string, entry: SchemaCacheEntry): Promise<void> {\n const dir = join(file, \"..\")\n await mkdir(dir, { recursive: true })\n const tmp = `${file}.${process.pid}.${randomBytes(4).toString(\"hex\")}.tmp`\n try {\n await writeFile(tmp, `${JSON.stringify(entry)}\\n`)\n await rename(tmp, file)\n } catch (error) {\n await rm(tmp, { force: true }).catch(() => {})\n throw error\n }\n}\n\nexport function isFresh(entry: SchemaCacheEntry, now: number): boolean {\n return entry.stale !== true && entry.ttlMs > 0 && now >= entry.fetchedAt && now < entry.fetchedAt + entry.ttlMs\n}\n\n/* 실행 하나의 스키마 상태 */\n\nexport type SchemaMode = \"cache\" | \"embedded\" | \"server\"\n\n/** 서버 도구 목록 + 노출 방식 (command = 명령어별 도구, 없음 = dispatcher) */\nexport interface ToolListing {\n tools: RemoteTool[]\n exposure?: string\n}\n\nexport interface FetchedHelp {\n value: CachedHelp\n /** 응답 _meta[\"dev.mext/manifestHash\"] */\n hash: string | undefined\n}\n\nexport interface SchemaOptions {\n /** 캐시 파일. undefined = 캐시 없음 (읽기 · 쓰기 안 함) */\n file: string | undefined\n url: string\n client: CacheClient\n /** 번들 형태의 내장 manifest + 빌드 시 manifestHash */\n embedded?: { manifest: ClientManifest; hash: string }\n /** 서버 help (tools/call help · command 노출 = tools/list). UNKNOWN_COMMAND 는 value.error, 그 외 오류 = throw */\n fetchHelp(target: string, listing: () => Promise<ToolListing>): Promise<FetchedHelp>\n /** 서버 tools/list (범용 형태 = + server/discover 의 노출 방식) */\n fetchTools(): Promise<{ tools: RemoteTool[]; ttlMs?: number; exposure?: string }>\n /** 오프라인 help 안내 (stderr) */\n warn(message: string): void\n now?: () => number\n}\n\nexport interface Schema {\n readonly mode: SchemaMode\n /** HelpSource: 대상 → help. 없는 대상 = MextError UNKNOWN_COMMAND */\n help(target: string): Promise<Help>\n /** 로컬 (cache · embedded) 파싱 실패 후 서버 help 로 전환. 이미 server = false (재시도 안 함) */\n refetch(): boolean\n /** 도구 목록 (유효 캐시 = 네트워크 없음) */\n tools(): Promise<RemoteTool[]>\n /** fetchTools 의 노출 방식 (유효 캐시 = 네트워크 없음). 없음 = dispatcher */\n exposure(): Promise<string | undefined>\n /** tools/call 결과 _meta 의 manifestHash 관찰. 이번 help 의 해시와 다르면 stale */\n observe(hash: string | undefined): void\n /** 바뀐 내용이 있으면 캐시 파일 쓰기 (실패 무시) */\n save(): Promise<void>\n}\n\nexport async function openSchema(options: SchemaOptions): Promise<Schema> {\n const clock = options.now ?? Date.now\n const started = clock()\n const { embedded } = options\n const previous = options.file ? await readSchemaCache(options.file, options.url, options.client) : undefined\n const diverged =\n previous !== undefined &&\n (previous.stale === true || (embedded !== undefined && previous.manifestHash !== undefined && previous.manifestHash !== embedded.hash))\n let mode: SchemaMode =\n previous !== undefined && isFresh(previous, started) ? \"cache\" : embedded && !diverged ? \"embedded\" : \"server\"\n const cached = mode === \"cache\" ? previous : undefined\n\n let hash = cached ? cached.manifestHash : mode === \"embedded\" ? embedded!.hash : undefined\n let help: Record<string, CachedHelp> = cached ? { ...cached.help } : {}\n let tools: RemoteTool[] | undefined = cached?.tools\n let exposure: string | undefined = cached?.exposure\n let fetchedAt = cached?.fetchedAt ?? started\n let ttlMs = cached?.ttlMs ?? 0\n let stale = false\n let dirty = false\n let refetched = false\n let warned = false\n let pendingTools: Promise<ToolListing> | undefined\n const listing = (list: RemoteTool[]): ToolListing => (exposure === undefined ? { tools: list } : { tools: list, exposure })\n\n const loadTools = (): Promise<ToolListing> => {\n if (tools) return Promise.resolve(listing(tools))\n return (pendingTools ??= options\n .fetchTools()\n .then((r) => {\n tools = r.tools\n exposure = r.exposure\n ttlMs = r.ttlMs ?? 0\n fetchedAt = clock()\n dirty = true\n return listing(r.tools)\n })\n .finally(() => {\n pendingTools = undefined\n }))\n }\n\n const local = (target: string): Help | undefined => {\n const hit = help[target]\n if (hit) return unpack(hit)\n if (embedded && mode !== \"server\" && hash === embedded.hash) return manifestHelp(embedded.manifest, target)\n return undefined\n }\n\n return {\n get mode() {\n return mode\n },\n async help(target) {\n const found = local(target)\n if (found) return found\n let fetched: FetchedHelp\n try {\n fetched = await options.fetchHelp(target, loadTools)\n } catch (error) {\n // 오프라인: 남은 캐시 (수명 지남 · stale) → 내장 manifest. refetch 중이면 runner 가 원래 로컬 오류를 낸다\n if (error instanceof RemoteTransportError && !refetched) {\n const old = previous?.help[target]\n if (old || embedded) {\n if (!warned) options.warn(`warning: ${error.message} Showing ${old ? \"cached\" : \"built-in\"} help.\\n`)\n warned = true\n return old ? unpack(old) : manifestHelp(embedded!.manifest, target)\n }\n }\n throw error\n }\n if (fetched.hash !== undefined) {\n if (hash === undefined) hash = fetched.hash\n else if (fetched.hash !== hash) {\n if (mode === \"server\") {\n // 실행 중 서버 교체: 이전 응답 버림\n help = {}\n hash = fetched.hash\n } else stale = true\n }\n }\n help[target] = fetched.value\n dirty = true\n return unpack(fetched.value)\n },\n refetch() {\n if (mode === \"server\") return false\n mode = \"server\"\n refetched = true\n help = {}\n hash = undefined\n return true\n },\n tools: async () => (await loadTools()).tools,\n exposure: async () => (await loadTools()).exposure,\n observe(observed) {\n if (observed === undefined) return\n if (hash === undefined) {\n hash = observed\n dirty = true\n } else if (observed !== hash) {\n hash = observed\n stale = true\n dirty = true\n }\n },\n async save() {\n if (!options.file || !dirty || !tools) return\n const entry: SchemaCacheEntry = {\n format: SCHEMA_CACHE_FORMAT,\n url: canonicalServerUrl(options.url),\n client: options.client,\n ...(hash !== undefined ? { manifestHash: hash } : {}),\n fetchedAt,\n ttlMs,\n ...(stale ? { stale: true as const } : {}),\n tools,\n ...(exposure !== undefined ? { exposure } : {}),\n help,\n }\n await writeSchemaCache(options.file, entry).catch(() => {})\n },\n }\n}\n\nfunction unpack(cached: CachedHelp): Help {\n if (\"help\" in cached) return cached.help\n const { code, message, ...details } = cached.error\n throw new MextError(code as MextErrorCode, message, details as never)\n}\n"]}
|
package/dist/client/main.js
CHANGED
|
@@ -2,7 +2,7 @@ import { table } from "../cli/help.js";
|
|
|
2
2
|
import { resolveIo } from "../cli/io.js";
|
|
3
3
|
import { loginCommand } from "../cli/login.js";
|
|
4
4
|
import { logoutCommand } from "../cli/logout.js";
|
|
5
|
-
import { EXIT, formatJson } from "../cli/output.js";
|
|
5
|
+
import { emitError, EXIT, formatJson } from "../cli/output.js";
|
|
6
6
|
import { mcpInstallText } from "../mcp/install.js";
|
|
7
7
|
import { envPrefix } from "../remote/credentials.js";
|
|
8
8
|
import { runRemote } from "./runner.js";
|
|
@@ -11,9 +11,10 @@ export async function runCustomerCli(config, argv, partialIo = {}, hooks = {}) {
|
|
|
11
11
|
const { bin } = config;
|
|
12
12
|
const prefix = envPrefix(bin);
|
|
13
13
|
const url = io.env[`${prefix}_URL`] || config.url;
|
|
14
|
+
const formatter = hooks.formatError;
|
|
14
15
|
if (!/^https?:\/\//i.test(url)) {
|
|
15
|
-
|
|
16
|
-
return EXIT.usage;
|
|
16
|
+
const message = `${prefix}_URL must be an http(s) URL (got "${url}")`;
|
|
17
|
+
return emitError(io, { body: { code: "INVALID_ARGUMENT", message }, text: `error: ${message}\n`, exitCode: EXIT.usage, json: false }, formatter);
|
|
17
18
|
}
|
|
18
19
|
const [first, ...rest] = argv;
|
|
19
20
|
switch (first) {
|
|
@@ -22,11 +23,11 @@ export async function runCustomerCli(config, argv, partialIo = {}, hooks = {}) {
|
|
|
22
23
|
io.stdout.write(`${config.version}\n`);
|
|
23
24
|
return EXIT.ok;
|
|
24
25
|
case "login":
|
|
25
|
-
return loginCommand({ bin, url })(rest, io);
|
|
26
|
+
return loginCommand({ bin, url, ...(formatter ? { formatter } : {}) })(rest, io);
|
|
26
27
|
case "logout":
|
|
27
|
-
return logoutCommand({ bin, url })(rest, io);
|
|
28
|
+
return logoutCommand({ bin, url, ...(formatter ? { formatter } : {}) })(rest, io);
|
|
28
29
|
case "mcp":
|
|
29
|
-
return mcp(config, url, rest, io);
|
|
30
|
+
return mcp(config, url, rest, io, formatter);
|
|
30
31
|
case "__mext_inspect":
|
|
31
32
|
// 숨김: 지원 · 디버깅용 내장 설정 (토큰 없음)
|
|
32
33
|
io.stdout.write(formatJson({
|
|
@@ -48,7 +49,7 @@ export async function runCustomerCli(config, argv, partialIo = {}, hooks = {}) {
|
|
|
48
49
|
version: config.version,
|
|
49
50
|
...(config.manifest ? { manifest: config.manifest, manifestHash: config.manifestHash } : {}),
|
|
50
51
|
rootHelpFooter: builtinHelp(config, url),
|
|
51
|
-
...(
|
|
52
|
+
...(formatter ? { formatError: formatter } : {}),
|
|
52
53
|
}, argv, io);
|
|
53
54
|
}
|
|
54
55
|
/** 프로세스 진입점 (bin.js). 첫 SIGINT = 진행 중 요청 abort (exit 130), 두 번째 = 즉시 종료 */
|
|
@@ -62,7 +63,7 @@ export async function main(config, hooks = {}) {
|
|
|
62
63
|
const code = await runCustomerCli(config, process.argv.slice(2), { signal: controller.signal }, hooks);
|
|
63
64
|
process.stdout.write("", () => process.stderr.write("", () => process.exit(code)));
|
|
64
65
|
}
|
|
65
|
-
function mcp(config, url, argv, io) {
|
|
66
|
+
function mcp(config, url, argv, io, formatter) {
|
|
66
67
|
const [sub, ...rest] = argv;
|
|
67
68
|
const isHelp = (t) => t === "--help" || t === "-h";
|
|
68
69
|
const usage = `Usage:\n ${config.bin} mcp install Print MCP client registration commands (does not modify client config files)\n`;
|
|
@@ -74,8 +75,8 @@ function mcp(config, url, argv, io) {
|
|
|
74
75
|
io.stdout.write(`${mcpInstallText({ name: config.bin, url, stdioCommand: false, auth: true })}\n`);
|
|
75
76
|
return EXIT.ok;
|
|
76
77
|
}
|
|
77
|
-
|
|
78
|
-
return EXIT.usage;
|
|
78
|
+
const message = sub === undefined ? "missing subcommand" : `unknown argument "${argv.join(" ")}"`;
|
|
79
|
+
return emitError(io, { body: { code: "INVALID_ARGUMENT", message }, text: `error: ${message}\n\n${usage}`, exitCode: EXIT.usage, json: false }, formatter);
|
|
79
80
|
}
|
|
80
81
|
/** 사람용 루트 help 뒤의 내장 명령 · 환경변수 */
|
|
81
82
|
function builtinHelp(config, url) {
|