@obov/mext 0.0.0-stage → 0.1.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-cli.d.ts +39 -0
- package/dist/build-cli.js +160 -0
- package/dist/build-cli.js.map +1 -0
- package/dist/build.d.ts +65 -0
- package/dist/build.js +252 -0
- package/dist/build.js.map +1 -0
- package/dist/cli/args.d.ts +107 -0
- package/dist/cli/args.js +621 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/bin.d.ts +2 -0
- package/dist/cli/bin.js +13 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/build.d.ts +11 -0
- package/dist/cli/build.js +87 -0
- package/dist/cli/build.js.map +1 -0
- package/dist/cli/dev-lock.d.ts +23 -0
- package/dist/cli/dev-lock.js +68 -0
- package/dist/cli/dev-lock.js.map +1 -0
- package/dist/cli/dev-server.d.ts +20 -0
- package/dist/cli/dev-server.js +74 -0
- package/dist/cli/dev-server.js.map +1 -0
- package/dist/cli/dev.d.ts +21 -0
- package/dist/cli/dev.js +564 -0
- package/dist/cli/dev.js.map +1 -0
- package/dist/cli/help.d.ts +31 -0
- package/dist/cli/help.js +238 -0
- package/dist/cli/help.js.map +1 -0
- package/dist/cli/io.d.ts +26 -0
- package/dist/cli/io.js +74 -0
- package/dist/cli/io.js.map +1 -0
- package/dist/cli/login.d.ts +32 -0
- package/dist/cli/login.js +284 -0
- package/dist/cli/login.js.map +1 -0
- package/dist/cli/logout.d.ts +9 -0
- package/dist/cli/logout.js +105 -0
- package/dist/cli/logout.js.map +1 -0
- package/dist/cli/main.d.ts +19 -0
- package/dist/cli/main.js +77 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/mcp.d.ts +16 -0
- package/dist/cli/mcp.js +92 -0
- package/dist/cli/mcp.js.map +1 -0
- package/dist/cli/output.d.ts +34 -0
- package/dist/cli/output.js +172 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/remote.d.ts +17 -0
- package/dist/cli/remote.js +35 -0
- package/dist/cli/remote.js.map +1 -0
- package/dist/cli/run.d.ts +14 -0
- package/dist/cli/run.js +218 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/cli/start.d.ts +8 -0
- package/dist/cli/start.js +37 -0
- package/dist/cli/start.js.map +1 -0
- package/dist/client/cache.d.ts +104 -0
- package/dist/client/cache.js +208 -0
- package/dist/client/cache.js.map +1 -0
- package/dist/client/main.d.ts +25 -0
- package/dist/client/main.js +100 -0
- package/dist/client/main.js.map +1 -0
- package/dist/client/manifest.d.ts +19 -0
- package/dist/client/manifest.js +68 -0
- package/dist/client/manifest.js.map +1 -0
- package/dist/client/runner.d.ts +49 -0
- package/dist/client/runner.js +562 -0
- package/dist/client/runner.js.map +1 -0
- package/dist/command.d.ts +75 -0
- package/dist/command.js +44 -0
- package/dist/command.js.map +1 -0
- package/dist/config.d.ts +53 -0
- package/dist/config.js +122 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +74 -0
- package/dist/errors.js +38 -0
- package/dist/errors.js.map +1 -0
- package/dist/ids.d.ts +6 -0
- package/dist/ids.js +12 -0
- package/dist/ids.js.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/instrumentation.d.ts +97 -0
- package/dist/instrumentation.js +165 -0
- package/dist/instrumentation.js.map +1 -0
- package/dist/invoke.d.ts +64 -0
- package/dist/invoke.js +152 -0
- package/dist/invoke.js.map +1 -0
- package/dist/lookup.d.ts +9 -0
- package/dist/lookup.js +27 -0
- package/dist/lookup.js.map +1 -0
- package/dist/manifest.d.ts +68 -0
- package/dist/manifest.js +77 -0
- package/dist/manifest.js.map +1 -0
- package/dist/mcp/constants.d.ts +9 -0
- package/dist/mcp/constants.js +10 -0
- package/dist/mcp/constants.js.map +1 -0
- package/dist/mcp/dispatch.d.ts +66 -0
- package/dist/mcp/dispatch.js +249 -0
- package/dist/mcp/dispatch.js.map +1 -0
- package/dist/mcp/help.d.ts +57 -0
- package/dist/mcp/help.js +136 -0
- package/dist/mcp/help.js.map +1 -0
- package/dist/mcp/http.d.ts +92 -0
- package/dist/mcp/http.js +366 -0
- package/dist/mcp/http.js.map +1 -0
- package/dist/mcp/index.d.ts +15 -0
- package/dist/mcp/index.js +9 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/install.d.ts +17 -0
- package/dist/mcp/install.js +36 -0
- package/dist/mcp/install.js.map +1 -0
- package/dist/mcp/mrtr.d.ts +82 -0
- package/dist/mcp/mrtr.js +130 -0
- package/dist/mcp/mrtr.js.map +1 -0
- package/dist/mcp/server.d.ts +58 -0
- package/dist/mcp/server.js +204 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/stdio.d.ts +57 -0
- package/dist/mcp/stdio.js +79 -0
- package/dist/mcp/stdio.js.map +1 -0
- package/dist/principal.d.ts +16 -0
- package/dist/principal.js +24 -0
- package/dist/principal.js.map +1 -0
- package/dist/registry.d.ts +90 -0
- package/dist/registry.js +169 -0
- package/dist/registry.js.map +1 -0
- package/dist/remote/browser.d.ts +15 -0
- package/dist/remote/browser.js +47 -0
- package/dist/remote/browser.js.map +1 -0
- package/dist/remote/client.d.ts +113 -0
- package/dist/remote/client.js +312 -0
- package/dist/remote/client.js.map +1 -0
- package/dist/remote/credentials.d.ts +48 -0
- package/dist/remote/credentials.js +196 -0
- package/dist/remote/credentials.js.map +1 -0
- package/dist/remote/index.d.ts +8 -0
- package/dist/remote/index.js +5 -0
- package/dist/remote/index.js.map +1 -0
- package/dist/remote/oauth.d.ts +186 -0
- package/dist/remote/oauth.js +507 -0
- package/dist/remote/oauth.js.map +1 -0
- package/dist/scan.d.ts +34 -0
- package/dist/scan.js +155 -0
- package/dist/scan.js.map +1 -0
- package/dist/start.d.ts +63 -0
- package/dist/start.js +267 -0
- package/dist/start.js.map +1 -0
- package/dist/suggest.d.ts +7 -0
- package/dist/suggest.js +45 -0
- package/dist/suggest.js.map +1 -0
- package/dist/version.d.ts +4 -0
- package/dist/version.js +13 -0
- package/dist/version.js.map +1 -0
- package/package.json +49 -4
- package/README.md +0 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"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","sourcesContent":["import { createApp, loadConfig, resolveCommandsDir, resolveLocalPrincipal } from \"../config.ts\"\nimport { MextError } from \"../errors.ts\"\nimport { isSegment } from \"../ids.ts\"\nimport { loadProjectInstrumentation } 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 { resolveCommand, type RegisteredCommand, type Registry } from \"../registry.ts\"\nimport { loadRegistry } from \"../scan.ts\"\nimport { analyzeInput, assertCliConvertible, coerceValue, parseArgs } from \"./args.ts\"\nimport { cliPath, renderHelp } from \"./help.ts\"\nimport { createLineReader, readAll, type CliIo, type LineReader } from \"./io.ts\"\nimport { CliInterrupted, EXIT, errorJson, exitCodeOf, formatError, formatJson, formatProgress, formatResult } from \"./output.ts\"\nimport { remoteTarget, runRemoteCommand } from \"./remote.ts\"\n\nexport const RUN_PROG = \"mext run\"\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 const prog = RUN_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 try {\n // instrumentation.ts register() = 설정 · 명령어 모듈 import 전 (프로세스당 1회)\n const instrumentation = await loadProjectInstrumentation(io.cwd)\n const config = await loadConfig(io.cwd)\n const registry = await loadRegistry(resolveCommandsDir(io.cwd, config))\n assertCliConvertible(registry)\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 return printHelp(registry, id, io, prog, json, config.tools)\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 const help = lead.help || beforeDashDash.includes(\"--help\") || beforeDashDash.includes(\"-h\")\n if (help) return printHelp(registry, id, io, prog, json, config.tools)\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)\n io.stderr.write(formatError(error, prog))\n io.stderr.write(`\\n${renderHelp(registry, id, { prog })}`)\n return EXIT.usage\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)\n } finally {\n lines.close()\n }\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(registry: Registry, id: string, io: CliIo, prog: string, json: boolean, tools: ToolExposure | undefined): 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 } : {})) : renderHelp(registry, id, { prog }))\n return EXIT.ok\n}\n\nfunction report(error: unknown, io: CliIo, prog: string, json: boolean): number {\n io.stderr.write(json ? formatJson(errorJson(error)) : formatError(error, prog))\n return exitCodeOf(error)\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"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CliIo } from "./io.ts";
|
|
2
|
+
export declare const START_PROG = "mext start";
|
|
3
|
+
/**
|
|
4
|
+
* mext start [--stdio] [--port <n>] [--host <h>] = startFromBuild(<cwd>/.mext) (node .mext/server.js 와 같음).
|
|
5
|
+
* .mext/ 만 읽는다 (소스 스캔 · 감시 · TypeScript 없음). 종료 = SIGINT · SIGTERM
|
|
6
|
+
*/
|
|
7
|
+
export declare function startCommand(argv: readonly string[], io: CliIo): Promise<number>;
|
|
8
|
+
export declare function startHelp(): string;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { BUILD_DIR } from "../build.js";
|
|
3
|
+
import { startFromBuild } from "../start.js";
|
|
4
|
+
import { table } from "./help.js";
|
|
5
|
+
import { EXIT } from "./output.js";
|
|
6
|
+
export const START_PROG = "mext start";
|
|
7
|
+
/**
|
|
8
|
+
* mext start [--stdio] [--port <n>] [--host <h>] = startFromBuild(<cwd>/.mext) (node .mext/server.js 와 같음).
|
|
9
|
+
* .mext/ 만 읽는다 (소스 스캔 · 감시 · TypeScript 없음). 종료 = SIGINT · SIGTERM
|
|
10
|
+
*/
|
|
11
|
+
export async function startCommand(argv, io) {
|
|
12
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
13
|
+
io.stdout.write(startHelp());
|
|
14
|
+
return EXIT.ok;
|
|
15
|
+
}
|
|
16
|
+
return startFromBuild(join(io.cwd, BUILD_DIR), { argv, env: io.env, stderr: io.stderr });
|
|
17
|
+
}
|
|
18
|
+
export function startHelp() {
|
|
19
|
+
const lines = [
|
|
20
|
+
"Production MCP server from .mext/ (run mext build first). No source scan, no file watching.",
|
|
21
|
+
"",
|
|
22
|
+
"Usage:",
|
|
23
|
+
` ${START_PROG} [--port <n>] [--host <h>] Streamable HTTP (POST /mcp)`,
|
|
24
|
+
` ${START_PROG} --stdio stdio`,
|
|
25
|
+
"",
|
|
26
|
+
"Flags:",
|
|
27
|
+
...table([
|
|
28
|
+
["--stdio", "Serve MCP over stdin/stdout"],
|
|
29
|
+
["--port <n>", "HTTP port (default: PORT, then mext.config.ts server.port, then 3100)"],
|
|
30
|
+
["--host <h>", "HTTP host (default: HOST, then mext.config.ts server.host, then 127.0.0.1)"],
|
|
31
|
+
]).map((l) => ` ${l}`),
|
|
32
|
+
"",
|
|
33
|
+
"Same as: node .mext/server.js [--stdio]",
|
|
34
|
+
];
|
|
35
|
+
return `${lines.join("\n")}\n`;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=start.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.js","sourceRoot":"","sources":["../../src/cli/start.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAA;AAEjC,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAElC,MAAM,CAAC,MAAM,UAAU,GAAG,YAAY,CAAA;AAEtC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAuB,EAAE,EAAS;IACnE,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,CAAA;QAC5B,OAAO,IAAI,CAAC,EAAE,CAAA;IAChB,CAAC;IACD,OAAO,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAA;AAC1F,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,MAAM,KAAK,GAAG;QACZ,6FAA6F;QAC7F,EAAE;QACF,QAAQ;QACR,KAAK,UAAU,0DAA0D;QACzE,KAAK,UAAU,oCAAoC;QACnD,EAAE;QACF,QAAQ;QACR,GAAG,KAAK,CAAC;YACP,CAAC,SAAS,EAAE,6BAA6B,CAAC;YAC1C,CAAC,YAAY,EAAE,uEAAuE,CAAC;YACvF,CAAC,YAAY,EAAE,4EAA4E,CAAC;SAC7F,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;QACvB,EAAE;QACF,yCAAyC;KAC1C,CAAA;IACD,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAA;AAChC,CAAC","sourcesContent":["import { join } from \"node:path\"\nimport { BUILD_DIR } from \"../build.ts\"\nimport { startFromBuild } from \"../start.ts\"\nimport { table } from \"./help.ts\"\nimport type { CliIo } from \"./io.ts\"\nimport { EXIT } from \"./output.ts\"\n\nexport const START_PROG = \"mext start\"\n\n/**\n * mext start [--stdio] [--port <n>] [--host <h>] = startFromBuild(<cwd>/.mext) (node .mext/server.js 와 같음).\n * .mext/ 만 읽는다 (소스 스캔 · 감시 · TypeScript 없음). 종료 = SIGINT · SIGTERM\n */\nexport async function startCommand(argv: readonly string[], io: CliIo): Promise<number> {\n if (argv.includes(\"--help\") || argv.includes(\"-h\")) {\n io.stdout.write(startHelp())\n return EXIT.ok\n }\n return startFromBuild(join(io.cwd, BUILD_DIR), { argv, env: io.env, stderr: io.stderr })\n}\n\nexport function startHelp(): string {\n const lines = [\n \"Production MCP server from .mext/ (run mext build first). No source scan, no file watching.\",\n \"\",\n \"Usage:\",\n ` ${START_PROG} [--port <n>] [--host <h>] Streamable HTTP (POST /mcp)`,\n ` ${START_PROG} --stdio stdio`,\n \"\",\n \"Flags:\",\n ...table([\n [\"--stdio\", \"Serve MCP over stdin/stdout\"],\n [\"--port <n>\", \"HTTP port (default: PORT, then mext.config.ts server.port, then 3100)\"],\n [\"--host <h>\", \"HTTP host (default: HOST, then mext.config.ts server.host, then 127.0.0.1)\"],\n ]).map((l) => ` ${l}`),\n \"\",\n \"Same as: node .mext/server.js [--stdio]\",\n ]\n return `${lines.join(\"\\n\")}\\n`\n}\n"]}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { Help } from "../mcp/help.ts";
|
|
2
|
+
import { type RemoteTool } from "../remote/client.ts";
|
|
3
|
+
import { type ClientManifest } from "./manifest.ts";
|
|
4
|
+
/**
|
|
5
|
+
* 원격 스키마 캐시 · drift 감지 (§5 스키마 drift). 고객 CLI · mext run --url 공용 (번들 포함, Node 내장만 import).
|
|
6
|
+
*
|
|
7
|
+
* D4. 파일 = <cache dir>/<sha256(정규화 서버 URL) 앞 16 hex>.json, 쓰기 = 같은 폴더 임시 파일 → rename (원자적).
|
|
8
|
+
* cache dir = <BIN>_CACHE_DIR → $XDG_CACHE_HOME/<bin> → $HOME/.cache/<bin>. 셋 다 없음 = 캐시 없음.
|
|
9
|
+
* 내용 = SchemaCacheEntry. url · client (bin · version · mext 버전) 가 다르면 무효, 수명 = tools/list ttlMs.
|
|
10
|
+
*
|
|
11
|
+
* 이번 실행의 help 출처 (mode):
|
|
12
|
+
* cache 유효 캐시 (수명 안 · stale 아님). help = 캐시 → (해시 = 내장 manifest 면) 내장 manifest → 서버 (캐시에 추가)
|
|
13
|
+
* embedded 번들 형태 · 유효 캐시 없음 · 서버가 내장 manifest 와 다르다는 기록 없음. help = 내장 manifest
|
|
14
|
+
* server 그 외 (범용 · stale · 서버가 내장 manifest 와 다름). help = 서버 (tools/list + help), 캐시 새로 씀
|
|
15
|
+
* tools/call 결과 _meta 의 manifestHash ≠ 이번 help 의 해시 = stale 표시 (이번 결과는 그대로, 다음 실행이 server).
|
|
16
|
+
* 로컬 파싱 실패 = refetch() 로 server 전환 후 1회 재시도 (runner). 오프라인 = 남은 캐시 · 내장 manifest 로 help 만
|
|
17
|
+
*/
|
|
18
|
+
export declare const SCHEMA_CACHE_FORMAT = 1;
|
|
19
|
+
/** 캐시 무효화 단위. 하나라도 다르면 캐시 무시 */
|
|
20
|
+
export interface CacheClient {
|
|
21
|
+
/** 실행 파일 이름 (clientInfo.name) */
|
|
22
|
+
bin: string;
|
|
23
|
+
/** clientInfo.version (고객 CLI = cli.version, mext = mext 버전) */
|
|
24
|
+
version: string;
|
|
25
|
+
/** 클라이언트 런타임의 @obov/mext 버전 (help 해석 코드) */
|
|
26
|
+
mext: string;
|
|
27
|
+
}
|
|
28
|
+
/** help 결과 또는 UNKNOWN_COMMAND (경로 해석이 가장 긴 접두부터 시도하므로 없는 대상도 기록) */
|
|
29
|
+
export type CachedHelp = {
|
|
30
|
+
help: Help;
|
|
31
|
+
} | {
|
|
32
|
+
error: Record<string, unknown> & {
|
|
33
|
+
code: string;
|
|
34
|
+
message: string;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
export interface SchemaCacheEntry {
|
|
38
|
+
format: typeof SCHEMA_CACHE_FORMAT;
|
|
39
|
+
/** 정규화 서버 URL (파일 이름 해시 충돌 확인) */
|
|
40
|
+
url: string;
|
|
41
|
+
client: CacheClient;
|
|
42
|
+
/** help · tools 가 속한 서버 manifestHash. 없음 = 서버가 보내지 않음 */
|
|
43
|
+
manifestHash?: string;
|
|
44
|
+
/** tools/list 받은 시각 (epoch ms) */
|
|
45
|
+
fetchedAt: number;
|
|
46
|
+
/** tools/list ttlMs. 0 = 매 실행 재조회 (오프라인 help 용으로만 남김) */
|
|
47
|
+
ttlMs: number;
|
|
48
|
+
/** 서버 manifestHash 가 help 와 다름을 관찰. 다음 실행에서 서버 help 재조회 */
|
|
49
|
+
stale?: true;
|
|
50
|
+
/** tools/list 결과 */
|
|
51
|
+
tools: RemoteTool[];
|
|
52
|
+
/** help 대상 ("" = 루트) → 결과 */
|
|
53
|
+
help: Record<string, CachedHelp>;
|
|
54
|
+
}
|
|
55
|
+
/** <BIN>_CACHE_DIR → $XDG_CACHE_HOME/<bin> → $HOME/.cache/<bin> (USERPROFILE). 없으면 undefined (캐시 없음) */
|
|
56
|
+
export declare function schemaCacheDir(bin: string, env: Record<string, string | undefined>): string | undefined;
|
|
57
|
+
/** <dir>/<sha256(canonicalServerUrl(url)) 앞 16 hex>.json */
|
|
58
|
+
export declare function schemaCacheFile(dir: string, url: string): string;
|
|
59
|
+
/** 읽기 + 형식 · url · client 확인. 없음 · 깨짐 · 불일치 = undefined */
|
|
60
|
+
export declare function readSchemaCache(file: string, url: string, client: CacheClient): Promise<SchemaCacheEntry | undefined>;
|
|
61
|
+
/** 원자적 쓰기 (임시 파일 → rename). 실패는 호출자가 무시 (캐시는 최선) */
|
|
62
|
+
export declare function writeSchemaCache(file: string, entry: SchemaCacheEntry): Promise<void>;
|
|
63
|
+
export declare function isFresh(entry: SchemaCacheEntry, now: number): boolean;
|
|
64
|
+
export type SchemaMode = "cache" | "embedded" | "server";
|
|
65
|
+
export interface FetchedHelp {
|
|
66
|
+
value: CachedHelp;
|
|
67
|
+
/** 응답 _meta["dev.mext/manifestHash"] */
|
|
68
|
+
hash: string | undefined;
|
|
69
|
+
}
|
|
70
|
+
export interface SchemaOptions {
|
|
71
|
+
/** 캐시 파일. undefined = 캐시 없음 (읽기 · 쓰기 안 함) */
|
|
72
|
+
file: string | undefined;
|
|
73
|
+
url: string;
|
|
74
|
+
client: CacheClient;
|
|
75
|
+
/** 번들 형태의 내장 manifest + 빌드 시 manifestHash */
|
|
76
|
+
embedded?: {
|
|
77
|
+
manifest: ClientManifest;
|
|
78
|
+
hash: string;
|
|
79
|
+
};
|
|
80
|
+
/** 서버 help (tools/call help). UNKNOWN_COMMAND 는 value.error, 그 외 오류 = throw */
|
|
81
|
+
fetchHelp(target: string, tools: () => Promise<RemoteTool[]>): Promise<FetchedHelp>;
|
|
82
|
+
/** 서버 tools/list */
|
|
83
|
+
fetchTools(): Promise<{
|
|
84
|
+
tools: RemoteTool[];
|
|
85
|
+
ttlMs?: number;
|
|
86
|
+
}>;
|
|
87
|
+
/** 오프라인 help 안내 (stderr) */
|
|
88
|
+
warn(message: string): void;
|
|
89
|
+
now?: () => number;
|
|
90
|
+
}
|
|
91
|
+
export interface Schema {
|
|
92
|
+
readonly mode: SchemaMode;
|
|
93
|
+
/** HelpSource: 대상 → help. 없는 대상 = MextError UNKNOWN_COMMAND */
|
|
94
|
+
help(target: string): Promise<Help>;
|
|
95
|
+
/** 로컬 (cache · embedded) 파싱 실패 후 서버 help 로 전환. 이미 server = false (재시도 안 함) */
|
|
96
|
+
refetch(): boolean;
|
|
97
|
+
/** dispatcher 도구 목록 (유효 캐시 = 네트워크 없음) */
|
|
98
|
+
tools(): Promise<RemoteTool[]>;
|
|
99
|
+
/** tools/call 결과 _meta 의 manifestHash 관찰. 이번 help 의 해시와 다르면 stale */
|
|
100
|
+
observe(hash: string | undefined): void;
|
|
101
|
+
/** 바뀐 내용이 있으면 캐시 파일 쓰기 (실패 무시) */
|
|
102
|
+
save(): Promise<void>;
|
|
103
|
+
}
|
|
104
|
+
export declare function openSchema(options: SchemaOptions): Promise<Schema>;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { MextError } from "../errors.js";
|
|
5
|
+
import { isRecord, RemoteTransportError } from "../remote/client.js";
|
|
6
|
+
import { canonicalServerUrl, envPrefix } from "../remote/credentials.js";
|
|
7
|
+
import { manifestHelp } from "./manifest.js";
|
|
8
|
+
/**
|
|
9
|
+
* 원격 스키마 캐시 · drift 감지 (§5 스키마 drift). 고객 CLI · mext run --url 공용 (번들 포함, Node 내장만 import).
|
|
10
|
+
*
|
|
11
|
+
* D4. 파일 = <cache dir>/<sha256(정규화 서버 URL) 앞 16 hex>.json, 쓰기 = 같은 폴더 임시 파일 → rename (원자적).
|
|
12
|
+
* cache dir = <BIN>_CACHE_DIR → $XDG_CACHE_HOME/<bin> → $HOME/.cache/<bin>. 셋 다 없음 = 캐시 없음.
|
|
13
|
+
* 내용 = SchemaCacheEntry. url · client (bin · version · mext 버전) 가 다르면 무효, 수명 = tools/list ttlMs.
|
|
14
|
+
*
|
|
15
|
+
* 이번 실행의 help 출처 (mode):
|
|
16
|
+
* cache 유효 캐시 (수명 안 · stale 아님). help = 캐시 → (해시 = 내장 manifest 면) 내장 manifest → 서버 (캐시에 추가)
|
|
17
|
+
* embedded 번들 형태 · 유효 캐시 없음 · 서버가 내장 manifest 와 다르다는 기록 없음. help = 내장 manifest
|
|
18
|
+
* server 그 외 (범용 · stale · 서버가 내장 manifest 와 다름). help = 서버 (tools/list + help), 캐시 새로 씀
|
|
19
|
+
* tools/call 결과 _meta 의 manifestHash ≠ 이번 help 의 해시 = stale 표시 (이번 결과는 그대로, 다음 실행이 server).
|
|
20
|
+
* 로컬 파싱 실패 = refetch() 로 server 전환 후 1회 재시도 (runner). 오프라인 = 남은 캐시 · 내장 manifest 로 help 만
|
|
21
|
+
*/
|
|
22
|
+
export const SCHEMA_CACHE_FORMAT = 1;
|
|
23
|
+
/** <BIN>_CACHE_DIR → $XDG_CACHE_HOME/<bin> → $HOME/.cache/<bin> (USERPROFILE). 없으면 undefined (캐시 없음) */
|
|
24
|
+
export function schemaCacheDir(bin, env) {
|
|
25
|
+
const forced = env[`${envPrefix(bin)}_CACHE_DIR`];
|
|
26
|
+
if (forced)
|
|
27
|
+
return forced;
|
|
28
|
+
if (env.XDG_CACHE_HOME)
|
|
29
|
+
return join(env.XDG_CACHE_HOME, bin);
|
|
30
|
+
const home = env.HOME || env.USERPROFILE;
|
|
31
|
+
return home ? join(home, ".cache", bin) : undefined;
|
|
32
|
+
}
|
|
33
|
+
/** <dir>/<sha256(canonicalServerUrl(url)) 앞 16 hex>.json */
|
|
34
|
+
export function schemaCacheFile(dir, url) {
|
|
35
|
+
return join(dir, `${createHash("sha256").update(canonicalServerUrl(url)).digest("hex").slice(0, 16)}.json`);
|
|
36
|
+
}
|
|
37
|
+
/** 읽기 + 형식 · url · client 확인. 없음 · 깨짐 · 불일치 = undefined */
|
|
38
|
+
export async function readSchemaCache(file, url, client) {
|
|
39
|
+
let value;
|
|
40
|
+
try {
|
|
41
|
+
value = JSON.parse(await readFile(file, "utf8"));
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
if (!isRecord(value) || value.format !== SCHEMA_CACHE_FORMAT || value.url !== canonicalServerUrl(url))
|
|
47
|
+
return undefined;
|
|
48
|
+
const c = value.client;
|
|
49
|
+
if (!isRecord(c) || c.bin !== client.bin || c.version !== client.version || c.mext !== client.mext)
|
|
50
|
+
return undefined;
|
|
51
|
+
if (typeof value.fetchedAt !== "number" || typeof value.ttlMs !== "number")
|
|
52
|
+
return undefined;
|
|
53
|
+
if (!Array.isArray(value.tools) || !isRecord(value.help))
|
|
54
|
+
return undefined;
|
|
55
|
+
if (value.manifestHash !== undefined && typeof value.manifestHash !== "string")
|
|
56
|
+
return undefined;
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
/** 원자적 쓰기 (임시 파일 → rename). 실패는 호출자가 무시 (캐시는 최선) */
|
|
60
|
+
export async function writeSchemaCache(file, entry) {
|
|
61
|
+
const dir = join(file, "..");
|
|
62
|
+
await mkdir(dir, { recursive: true });
|
|
63
|
+
const tmp = `${file}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`;
|
|
64
|
+
try {
|
|
65
|
+
await writeFile(tmp, `${JSON.stringify(entry)}\n`);
|
|
66
|
+
await rename(tmp, file);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
await rm(tmp, { force: true }).catch(() => { });
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export function isFresh(entry, now) {
|
|
74
|
+
return entry.stale !== true && entry.ttlMs > 0 && now >= entry.fetchedAt && now < entry.fetchedAt + entry.ttlMs;
|
|
75
|
+
}
|
|
76
|
+
export async function openSchema(options) {
|
|
77
|
+
const clock = options.now ?? Date.now;
|
|
78
|
+
const started = clock();
|
|
79
|
+
const { embedded } = options;
|
|
80
|
+
const previous = options.file ? await readSchemaCache(options.file, options.url, options.client) : undefined;
|
|
81
|
+
const diverged = previous !== undefined &&
|
|
82
|
+
(previous.stale === true || (embedded !== undefined && previous.manifestHash !== undefined && previous.manifestHash !== embedded.hash));
|
|
83
|
+
let mode = previous !== undefined && isFresh(previous, started) ? "cache" : embedded && !diverged ? "embedded" : "server";
|
|
84
|
+
const cached = mode === "cache" ? previous : undefined;
|
|
85
|
+
let hash = cached ? cached.manifestHash : mode === "embedded" ? embedded.hash : undefined;
|
|
86
|
+
let help = cached ? { ...cached.help } : {};
|
|
87
|
+
let tools = cached?.tools;
|
|
88
|
+
let fetchedAt = cached?.fetchedAt ?? started;
|
|
89
|
+
let ttlMs = cached?.ttlMs ?? 0;
|
|
90
|
+
let stale = false;
|
|
91
|
+
let dirty = false;
|
|
92
|
+
let refetched = false;
|
|
93
|
+
let warned = false;
|
|
94
|
+
let pendingTools;
|
|
95
|
+
const loadTools = () => {
|
|
96
|
+
if (tools)
|
|
97
|
+
return Promise.resolve(tools);
|
|
98
|
+
return (pendingTools ??= options
|
|
99
|
+
.fetchTools()
|
|
100
|
+
.then((r) => {
|
|
101
|
+
tools = r.tools;
|
|
102
|
+
ttlMs = r.ttlMs ?? 0;
|
|
103
|
+
fetchedAt = clock();
|
|
104
|
+
dirty = true;
|
|
105
|
+
return r.tools;
|
|
106
|
+
})
|
|
107
|
+
.finally(() => {
|
|
108
|
+
pendingTools = undefined;
|
|
109
|
+
}));
|
|
110
|
+
};
|
|
111
|
+
const local = (target) => {
|
|
112
|
+
const hit = help[target];
|
|
113
|
+
if (hit)
|
|
114
|
+
return unpack(hit);
|
|
115
|
+
if (embedded && mode !== "server" && hash === embedded.hash)
|
|
116
|
+
return manifestHelp(embedded.manifest, target);
|
|
117
|
+
return undefined;
|
|
118
|
+
};
|
|
119
|
+
return {
|
|
120
|
+
get mode() {
|
|
121
|
+
return mode;
|
|
122
|
+
},
|
|
123
|
+
async help(target) {
|
|
124
|
+
const found = local(target);
|
|
125
|
+
if (found)
|
|
126
|
+
return found;
|
|
127
|
+
let fetched;
|
|
128
|
+
try {
|
|
129
|
+
fetched = await options.fetchHelp(target, loadTools);
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
// 오프라인: 남은 캐시 (수명 지남 · stale) → 내장 manifest. refetch 중이면 runner 가 원래 로컬 오류를 낸다
|
|
133
|
+
if (error instanceof RemoteTransportError && !refetched) {
|
|
134
|
+
const old = previous?.help[target];
|
|
135
|
+
if (old || embedded) {
|
|
136
|
+
if (!warned)
|
|
137
|
+
options.warn(`warning: ${error.message} Showing ${old ? "cached" : "built-in"} help.\n`);
|
|
138
|
+
warned = true;
|
|
139
|
+
return old ? unpack(old) : manifestHelp(embedded.manifest, target);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
144
|
+
if (fetched.hash !== undefined) {
|
|
145
|
+
if (hash === undefined)
|
|
146
|
+
hash = fetched.hash;
|
|
147
|
+
else if (fetched.hash !== hash) {
|
|
148
|
+
if (mode === "server") {
|
|
149
|
+
// 실행 중 서버 교체: 이전 응답 버림
|
|
150
|
+
help = {};
|
|
151
|
+
hash = fetched.hash;
|
|
152
|
+
}
|
|
153
|
+
else
|
|
154
|
+
stale = true;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
help[target] = fetched.value;
|
|
158
|
+
dirty = true;
|
|
159
|
+
return unpack(fetched.value);
|
|
160
|
+
},
|
|
161
|
+
refetch() {
|
|
162
|
+
if (mode === "server")
|
|
163
|
+
return false;
|
|
164
|
+
mode = "server";
|
|
165
|
+
refetched = true;
|
|
166
|
+
help = {};
|
|
167
|
+
hash = undefined;
|
|
168
|
+
return true;
|
|
169
|
+
},
|
|
170
|
+
tools: loadTools,
|
|
171
|
+
observe(observed) {
|
|
172
|
+
if (observed === undefined)
|
|
173
|
+
return;
|
|
174
|
+
if (hash === undefined) {
|
|
175
|
+
hash = observed;
|
|
176
|
+
dirty = true;
|
|
177
|
+
}
|
|
178
|
+
else if (observed !== hash) {
|
|
179
|
+
hash = observed;
|
|
180
|
+
stale = true;
|
|
181
|
+
dirty = true;
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
async save() {
|
|
185
|
+
if (!options.file || !dirty || !tools)
|
|
186
|
+
return;
|
|
187
|
+
const entry = {
|
|
188
|
+
format: SCHEMA_CACHE_FORMAT,
|
|
189
|
+
url: canonicalServerUrl(options.url),
|
|
190
|
+
client: options.client,
|
|
191
|
+
...(hash !== undefined ? { manifestHash: hash } : {}),
|
|
192
|
+
fetchedAt,
|
|
193
|
+
ttlMs,
|
|
194
|
+
...(stale ? { stale: true } : {}),
|
|
195
|
+
tools,
|
|
196
|
+
help,
|
|
197
|
+
};
|
|
198
|
+
await writeSchemaCache(options.file, entry).catch(() => { });
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
function unpack(cached) {
|
|
203
|
+
if ("help" in cached)
|
|
204
|
+
return cached.help;
|
|
205
|
+
const { code, message, ...details } = cached.error;
|
|
206
|
+
throw new MextError(code, message, details);
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type CliIo } from "../cli/io.ts";
|
|
2
|
+
import type { ClientManifest } from "./manifest.ts";
|
|
3
|
+
/**
|
|
4
|
+
* 고객 CLI 런타임 (§5). mext build 가 이 모듈 + 설정 (CustomerCliConfig) 을 .mext/cli/bin.js 하나로 번들한다.
|
|
5
|
+
* 번들 · 범용 형태가 같은 코드: manifest 가 있으면 help · 플래그 파싱을 내장 manifest 로, 없으면 서버 help 로.
|
|
6
|
+
* 명령: <bin> help · <bin> <ns> <cmd> [flags] · login · logout · mcp install · --version. 원격 실행 = mext run --url 과 같은 runner
|
|
7
|
+
*/
|
|
8
|
+
/** bin.js 에 인라인되는 설정 (mext build 가 생성) */
|
|
9
|
+
export interface CustomerCliConfig {
|
|
10
|
+
bin: string;
|
|
11
|
+
/** 빌드 설정의 서버 MCP 엔드포인트. 실행 시 <BIN>_URL 이 있으면 그 값 */
|
|
12
|
+
url: string;
|
|
13
|
+
/** --version · clientInfo.version */
|
|
14
|
+
version: string;
|
|
15
|
+
packageName: string;
|
|
16
|
+
/** 빌드한 @obov/mext 버전 */
|
|
17
|
+
mextVersion: string;
|
|
18
|
+
/** 빌드 시 manifestHash. 번들 형태 = 내장 manifest 의 해시 (서버 _meta["dev.mext/manifestHash"] 와 비교) */
|
|
19
|
+
manifestHash: string;
|
|
20
|
+
/** 번들 형태의 내장 manifest. 없음 = 범용 형태 */
|
|
21
|
+
manifest?: ClientManifest;
|
|
22
|
+
}
|
|
23
|
+
export declare function runCustomerCli(config: CustomerCliConfig, argv: readonly string[], partialIo?: Partial<CliIo>): Promise<number>;
|
|
24
|
+
/** 프로세스 진입점 (bin.js). 첫 SIGINT = 진행 중 요청 abort (exit 130), 두 번째 = 즉시 종료 */
|
|
25
|
+
export declare function main(config: CustomerCliConfig): Promise<void>;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { table } from "../cli/help.js";
|
|
2
|
+
import { resolveIo } from "../cli/io.js";
|
|
3
|
+
import { loginCommand } from "../cli/login.js";
|
|
4
|
+
import { logoutCommand } from "../cli/logout.js";
|
|
5
|
+
import { EXIT, formatJson } from "../cli/output.js";
|
|
6
|
+
import { mcpInstallText } from "../mcp/install.js";
|
|
7
|
+
import { envPrefix } from "../remote/credentials.js";
|
|
8
|
+
import { runRemote } from "./runner.js";
|
|
9
|
+
export async function runCustomerCli(config, argv, partialIo = {}) {
|
|
10
|
+
const io = resolveIo(partialIo);
|
|
11
|
+
const { bin } = config;
|
|
12
|
+
const prefix = envPrefix(bin);
|
|
13
|
+
const url = io.env[`${prefix}_URL`] || config.url;
|
|
14
|
+
if (!/^https?:\/\//i.test(url)) {
|
|
15
|
+
io.stderr.write(`error: ${prefix}_URL must be an http(s) URL (got "${url}")\n`);
|
|
16
|
+
return EXIT.usage;
|
|
17
|
+
}
|
|
18
|
+
const [first, ...rest] = argv;
|
|
19
|
+
switch (first) {
|
|
20
|
+
case "--version":
|
|
21
|
+
case "-v":
|
|
22
|
+
io.stdout.write(`${config.version}\n`);
|
|
23
|
+
return EXIT.ok;
|
|
24
|
+
case "login":
|
|
25
|
+
return loginCommand({ bin, url })(rest, io);
|
|
26
|
+
case "logout":
|
|
27
|
+
return logoutCommand({ bin, url })(rest, io);
|
|
28
|
+
case "mcp":
|
|
29
|
+
return mcp(config, url, rest, io);
|
|
30
|
+
case "__mext_inspect":
|
|
31
|
+
// 숨김: 지원 · 디버깅용 내장 설정 (토큰 없음)
|
|
32
|
+
io.stdout.write(formatJson({
|
|
33
|
+
bin,
|
|
34
|
+
url,
|
|
35
|
+
version: config.version,
|
|
36
|
+
packageName: config.packageName,
|
|
37
|
+
mextVersion: config.mextVersion,
|
|
38
|
+
manifestHash: config.manifestHash,
|
|
39
|
+
form: config.manifest ? "bundled" : "universal",
|
|
40
|
+
}));
|
|
41
|
+
return EXIT.ok;
|
|
42
|
+
}
|
|
43
|
+
return runRemote({
|
|
44
|
+
bin,
|
|
45
|
+
url,
|
|
46
|
+
prog: bin,
|
|
47
|
+
login: `${bin} login`,
|
|
48
|
+
version: config.version,
|
|
49
|
+
...(config.manifest ? { manifest: config.manifest, manifestHash: config.manifestHash } : {}),
|
|
50
|
+
rootHelpFooter: builtinHelp(config, url),
|
|
51
|
+
}, argv, io);
|
|
52
|
+
}
|
|
53
|
+
/** 프로세스 진입점 (bin.js). 첫 SIGINT = 진행 중 요청 abort (exit 130), 두 번째 = 즉시 종료 */
|
|
54
|
+
export async function main(config) {
|
|
55
|
+
const controller = new AbortController();
|
|
56
|
+
process.on("SIGINT", () => {
|
|
57
|
+
if (controller.signal.aborted)
|
|
58
|
+
process.exit(130);
|
|
59
|
+
controller.abort();
|
|
60
|
+
});
|
|
61
|
+
const code = await runCustomerCli(config, process.argv.slice(2), { signal: controller.signal });
|
|
62
|
+
process.stdout.write("", () => process.stderr.write("", () => process.exit(code)));
|
|
63
|
+
}
|
|
64
|
+
function mcp(config, url, argv, io) {
|
|
65
|
+
const [sub, ...rest] = argv;
|
|
66
|
+
const isHelp = (t) => t === "--help" || t === "-h";
|
|
67
|
+
const usage = `Usage:\n ${config.bin} mcp install Print MCP client registration commands (does not modify client config files)\n`;
|
|
68
|
+
if (sub !== undefined && (isHelp(sub) || (sub === "install" && rest.some(isHelp)))) {
|
|
69
|
+
io.stdout.write(usage);
|
|
70
|
+
return EXIT.ok;
|
|
71
|
+
}
|
|
72
|
+
if (sub === "install" && rest.length === 0) {
|
|
73
|
+
io.stdout.write(`${mcpInstallText({ name: config.bin, url, stdioCommand: false, auth: true })}\n`);
|
|
74
|
+
return EXIT.ok;
|
|
75
|
+
}
|
|
76
|
+
io.stderr.write(`error: ${sub === undefined ? "missing subcommand" : `unknown argument "${argv.join(" ")}"`}\n\n${usage}`);
|
|
77
|
+
return EXIT.usage;
|
|
78
|
+
}
|
|
79
|
+
/** 사람용 루트 help 뒤의 내장 명령 · 환경변수 */
|
|
80
|
+
function builtinHelp(config, url) {
|
|
81
|
+
const { bin } = config;
|
|
82
|
+
const prefix = envPrefix(bin);
|
|
83
|
+
return [
|
|
84
|
+
"CLI commands:",
|
|
85
|
+
...table([
|
|
86
|
+
["login", `Log in to ${url} (${bin} login --help)`],
|
|
87
|
+
["logout", "Revoke and remove the stored token"],
|
|
88
|
+
["mcp install", "Print MCP client registration commands"],
|
|
89
|
+
["--version", "Print the version"],
|
|
90
|
+
]).map((l) => ` ${l}`),
|
|
91
|
+
"",
|
|
92
|
+
"Environment:",
|
|
93
|
+
...table([
|
|
94
|
+
[`${prefix}_TOKEN`, `API token (instead of ${bin} login)`],
|
|
95
|
+
[`${prefix}_URL`, `Server URL (default: ${config.url})`],
|
|
96
|
+
]).map((l) => ` ${l}`),
|
|
97
|
+
"",
|
|
98
|
+
].join("\n");
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=main.js.map
|
|
@@ -0,0 +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 } 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\nexport async function runCustomerCli(\n config: CustomerCliConfig,\n argv: readonly string[],\n partialIo: Partial<CliIo> = {},\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 },\n argv,\n io,\n )\n}\n\n/** 프로세스 진입점 (bin.js). 첫 SIGINT = 진행 중 요청 abort (exit 130), 두 번째 = 즉시 종료 */\nexport async function main(config: CustomerCliConfig): 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 })\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"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Manifest, ManifestCommand, ManifestNamespace } from "../manifest.ts";
|
|
2
|
+
import type { Help } from "../mcp/help.ts";
|
|
3
|
+
/**
|
|
4
|
+
* 고객 CLI 번들 형태의 내장 manifest = 빌드 manifest 에서 서버 전용 항목 (file · module · 빌드 경로) 을 뺀 것.
|
|
5
|
+
* help 결과는 서버 help (mcp/help.ts help()) 와 같은 모양 (split 노출의 tool 필드 제외)
|
|
6
|
+
*/
|
|
7
|
+
export type ClientManifestCommand = Omit<ManifestCommand, "file">;
|
|
8
|
+
export interface ClientManifest {
|
|
9
|
+
/** commands/_index.md */
|
|
10
|
+
description?: string;
|
|
11
|
+
/** 루트 제외, ID 순 */
|
|
12
|
+
namespaces: ManifestNamespace[];
|
|
13
|
+
/** ID 순 */
|
|
14
|
+
commands: ClientManifestCommand[];
|
|
15
|
+
}
|
|
16
|
+
/** 빌드 manifest → 내장 manifest (mext build 가 호출) */
|
|
17
|
+
export declare function clientManifest(manifest: Pick<Manifest, "description" | "namespaces" | "commands">): ClientManifest;
|
|
18
|
+
/** 내장 manifest 의 help (target "" = 루트 · 네임스페이스 · 명령어 ID · 별칭). 없는 target = UNKNOWN_COMMAND */
|
|
19
|
+
export declare function manifestHelp(manifest: ClientManifest, target: string): Help;
|