@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.
Files changed (114) hide show
  1. package/dist/build.js +67 -4
  2. package/dist/build.js.map +1 -1
  3. package/dist/cli/ask-url.d.ts +16 -0
  4. package/dist/cli/ask-url.js +27 -0
  5. package/dist/cli/ask-url.js.map +1 -0
  6. package/dist/cli/build.js +7 -1
  7. package/dist/cli/build.js.map +1 -1
  8. package/dist/cli/dev-server.d.ts +7 -1
  9. package/dist/cli/dev-server.js +15 -2
  10. package/dist/cli/dev-server.js.map +1 -1
  11. package/dist/cli/dev.js +22 -7
  12. package/dist/cli/dev.js.map +1 -1
  13. package/dist/cli/login.d.ts +5 -0
  14. package/dist/cli/login.js +11 -7
  15. package/dist/cli/login.js.map +1 -1
  16. package/dist/cli/logout.js +4 -6
  17. package/dist/cli/logout.js.map +1 -1
  18. package/dist/cli/output.d.ts +1 -1
  19. package/dist/cli/output.js.map +1 -1
  20. package/dist/cli/run.js +7 -3
  21. package/dist/cli/run.js.map +1 -1
  22. package/dist/client/cache.d.ts +14 -4
  23. package/dist/client/cache.js +10 -3
  24. package/dist/client/cache.js.map +1 -1
  25. package/dist/client/main.js +11 -10
  26. package/dist/client/main.js.map +1 -1
  27. package/dist/client/manifest.d.ts +13 -1
  28. package/dist/client/manifest.js +43 -0
  29. package/dist/client/manifest.js.map +1 -1
  30. package/dist/client/runner.d.ts +3 -1
  31. package/dist/client/runner.js +80 -19
  32. package/dist/client/runner.js.map +1 -1
  33. package/dist/client/task.d.ts +47 -0
  34. package/dist/client/task.js +126 -0
  35. package/dist/client/task.js.map +1 -0
  36. package/dist/command.d.ts +30 -3
  37. package/dist/command.js +16 -0
  38. package/dist/command.js.map +1 -1
  39. package/dist/config.d.ts +40 -6
  40. package/dist/config.js +57 -8
  41. package/dist/config.js.map +1 -1
  42. package/dist/errors.d.ts +3 -1
  43. package/dist/errors.js.map +1 -1
  44. package/dist/index.d.ts +17 -5
  45. package/dist/index.js +9 -2
  46. package/dist/index.js.map +1 -1
  47. package/dist/instrumentation.d.ts +14 -2
  48. package/dist/instrumentation.js +12 -4
  49. package/dist/instrumentation.js.map +1 -1
  50. package/dist/invoke.d.ts +38 -0
  51. package/dist/invoke.js +72 -3
  52. package/dist/invoke.js.map +1 -1
  53. package/dist/local-bin.js +5 -3
  54. package/dist/local-bin.js.map +1 -1
  55. package/dist/manifest.d.ts +48 -3
  56. package/dist/manifest.js +14 -3
  57. package/dist/manifest.js.map +1 -1
  58. package/dist/mcp/constants.d.ts +4 -0
  59. package/dist/mcp/constants.js +4 -0
  60. package/dist/mcp/constants.js.map +1 -1
  61. package/dist/mcp/dispatch.d.ts +21 -7
  62. package/dist/mcp/dispatch.js +42 -7
  63. package/dist/mcp/dispatch.js.map +1 -1
  64. package/dist/mcp/http.d.ts +23 -5
  65. package/dist/mcp/http.js +64 -9
  66. package/dist/mcp/http.js.map +1 -1
  67. package/dist/mcp/index.d.ts +14 -6
  68. package/dist/mcp/index.js +7 -3
  69. package/dist/mcp/index.js.map +1 -1
  70. package/dist/mcp/mrtr.d.ts +40 -8
  71. package/dist/mcp/mrtr.js +32 -11
  72. package/dist/mcp/mrtr.js.map +1 -1
  73. package/dist/mcp/prompts.d.ts +25 -0
  74. package/dist/mcp/prompts.js +164 -0
  75. package/dist/mcp/prompts.js.map +1 -0
  76. package/dist/mcp/resources.d.ts +48 -0
  77. package/dist/mcp/resources.js +142 -0
  78. package/dist/mcp/resources.js.map +1 -0
  79. package/dist/mcp/server.d.ts +30 -5
  80. package/dist/mcp/server.js +143 -16
  81. package/dist/mcp/server.js.map +1 -1
  82. package/dist/mcp/stdio.d.ts +5 -0
  83. package/dist/mcp/stdio.js +16 -3
  84. package/dist/mcp/stdio.js.map +1 -1
  85. package/dist/mcp/subscriptions.d.ts +61 -0
  86. package/dist/mcp/subscriptions.js +188 -0
  87. package/dist/mcp/subscriptions.js.map +1 -0
  88. package/dist/mcp/tasks.d.ts +127 -0
  89. package/dist/mcp/tasks.js +448 -0
  90. package/dist/mcp/tasks.js.map +1 -0
  91. package/dist/module-files.d.ts +24 -0
  92. package/dist/module-files.js +97 -0
  93. package/dist/module-files.js.map +1 -0
  94. package/dist/prompt.d.ts +133 -0
  95. package/dist/prompt.js +222 -0
  96. package/dist/prompt.js.map +1 -0
  97. package/dist/registry.d.ts +6 -0
  98. package/dist/registry.js.map +1 -1
  99. package/dist/remote/client.d.ts +17 -1
  100. package/dist/remote/client.js +18 -2
  101. package/dist/remote/client.js.map +1 -1
  102. package/dist/resource.d.ts +169 -0
  103. package/dist/resource.js +301 -0
  104. package/dist/resource.js.map +1 -0
  105. package/dist/route.d.ts +71 -0
  106. package/dist/route.js +280 -0
  107. package/dist/route.js.map +1 -0
  108. package/dist/start.d.ts +14 -3
  109. package/dist/start.js +76 -11
  110. package/dist/start.js.map +1 -1
  111. package/dist/state.d.ts +38 -0
  112. package/dist/state.js +98 -0
  113. package/dist/state.js.map +1 -0
  114. package/package.json +1 -1
package/dist/cli/dev.js CHANGED
@@ -4,10 +4,12 @@ import { createServer, request as httpRequest } from "node:http";
4
4
  import { basename, dirname, extname, relative, resolve } from "node:path";
5
5
  import { Writable } from "node:stream";
6
6
  import { fileURLToPath } from "node:url";
7
- import { CONFIG_FILE, loadConfig, mcpStdioDeclarations, resolveCommandsDir, resolveLocalPrincipal } from "../config.js";
7
+ import { CONFIG_FILE, loadConfig, mcpStdioDeclarations, resolveCommandsDir, resolveLocalPrincipal, resolvePromptsDir, resolveResourcesDir, } from "../config.js";
8
8
  import { DEFAULT_HOST, DEFAULT_PORT, MCP_PATH } from "../mcp/constants.js";
9
9
  import { loadProjectInstrumentation } from "../instrumentation.js";
10
10
  import { redirectStdout, serveMcpStdio } from "../mcp/stdio.js";
11
+ import { loadPromptSet, withPrompts } from "../prompt.js";
12
+ import { loadResourceSet, withResources } from "../resource.js";
11
13
  import { loadRegistry } from "../scan.js";
12
14
  import { acquireDevLock, releaseDevLock, updateDevLock } from "./dev-lock.js";
13
15
  import { table } from "./help.js";
@@ -82,7 +84,7 @@ async function stdio(io) {
82
84
  try {
83
85
  const instrumentation = await loadProjectInstrumentation(io.cwd);
84
86
  const config = await loadConfig(io.cwd);
85
- const registry = await loadRegistry(resolveCommandsDir(io.cwd, config));
87
+ const registry = withPrompts(withResources(await loadRegistry(resolveCommandsDir(io.cwd, config)), await loadResourceSet(resolveResourcesDir(io.cwd, config))), await loadPromptSet(resolvePromptsDir(io.cwd, config)));
86
88
  const principal = await resolveLocalPrincipal(config);
87
89
  const server = serveMcpStdio({
88
90
  registry,
@@ -194,6 +196,8 @@ class DevSupervisor {
194
196
  /** 자식이 하나도 없을 때의 로드 오류 (요청에 구조화 오류로 응답) */
195
197
  loadError;
196
198
  commandsDir;
199
+ /** routes/ · resources/ · prompts/ (선택, §10 · §12.3 · §12.4). 없으면 생성 감지만 */
200
+ optionalDirs;
197
201
  bound;
198
202
  warnedServerChange = false;
199
203
  seq = 0;
@@ -206,6 +210,7 @@ class DevSupervisor {
206
210
  this.cwd = cwd;
207
211
  this.log = log;
208
212
  this.commandsDir = resolve(cwd, "commands");
213
+ this.optionalDirs = ["routes", "resources", "prompts"].map((name) => resolve(cwd, name));
209
214
  }
210
215
  /** 첫 자식 fork. 자식이 보고한 config.server (host · port) 반환. config 로드 실패 = undefined */
211
216
  start() {
@@ -293,8 +298,10 @@ class DevSupervisor {
293
298
  this.warnedServerChange = true;
294
299
  this.log("server.host / server.port changes in mext.config.ts apply after restarting mext dev");
295
300
  }
296
- if (message.commandsDir !== this.commandsDir) {
301
+ const optionalDirs = [message.routesDir, message.resourcesDir, message.promptsDir];
302
+ if (message.commandsDir !== this.commandsDir || optionalDirs.some((dir, i) => dir !== this.optionalDirs[i])) {
297
303
  this.commandsDir = message.commandsDir;
304
+ this.optionalDirs = optionalDirs;
298
305
  if (this.watchers.size > 0)
299
306
  this.watchFiles();
300
307
  }
@@ -315,6 +322,8 @@ class DevSupervisor {
315
322
  // commands/ 가 없던 상태에서 생겼으면 감시 시작
316
323
  if (this.watchers.size > 0 && !this.watchers.has(this.commandsDir))
317
324
  this.watchFiles();
325
+ else if (this.watchers.size > 0 && this.optionalDirs.some((dir) => !this.watchers.has(dir) && existsSync(dir)))
326
+ this.watchFiles();
318
327
  }
319
328
  onLoadFailed(child, message) {
320
329
  if (child !== this.pending)
@@ -333,12 +342,14 @@ class DevSupervisor {
333
342
  }
334
343
  this.flush();
335
344
  }
336
- /** 진행 중 요청이 끝나면 종료 */
345
+ /** 진행 중 요청이 끝나면 종료. subscriptions/listen 스트림은 끝나지 않으므로 자식이 완료 result 후 닫는다 (§12.5) */
337
346
  retire(child) {
338
347
  child.retiring = true;
339
348
  this.retired.add(child);
340
349
  if (child.inflight === 0)
341
350
  this.stop(child);
351
+ else if (child.proc.connected)
352
+ child.proc.send({ type: "retire" }, () => { });
342
353
  }
343
354
  stop(child) {
344
355
  if (child.proc.exitCode !== null || child.proc.signalCode !== null)
@@ -441,7 +452,7 @@ class DevSupervisor {
441
452
  });
442
453
  }
443
454
  /* -------------------------------------------------------------- 파일 감시 */
444
- /** commandsDir (recursive) + 프로젝트 루트 (mext.config.ts · instrumentation.ts · commandsDir 생성 · 삭제) */
455
+ /** commandsDir · routes · resources · prompts (recursive) + 프로젝트 루트 (mext.config.ts · instrumentation.ts · 폴더 생성 · 삭제) */
445
456
  watchFiles() {
446
457
  if (this.closing)
447
458
  return;
@@ -451,9 +462,13 @@ class DevSupervisor {
451
462
  const rootNames = new Set(DEV_WATCHED_ROOT_FILES);
452
463
  if (dirname(this.commandsDir) === this.cwd)
453
464
  rootNames.add(basename(this.commandsDir));
465
+ for (const dir of this.optionalDirs)
466
+ if (dirname(dir) === this.cwd)
467
+ rootNames.add(basename(dir));
454
468
  this.addWatcher(this.cwd, false, (name) => (rootNames.has(name) ? name : undefined));
455
- if (existsSync(this.commandsDir)) {
456
- this.addWatcher(this.commandsDir, true, (name) => relative(this.cwd, resolve(this.commandsDir, name)));
469
+ for (const dir of new Set([this.commandsDir, ...this.optionalDirs])) {
470
+ if (existsSync(dir))
471
+ this.addWatcher(dir, true, (name) => relative(this.cwd, resolve(dir, name)));
457
472
  }
458
473
  }
459
474
  addWatcher(dir, recursive, accept) {
@@ -1 +1 @@
1
- {"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/cli/dev.ts"],"names":[],"mappings":"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","sourcesContent":["import { fork, type ChildProcess } from \"node:child_process\"\nimport { existsSync, watch, type FSWatcher } from \"node:fs\"\nimport { createServer, request as httpRequest, type IncomingMessage, type Server, type ServerResponse } from \"node:http\"\nimport type { AddressInfo } from \"node:net\"\nimport { basename, dirname, extname, relative, resolve } from \"node:path\"\nimport { Writable } from \"node:stream\"\nimport { fileURLToPath } from \"node:url\"\nimport { CONFIG_FILE, loadConfig, mcpStdioDeclarations, resolveCommandsDir, resolveLocalPrincipal } from \"../config.ts\"\nimport { DEFAULT_HOST, DEFAULT_PORT, MCP_PATH } from \"../mcp/constants.ts\"\nimport { loadProjectInstrumentation } from \"../instrumentation.ts\"\nimport { redirectStdout, serveMcpStdio } from \"../mcp/stdio.ts\"\nimport { loadRegistry } from \"../scan.ts\"\nimport { acquireDevLock, releaseDevLock, updateDevLock, type DevLock } from \"./dev-lock.ts\"\nimport type { DevChildMessage, DevParentMessage } from \"./dev-server.ts\"\nimport { table } from \"./help.ts\"\nimport type { CliIo, CliWriter } from \"./io.ts\"\nimport { EXIT, exitCodeOf, formatError } from \"./output.ts\"\n\nexport const DEV_PROG = \"mext dev\"\n\n/** 감시 대상 프로젝트 루트 파일 (commandsDir/** 와 함께) */\nexport const DEV_WATCHED_ROOT_FILES: readonly string[] = [CONFIG_FILE, \"instrumentation.ts\"]\n\n/** 파일 변경 → 재시작 debounce (ms) */\nexport const DEV_DEBOUNCE_MS = 100\n\n/**\n * mext dev [--port <n>] [--host <h>] 개발 HTTP 서버. 감독 프로세스 + 서버 자식 (파일 변경 시 교체)\n * mext dev --stdio stdio 서버 (감시 없음, 같은 프로세스)\n */\nexport async function devCommand(argv: readonly string[], io: CliIo): Promise<number> {\n const parsed = parseDevArgs(argv)\n if (typeof parsed === \"string\") {\n io.stderr.write(`error: ${parsed}\\nRun \"${DEV_PROG} --help\" for usage.\\n`)\n return EXIT.usage\n }\n if (parsed.help) {\n io.stdout.write(devHelp())\n return EXIT.ok\n }\n if (parsed.stdio) return stdio(io)\n return supervise(parsed, io)\n}\n\ninterface DevArgs {\n help: boolean\n stdio: boolean\n port?: number\n host?: string\n}\n\n/** 반환 문자열 = 사용법 오류 메시지 */\nexport function parseDevArgs(argv: readonly string[]): DevArgs | string {\n const args: DevArgs = { help: false, stdio: false }\n for (let i = 0; i < argv.length; i++) {\n const tok = argv[i]!\n if (tok === \"--help\" || tok === \"-h\") {\n args.help = true\n continue\n }\n if (tok === \"--stdio\") {\n args.stdio = true\n continue\n }\n if (!tok.startsWith(\"--\")) return `unexpected argument \"${tok}\"`\n const eq = tok.indexOf(\"=\")\n const name = eq < 0 ? tok.slice(2) : tok.slice(2, eq)\n if (name !== \"port\" && name !== \"host\") return `unknown flag --${name}`\n const value = eq < 0 ? argv[++i] : tok.slice(eq + 1)\n if (value === undefined || value === \"\") return `--${name} requires a value`\n if (name === \"port\") {\n const port = Number(value)\n if (!Number.isInteger(port) || port < 0 || port > 65_535) return `--port must be an integer between 0 and 65535`\n args.port = port\n } else args.host = value\n }\n if (args.stdio && (args.port !== undefined || args.host !== undefined)) return \"--port and --host do not apply to --stdio\"\n return args\n}\n\n/* ---------------------------------------------------------------- stdio */\n\n/**\n * stdio: stdout = MCP 메시지만. D4: 이 프로세스의 그 외 stdout 쓰기 (console.log · process.stdout.write) 는\n * 명령어 import 전부터 종료까지 stderr 로 돌린다. stdin EOF = 연결 종료 → 바로 반환 (bin 이 exit).\n * 감시 · 잠금 없음: MCP 클라이언트가 프로세스를 소유 · 재실행한다\n */\nasync function stdio(io: CliIo): Promise<number> {\n const redirect = io.stdout === process.stdout ? redirectStdout() : undefined\n const wire = redirect?.wire ?? writerStream(io.stdout)\n try {\n const instrumentation = await loadProjectInstrumentation(io.cwd)\n const config = await loadConfig(io.cwd)\n const registry = await loadRegistry(resolveCommandsDir(io.cwd, config))\n const principal = await resolveLocalPrincipal(config)\n const server = serveMcpStdio({\n registry,\n instrumentation,\n principal,\n ...(config.app ? { app: config.app } : {}),\n ...(config.tools ? { tools: config.tools } : {}),\n ...mcpStdioDeclarations(config),\n stdin: io.stdin,\n stdout: wire,\n onerror: (error) => io.stderr.write(`mcp: ${error.message}\\n`),\n })\n const onAbort = (): void => void server.close()\n if (io.signal?.aborted) onAbort()\n io.signal?.addEventListener(\"abort\", onAbort, { once: true })\n // SIGTERM (MCP 클라이언트 종료) = close → cleanup 후 exit 0. 실제 프로세스 stdio 일 때만\n if (redirect) process.once(\"SIGTERM\", onAbort)\n await server.closed\n io.signal?.removeEventListener(\"abort\", onAbort)\n if (redirect) process.off(\"SIGTERM\", onAbort)\n return io.signal?.aborted ? EXIT.interrupted : EXIT.ok\n } catch (error) {\n io.stderr.write(formatError(error, DEV_PROG))\n return exitCodeOf(error)\n }\n // redirect 는 원복하지 않는다: 종료 중 남은 핸들러 출력도 stdout 에 섞이지 않게 (프로세스는 곧 exit)\n}\n\n/** 주입된 CliWriter (테스트) → transport 용 Writable */\nfunction writerStream(writer: CliWriter): Writable {\n return new Writable({\n write(chunk: Buffer | string, _encoding, callback) {\n writer.write(typeof chunk === \"string\" ? chunk : chunk.toString(\"utf8\"))\n callback()\n },\n })\n}\n\n/* ---------------------------------------------------------------- HTTP 감독 프로세스 */\n\n/**\n * 감독 프로세스 (이 프로세스) 는 사용자 코드를 import 하지 않는다. listen 소켓 · HTTP 연결을 쥐고\n * 요청마다 현재 서버 자식 (dev-server.ts, 127.0.0.1 임의 포트) 으로 중계한다.\n * 파일 변경 → 새 자식 fork → ready 후 전환, 이전 자식은 진행 중 요청이 끝나면 종료.\n * D2: 재시작 중 (새 자식 준비 전) 들어온 요청은 대기 후 새 자식이 처리. 새 자식 로드 실패 = 이전 자식이 처리\n */\nasync function supervise(args: DevArgs, io: CliIo): Promise<number> {\n const cwd = resolve(io.cwd)\n const log = (line: string): void => void io.stderr.write(`${DEV_PROG}: ${line}\\n`)\n\n let lock: DevLock\n try {\n const got = acquireDevLock(cwd)\n if (\"running\" in got) {\n const where = got.running.url ? `at ${got.running.url}` : \"(starting)\"\n io.stderr.write(\n `error: ${DEV_PROG} is already running ${where} (PID ${got.running.pid}).\\n` +\n \"Stop it first, or connect to that server.\\n\",\n )\n return EXIT.error\n }\n lock = got.acquired\n } catch (error) {\n io.stderr.write(formatError(error, DEV_PROG))\n return EXIT.error\n }\n const onExit = (): void => releaseDevLock(cwd)\n process.on(\"exit\", onExit)\n\n const supervisor = new DevSupervisor(cwd, log)\n try {\n const first = await supervisor.start()\n const host = args.host ?? first?.host ?? DEFAULT_HOST\n const port = args.port ?? first?.port ?? DEFAULT_PORT\n const url = await supervisor.listen(host, port)\n lock = { ...lock, url }\n updateDevLock(cwd, lock)\n io.stderr.write(`MCP dev server (Streamable HTTP) listening on ${url}\\n`)\n supervisor.watchFiles()\n // SIGINT (io.signal) 까지 실행\n await new Promise<void>((done) => {\n if (io.signal?.aborted) return done()\n io.signal?.addEventListener(\"abort\", () => done(), { once: true })\n })\n return EXIT.ok\n } catch (error) {\n io.stderr.write(formatError(error, DEV_PROG))\n return exitCodeOf(error)\n } finally {\n await supervisor.close()\n releaseDevLock(cwd)\n process.off(\"exit\", onExit)\n }\n}\n\ninterface ServerChild {\n seq: number\n proc: ChildProcess\n /** ready 후 자식의 127.0.0.1 포트 */\n port?: number\n inflight: number\n retiring: boolean\n startedAt: number\n}\n\n/** 자식 엔트리. tsc 빌드 (.js) · 원본 (.ts) 모두 이 모듈과 같은 확장자 */\nconst CHILD_ENTRY = fileURLToPath(new URL(`./dev-server${extname(fileURLToPath(import.meta.url))}`, import.meta.url))\n\n/** 요청 · 응답에서 중계하지 않는 hop-by-hop 헤더 */\nconst HOP_HEADERS = new Set([\"connection\", \"keep-alive\", \"proxy-connection\", \"upgrade\", \"te\", \"trailer\"])\n\nclass DevSupervisor {\n private readonly cwd: string\n private readonly log: (line: string) => void\n private server: Server | undefined\n private current: ServerChild | undefined\n private pending: ServerChild | undefined\n private readonly retired = new Set<ServerChild>()\n /** 새 자식 준비 전까지 대기 중인 요청 (D2) */\n private queue: (() => void)[] = []\n /** 자식이 하나도 없을 때의 로드 오류 (요청에 구조화 오류로 응답) */\n private loadError: string | undefined\n private commandsDir: string\n private bound: { host: string; port: number } | undefined\n private warnedServerChange = false\n private seq = 0\n private closing = false\n private watchers = new Map<string, FSWatcher>()\n private debounce: NodeJS.Timeout | undefined\n private changed = new Set<string>()\n private firstConfig: ((server: { host?: string; port?: number } | undefined) => void) | undefined\n\n constructor(cwd: string, log: (line: string) => void) {\n this.cwd = cwd\n this.log = log\n this.commandsDir = resolve(cwd, \"commands\")\n }\n\n /** 첫 자식 fork. 자식이 보고한 config.server (host · port) 반환. config 로드 실패 = undefined */\n start(): Promise<{ host?: string; port?: number } | undefined> {\n return new Promise((done) => {\n this.firstConfig = done\n this.spawn()\n })\n }\n\n async listen(host: string, port: number): Promise<string> {\n const server = createServer((req, res) => this.dispatch(req, res))\n this.server = server\n await new Promise<void>((done, reject) => {\n server.once(\"error\", reject)\n server.listen(port, host, () => {\n server.off(\"error\", reject)\n done()\n })\n })\n const address = server.address() as AddressInfo\n this.bound = { host, port }\n const shown = host.includes(\":\") && !host.startsWith(\"[\") ? `[${host}]` : host\n return `http://${shown}:${address.port}${MCP_PATH}`\n }\n\n /* -------------------------------------------------------------- 자식 수명 */\n\n private spawn(): void {\n if (this.closing) return\n if (this.pending) this.stop(this.pending)\n const child: ServerChild = {\n seq: ++this.seq,\n proc: fork(CHILD_ENTRY, [], {\n cwd: this.cwd,\n // node --test 의 실행 옵션은 자식에 넘기지 않는다 (--conditions 등은 유지)\n execArgv: process.execArgv.filter((a) => !a.startsWith(\"--test\")),\n stdio: [\"ignore\", \"inherit\", \"inherit\", \"ipc\"],\n }),\n inflight: 0,\n retiring: false,\n startedAt: Date.now(),\n }\n this.pending = child\n let failed = false\n child.proc.on(\"message\", (message: DevChildMessage) => {\n if (message.type === \"config\") this.onConfig(child, message)\n else if (message.type === \"ready\") this.onReady(child, message.port, message.commands)\n else if (message.type === \"error\") {\n failed = true\n this.onLoadFailed(child, message.message)\n }\n })\n child.proc.on(\"error\", (error) => {\n if (!failed) this.onLoadFailed(child, error.message)\n failed = true\n })\n child.proc.on(\"exit\", (code, signal) => {\n this.retired.delete(child)\n if (this.pending === child && !failed) {\n failed = true\n this.onLoadFailed(child, `server process exited (${signal ?? `code ${code}`}) before it was ready`)\n } else if (this.current === child) {\n this.current = undefined\n if (this.closing) return\n this.log(`server process exited unexpectedly (${signal ?? `code ${code}`}); restarting`)\n this.spawn()\n }\n })\n }\n\n private onConfig(child: ServerChild, message: Extract<DevChildMessage, { type: \"config\" }>): void {\n if (child !== this.pending) return\n if (this.firstConfig) {\n this.firstConfig(message.server)\n this.firstConfig = undefined\n } else if (\n this.bound &&\n !this.warnedServerChange &&\n ((message.server.host !== undefined && message.server.host !== this.bound.host) ||\n (message.server.port !== undefined && message.server.port !== this.bound.port))\n ) {\n this.warnedServerChange = true\n this.log(\"server.host / server.port changes in mext.config.ts apply after restarting mext dev\")\n }\n if (message.commandsDir !== this.commandsDir) {\n this.commandsDir = message.commandsDir\n if (this.watchers.size > 0) this.watchFiles()\n }\n }\n\n private onReady(child: ServerChild, port: number, commands: number): void {\n if (child !== this.pending) return\n const previous = this.current\n child.port = port\n this.pending = undefined\n this.current = child\n this.loadError = undefined\n const ms = Date.now() - child.startedAt\n this.log(`${previous ? \"reloaded\" : \"ready\"} (${commands} command${commands === 1 ? \"\" : \"s\"}, ${ms}ms)`)\n if (previous) this.retire(previous)\n this.flush()\n // commands/ 가 없던 상태에서 생겼으면 감시 시작\n if (this.watchers.size > 0 && !this.watchers.has(this.commandsDir)) this.watchFiles()\n }\n\n private onLoadFailed(child: ServerChild, message: string): void {\n if (child !== this.pending) return\n this.pending = undefined\n if (this.firstConfig) {\n this.firstConfig(undefined)\n this.firstConfig = undefined\n }\n if (this.current) {\n this.log(`reload failed; still serving the previous version. Fix the error and save to retry.\\n${indent(message)}`)\n } else {\n this.loadError = message\n this.log(`load failed; requests return an error until the next change.\\n${indent(message)}`)\n }\n this.flush()\n }\n\n /** 진행 중 요청이 끝나면 종료 */\n private retire(child: ServerChild): void {\n child.retiring = true\n this.retired.add(child)\n if (child.inflight === 0) this.stop(child)\n }\n\n private stop(child: ServerChild): void {\n if (child.proc.exitCode !== null || child.proc.signalCode !== null) return\n // 준비 전 (로드 중) 자식은 shutdown 메시지를 처리하지 않는다\n if (child.port !== undefined && child.proc.connected) {\n child.proc.send({ type: \"shutdown\" } satisfies DevParentMessage, () => {})\n } else child.proc.kill(\"SIGTERM\")\n setTimeout(() => {\n if (child.proc.exitCode === null && child.proc.signalCode === null) child.proc.kill(\"SIGKILL\")\n }, 3_000).unref()\n }\n\n /* -------------------------------------------------------------- 요청 중계 */\n\n private dispatch(req: IncomingMessage, res: ServerResponse): void {\n if (this.pending) {\n this.queue.push(() => this.dispatch(req, res))\n return\n }\n const child = this.current\n if (child?.port !== undefined) return this.proxy(child, req, res)\n this.sendUnavailable(req, res, this.loadError ?? \"the server process is not running\")\n }\n\n private flush(): void {\n const queued = this.queue\n this.queue = []\n for (const run of queued) run()\n }\n\n private proxy(child: ServerChild, req: IncomingMessage, res: ServerResponse): void {\n // 대기 중 클라이언트가 끊은 요청\n if (res.destroyed || req.destroyed) return\n child.inflight++\n let finished = false\n const done = (): void => {\n if (finished) return\n finished = true\n child.inflight--\n if (child.retiring && child.inflight === 0) this.stop(child)\n }\n const headers: Record<string, string | string[]> = {}\n for (const [name, value] of Object.entries(req.headers)) {\n if (value !== undefined && !HOP_HEADERS.has(name)) headers[name] = value\n }\n const upstream = httpRequest({\n host: \"127.0.0.1\",\n port: child.port,\n method: req.method,\n path: req.url,\n headers,\n agent: false,\n })\n upstream.on(\"response\", (up) => {\n const out: Record<string, string | string[]> = {}\n for (const [name, value] of Object.entries(up.headers)) {\n if (value !== undefined && !HOP_HEADERS.has(name)) out[name] = value\n }\n res.writeHead(up.statusCode ?? 502, out)\n res.flushHeaders()\n up.pipe(res)\n up.on(\"error\", () => res.destroy())\n up.on(\"aborted\", () => res.destroy())\n })\n upstream.on(\"error\", (error) => {\n if (res.headersSent) res.destroy()\n else if (!res.destroyed) {\n sendJson(res, 502, rpcError(-32_603, `mext dev: server process did not respond (${error.message}).`))\n }\n done()\n })\n // 클라이언트 연결 종료 (SSE 취소 포함) = 자식으로의 요청도 닫아 ctx.signal abort\n res.on(\"close\", () => {\n if (!res.writableFinished) upstream.destroy()\n done()\n })\n req.pipe(upstream)\n }\n\n /** 자식 없음 (로드 실패) = 503 + JSON-RPC 오류. MCP 엔드포인트 외 경로도 같은 응답 */\n private sendUnavailable(req: IncomingMessage, res: ServerResponse, message: string): void {\n const chunks: Buffer[] = []\n let size = 0\n req.on(\"data\", (chunk: Buffer) => {\n size += chunk.length\n if (size <= 1024 * 1024) chunks.push(chunk)\n })\n req.on(\"end\", () => {\n const text =\n \"mext dev: the project failed to load. Fix the error and save; the server reloads automatically.\\n\" + message\n sendJson(res, 503, rpcError(-32_603, text, { loadError: message }, requestId(Buffer.concat(chunks))))\n })\n }\n\n /* -------------------------------------------------------------- 파일 감시 */\n\n /** commandsDir (recursive) + 프로젝트 루트 (mext.config.ts · instrumentation.ts · commandsDir 생성 · 삭제) */\n watchFiles(): void {\n if (this.closing) return\n for (const w of this.watchers.values()) w.close()\n this.watchers.clear()\n const rootNames = new Set(DEV_WATCHED_ROOT_FILES)\n if (dirname(this.commandsDir) === this.cwd) rootNames.add(basename(this.commandsDir))\n this.addWatcher(this.cwd, false, (name) => (rootNames.has(name) ? name : undefined))\n if (existsSync(this.commandsDir)) {\n this.addWatcher(this.commandsDir, true, (name) => relative(this.cwd, resolve(this.commandsDir, name)))\n }\n }\n\n private addWatcher(dir: string, recursive: boolean, accept: (name: string) => string | undefined): void {\n try {\n const watcher = watch(dir, { recursive, persistent: false }, (_event, filename) => {\n const name = filename === null ? undefined : accept(filename.toString())\n if (name !== undefined) this.schedule(name)\n })\n watcher.on(\"error\", (error) => {\n this.log(`file watching stopped for ${relative(this.cwd, dir) || \".\"} (${error.message})`)\n watcher.close()\n this.watchers.delete(dir)\n })\n this.watchers.set(dir, watcher)\n } catch (error) {\n // R3: Linux inotify 한도 (ENOSPC) 등. 서버는 계속, 재시작은 수동\n this.log(`cannot watch ${relative(this.cwd, dir) || \".\"} (${(error as Error).message}); restart mext dev after changes`)\n }\n }\n\n private schedule(name: string): void {\n if (this.closing) return\n this.changed.add(name)\n clearTimeout(this.debounce)\n this.debounce = setTimeout(() => {\n const names = [...this.changed]\n this.changed.clear()\n const shown = names.slice(0, 3).join(\", \") + (names.length > 3 ? `, +${names.length - 3} more` : \"\")\n this.log(`change detected (${shown}); reloading`)\n this.spawn()\n }, DEV_DEBOUNCE_MS)\n }\n\n /* -------------------------------------------------------------- 종료 */\n\n async close(): Promise<void> {\n this.closing = true\n clearTimeout(this.debounce)\n for (const w of this.watchers.values()) w.close()\n this.watchers.clear()\n const children = [this.current, this.pending, ...this.retired].filter((c): c is ServerChild => c !== undefined)\n const exited = children.map(\n (c) =>\n new Promise<void>((done) => {\n if (c.proc.exitCode !== null || c.proc.signalCode !== null) return done()\n c.proc.once(\"exit\", () => done())\n this.stop(c)\n }),\n )\n if (this.server) {\n const server = this.server\n server.closeAllConnections()\n await new Promise<void>((done) => server.close(() => done()))\n }\n this.flush()\n await Promise.all(exited)\n }\n}\n\nfunction indent(text: string): string {\n return text\n .split(\"\\n\")\n .map((l) => ` ${l}`)\n .join(\"\\n\")\n}\n\nfunction sendJson(res: ServerResponse, status: number, body: unknown): void {\n if (res.headersSent || res.destroyed) return\n const text = JSON.stringify(body)\n res.writeHead(status, { \"Content-Type\": \"application/json\", \"Content-Length\": Buffer.byteLength(text) })\n res.end(text)\n}\n\nfunction rpcError(code: number, message: string, data?: unknown, id: string | number | null = null) {\n return { jsonrpc: \"2.0\", id, error: data === undefined ? { code, message } : { code, message, data } }\n}\n\nfunction requestId(body: Buffer): string | number | null {\n try {\n const { id } = JSON.parse(body.toString(\"utf8\")) as { id?: unknown }\n return typeof id === \"string\" || typeof id === \"number\" ? id : null\n } catch {\n return null\n }\n}\n\nexport function devHelp(): string {\n const lines = [\n \"Run the development MCP server (MCP 2026-07-28). Reloads on file changes.\",\n \"\",\n \"Usage:\",\n ` ${DEV_PROG} [--port <n>] [--host <host>]`,\n ` ${DEV_PROG} --stdio`,\n \"\",\n \"Modes:\",\n ...table([\n [\n DEV_PROG,\n `Streamable HTTP at POST http://${DEFAULT_HOST}:${DEFAULT_PORT}${MCP_PATH} (mext.config.ts: app · auth · tools · server · oauth)`,\n ],\n [\"\", `Watches commands/, ${DEV_WATCHED_ROOT_FILES.join(\", \")} and restarts the server process; the port stays open`],\n [`${DEV_PROG} --stdio`, \"stdio (line-delimited JSON-RPC). Local principal; other stdout output goes to stderr. No watching\"],\n ]).map((l) => ` ${l}`),\n \"\",\n \"Flags:\",\n ...table([\n [\"--port <n>\", `HTTP port (default server.port or ${DEFAULT_PORT}; 0 = any free port)`],\n [\"--host <host>\", `HTTP bind address (default server.host or ${DEFAULT_HOST})`],\n [\"--stdio\", \"Serve over stdin/stdout instead of HTTP\"],\n [\"-h, --help\", \"Show help\"],\n ]).map((l) => ` ${l}`),\n \"\",\n \"One HTTP dev server per project: .mext/dev/lock records { pid, url, startedAt } (add .mext/ to .gitignore).\",\n 'Register with an MCP client: \"mext mcp install\".',\n ]\n return `${lines.join(\"\\n\")}\\n`\n}\n"]}
1
+ {"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/cli/dev.ts"],"names":[],"mappings":"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","sourcesContent":["import { fork, type ChildProcess } from \"node:child_process\"\nimport { existsSync, watch, type FSWatcher } from \"node:fs\"\nimport { createServer, request as httpRequest, type IncomingMessage, type Server, type ServerResponse } from \"node:http\"\nimport type { AddressInfo } from \"node:net\"\nimport { basename, dirname, extname, relative, resolve } from \"node:path\"\nimport { Writable } from \"node:stream\"\nimport { fileURLToPath } from \"node:url\"\nimport {\n CONFIG_FILE,\n loadConfig,\n mcpStdioDeclarations,\n resolveCommandsDir,\n resolveLocalPrincipal,\n resolvePromptsDir,\n resolveResourcesDir,\n} from \"../config.ts\"\nimport { DEFAULT_HOST, DEFAULT_PORT, MCP_PATH } from \"../mcp/constants.ts\"\nimport { loadProjectInstrumentation } from \"../instrumentation.ts\"\nimport { redirectStdout, serveMcpStdio } from \"../mcp/stdio.ts\"\nimport { loadPromptSet, withPrompts } from \"../prompt.ts\"\nimport { loadResourceSet, withResources } from \"../resource.ts\"\nimport { loadRegistry } from \"../scan.ts\"\nimport { acquireDevLock, releaseDevLock, updateDevLock, type DevLock } from \"./dev-lock.ts\"\nimport type { DevChildMessage, DevParentMessage } from \"./dev-server.ts\"\nimport { table } from \"./help.ts\"\nimport type { CliIo, CliWriter } from \"./io.ts\"\nimport { EXIT, exitCodeOf, formatError } from \"./output.ts\"\n\nexport const DEV_PROG = \"mext dev\"\n\n/** 감시 대상 프로젝트 루트 파일 (commandsDir/** 와 함께) */\nexport const DEV_WATCHED_ROOT_FILES: readonly string[] = [CONFIG_FILE, \"instrumentation.ts\"]\n\n/** 파일 변경 → 재시작 debounce (ms) */\nexport const DEV_DEBOUNCE_MS = 100\n\n/**\n * mext dev [--port <n>] [--host <h>] 개발 HTTP 서버. 감독 프로세스 + 서버 자식 (파일 변경 시 교체)\n * mext dev --stdio stdio 서버 (감시 없음, 같은 프로세스)\n */\nexport async function devCommand(argv: readonly string[], io: CliIo): Promise<number> {\n const parsed = parseDevArgs(argv)\n if (typeof parsed === \"string\") {\n io.stderr.write(`error: ${parsed}\\nRun \"${DEV_PROG} --help\" for usage.\\n`)\n return EXIT.usage\n }\n if (parsed.help) {\n io.stdout.write(devHelp())\n return EXIT.ok\n }\n if (parsed.stdio) return stdio(io)\n return supervise(parsed, io)\n}\n\ninterface DevArgs {\n help: boolean\n stdio: boolean\n port?: number\n host?: string\n}\n\n/** 반환 문자열 = 사용법 오류 메시지 */\nexport function parseDevArgs(argv: readonly string[]): DevArgs | string {\n const args: DevArgs = { help: false, stdio: false }\n for (let i = 0; i < argv.length; i++) {\n const tok = argv[i]!\n if (tok === \"--help\" || tok === \"-h\") {\n args.help = true\n continue\n }\n if (tok === \"--stdio\") {\n args.stdio = true\n continue\n }\n if (!tok.startsWith(\"--\")) return `unexpected argument \"${tok}\"`\n const eq = tok.indexOf(\"=\")\n const name = eq < 0 ? tok.slice(2) : tok.slice(2, eq)\n if (name !== \"port\" && name !== \"host\") return `unknown flag --${name}`\n const value = eq < 0 ? argv[++i] : tok.slice(eq + 1)\n if (value === undefined || value === \"\") return `--${name} requires a value`\n if (name === \"port\") {\n const port = Number(value)\n if (!Number.isInteger(port) || port < 0 || port > 65_535) return `--port must be an integer between 0 and 65535`\n args.port = port\n } else args.host = value\n }\n if (args.stdio && (args.port !== undefined || args.host !== undefined)) return \"--port and --host do not apply to --stdio\"\n return args\n}\n\n/* ---------------------------------------------------------------- stdio */\n\n/**\n * stdio: stdout = MCP 메시지만. D4: 이 프로세스의 그 외 stdout 쓰기 (console.log · process.stdout.write) 는\n * 명령어 import 전부터 종료까지 stderr 로 돌린다. stdin EOF = 연결 종료 → 바로 반환 (bin 이 exit).\n * 감시 · 잠금 없음: MCP 클라이언트가 프로세스를 소유 · 재실행한다\n */\nasync function stdio(io: CliIo): Promise<number> {\n const redirect = io.stdout === process.stdout ? redirectStdout() : undefined\n const wire = redirect?.wire ?? writerStream(io.stdout)\n try {\n const instrumentation = await loadProjectInstrumentation(io.cwd)\n const config = await loadConfig(io.cwd)\n const registry = withPrompts(\n withResources(await loadRegistry(resolveCommandsDir(io.cwd, config)), await loadResourceSet(resolveResourcesDir(io.cwd, config))),\n await loadPromptSet(resolvePromptsDir(io.cwd, config)),\n )\n const principal = await resolveLocalPrincipal(config)\n const server = serveMcpStdio({\n registry,\n instrumentation,\n principal,\n ...(config.app ? { app: config.app } : {}),\n ...(config.tools ? { tools: config.tools } : {}),\n ...mcpStdioDeclarations(config),\n stdin: io.stdin,\n stdout: wire,\n onerror: (error) => io.stderr.write(`mcp: ${error.message}\\n`),\n })\n const onAbort = (): void => void server.close()\n if (io.signal?.aborted) onAbort()\n io.signal?.addEventListener(\"abort\", onAbort, { once: true })\n // SIGTERM (MCP 클라이언트 종료) = close → cleanup 후 exit 0. 실제 프로세스 stdio 일 때만\n if (redirect) process.once(\"SIGTERM\", onAbort)\n await server.closed\n io.signal?.removeEventListener(\"abort\", onAbort)\n if (redirect) process.off(\"SIGTERM\", onAbort)\n return io.signal?.aborted ? EXIT.interrupted : EXIT.ok\n } catch (error) {\n io.stderr.write(formatError(error, DEV_PROG))\n return exitCodeOf(error)\n }\n // redirect 는 원복하지 않는다: 종료 중 남은 핸들러 출력도 stdout 에 섞이지 않게 (프로세스는 곧 exit)\n}\n\n/** 주입된 CliWriter (테스트) → transport 용 Writable */\nfunction writerStream(writer: CliWriter): Writable {\n return new Writable({\n write(chunk: Buffer | string, _encoding, callback) {\n writer.write(typeof chunk === \"string\" ? chunk : chunk.toString(\"utf8\"))\n callback()\n },\n })\n}\n\n/* ---------------------------------------------------------------- HTTP 감독 프로세스 */\n\n/**\n * 감독 프로세스 (이 프로세스) 는 사용자 코드를 import 하지 않는다. listen 소켓 · HTTP 연결을 쥐고\n * 요청마다 현재 서버 자식 (dev-server.ts, 127.0.0.1 임의 포트) 으로 중계한다.\n * 파일 변경 → 새 자식 fork → ready 후 전환, 이전 자식은 진행 중 요청이 끝나면 종료.\n * D2: 재시작 중 (새 자식 준비 전) 들어온 요청은 대기 후 새 자식이 처리. 새 자식 로드 실패 = 이전 자식이 처리\n */\nasync function supervise(args: DevArgs, io: CliIo): Promise<number> {\n const cwd = resolve(io.cwd)\n const log = (line: string): void => void io.stderr.write(`${DEV_PROG}: ${line}\\n`)\n\n let lock: DevLock\n try {\n const got = acquireDevLock(cwd)\n if (\"running\" in got) {\n const where = got.running.url ? `at ${got.running.url}` : \"(starting)\"\n io.stderr.write(\n `error: ${DEV_PROG} is already running ${where} (PID ${got.running.pid}).\\n` +\n \"Stop it first, or connect to that server.\\n\",\n )\n return EXIT.error\n }\n lock = got.acquired\n } catch (error) {\n io.stderr.write(formatError(error, DEV_PROG))\n return EXIT.error\n }\n const onExit = (): void => releaseDevLock(cwd)\n process.on(\"exit\", onExit)\n\n const supervisor = new DevSupervisor(cwd, log)\n try {\n const first = await supervisor.start()\n const host = args.host ?? first?.host ?? DEFAULT_HOST\n const port = args.port ?? first?.port ?? DEFAULT_PORT\n const url = await supervisor.listen(host, port)\n lock = { ...lock, url }\n updateDevLock(cwd, lock)\n io.stderr.write(`MCP dev server (Streamable HTTP) listening on ${url}\\n`)\n supervisor.watchFiles()\n // SIGINT (io.signal) 까지 실행\n await new Promise<void>((done) => {\n if (io.signal?.aborted) return done()\n io.signal?.addEventListener(\"abort\", () => done(), { once: true })\n })\n return EXIT.ok\n } catch (error) {\n io.stderr.write(formatError(error, DEV_PROG))\n return exitCodeOf(error)\n } finally {\n await supervisor.close()\n releaseDevLock(cwd)\n process.off(\"exit\", onExit)\n }\n}\n\ninterface ServerChild {\n seq: number\n proc: ChildProcess\n /** ready 후 자식의 127.0.0.1 포트 */\n port?: number\n inflight: number\n retiring: boolean\n startedAt: number\n}\n\n/** 자식 엔트리. tsc 빌드 (.js) · 원본 (.ts) 모두 이 모듈과 같은 확장자 */\nconst CHILD_ENTRY = fileURLToPath(new URL(`./dev-server${extname(fileURLToPath(import.meta.url))}`, import.meta.url))\n\n/** 요청 · 응답에서 중계하지 않는 hop-by-hop 헤더 */\nconst HOP_HEADERS = new Set([\"connection\", \"keep-alive\", \"proxy-connection\", \"upgrade\", \"te\", \"trailer\"])\n\nclass DevSupervisor {\n private readonly cwd: string\n private readonly log: (line: string) => void\n private server: Server | undefined\n private current: ServerChild | undefined\n private pending: ServerChild | undefined\n private readonly retired = new Set<ServerChild>()\n /** 새 자식 준비 전까지 대기 중인 요청 (D2) */\n private queue: (() => void)[] = []\n /** 자식이 하나도 없을 때의 로드 오류 (요청에 구조화 오류로 응답) */\n private loadError: string | undefined\n private commandsDir: string\n /** routes/ · resources/ · prompts/ (선택, §10 · §12.3 · §12.4). 없으면 생성 감지만 */\n private optionalDirs: readonly string[]\n private bound: { host: string; port: number } | undefined\n private warnedServerChange = false\n private seq = 0\n private closing = false\n private watchers = new Map<string, FSWatcher>()\n private debounce: NodeJS.Timeout | undefined\n private changed = new Set<string>()\n private firstConfig: ((server: { host?: string; port?: number } | undefined) => void) | undefined\n\n constructor(cwd: string, log: (line: string) => void) {\n this.cwd = cwd\n this.log = log\n this.commandsDir = resolve(cwd, \"commands\")\n this.optionalDirs = [\"routes\", \"resources\", \"prompts\"].map((name) => resolve(cwd, name))\n }\n\n /** 첫 자식 fork. 자식이 보고한 config.server (host · port) 반환. config 로드 실패 = undefined */\n start(): Promise<{ host?: string; port?: number } | undefined> {\n return new Promise((done) => {\n this.firstConfig = done\n this.spawn()\n })\n }\n\n async listen(host: string, port: number): Promise<string> {\n const server = createServer((req, res) => this.dispatch(req, res))\n this.server = server\n await new Promise<void>((done, reject) => {\n server.once(\"error\", reject)\n server.listen(port, host, () => {\n server.off(\"error\", reject)\n done()\n })\n })\n const address = server.address() as AddressInfo\n this.bound = { host, port }\n const shown = host.includes(\":\") && !host.startsWith(\"[\") ? `[${host}]` : host\n return `http://${shown}:${address.port}${MCP_PATH}`\n }\n\n /* -------------------------------------------------------------- 자식 수명 */\n\n private spawn(): void {\n if (this.closing) return\n if (this.pending) this.stop(this.pending)\n const child: ServerChild = {\n seq: ++this.seq,\n proc: fork(CHILD_ENTRY, [], {\n cwd: this.cwd,\n // node --test 의 실행 옵션은 자식에 넘기지 않는다 (--conditions 등은 유지)\n execArgv: process.execArgv.filter((a) => !a.startsWith(\"--test\")),\n stdio: [\"ignore\", \"inherit\", \"inherit\", \"ipc\"],\n }),\n inflight: 0,\n retiring: false,\n startedAt: Date.now(),\n }\n this.pending = child\n let failed = false\n child.proc.on(\"message\", (message: DevChildMessage) => {\n if (message.type === \"config\") this.onConfig(child, message)\n else if (message.type === \"ready\") this.onReady(child, message.port, message.commands)\n else if (message.type === \"error\") {\n failed = true\n this.onLoadFailed(child, message.message)\n }\n })\n child.proc.on(\"error\", (error) => {\n if (!failed) this.onLoadFailed(child, error.message)\n failed = true\n })\n child.proc.on(\"exit\", (code, signal) => {\n this.retired.delete(child)\n if (this.pending === child && !failed) {\n failed = true\n this.onLoadFailed(child, `server process exited (${signal ?? `code ${code}`}) before it was ready`)\n } else if (this.current === child) {\n this.current = undefined\n if (this.closing) return\n this.log(`server process exited unexpectedly (${signal ?? `code ${code}`}); restarting`)\n this.spawn()\n }\n })\n }\n\n private onConfig(child: ServerChild, message: Extract<DevChildMessage, { type: \"config\" }>): void {\n if (child !== this.pending) return\n if (this.firstConfig) {\n this.firstConfig(message.server)\n this.firstConfig = undefined\n } else if (\n this.bound &&\n !this.warnedServerChange &&\n ((message.server.host !== undefined && message.server.host !== this.bound.host) ||\n (message.server.port !== undefined && message.server.port !== this.bound.port))\n ) {\n this.warnedServerChange = true\n this.log(\"server.host / server.port changes in mext.config.ts apply after restarting mext dev\")\n }\n const optionalDirs = [message.routesDir, message.resourcesDir, message.promptsDir]\n if (message.commandsDir !== this.commandsDir || optionalDirs.some((dir, i) => dir !== this.optionalDirs[i])) {\n this.commandsDir = message.commandsDir\n this.optionalDirs = optionalDirs\n if (this.watchers.size > 0) this.watchFiles()\n }\n }\n\n private onReady(child: ServerChild, port: number, commands: number): void {\n if (child !== this.pending) return\n const previous = this.current\n child.port = port\n this.pending = undefined\n this.current = child\n this.loadError = undefined\n const ms = Date.now() - child.startedAt\n this.log(`${previous ? \"reloaded\" : \"ready\"} (${commands} command${commands === 1 ? \"\" : \"s\"}, ${ms}ms)`)\n if (previous) this.retire(previous)\n this.flush()\n // commands/ 가 없던 상태에서 생겼으면 감시 시작\n if (this.watchers.size > 0 && !this.watchers.has(this.commandsDir)) this.watchFiles()\n else if (this.watchers.size > 0 && this.optionalDirs.some((dir) => !this.watchers.has(dir) && existsSync(dir))) this.watchFiles()\n }\n\n private onLoadFailed(child: ServerChild, message: string): void {\n if (child !== this.pending) return\n this.pending = undefined\n if (this.firstConfig) {\n this.firstConfig(undefined)\n this.firstConfig = undefined\n }\n if (this.current) {\n this.log(`reload failed; still serving the previous version. Fix the error and save to retry.\\n${indent(message)}`)\n } else {\n this.loadError = message\n this.log(`load failed; requests return an error until the next change.\\n${indent(message)}`)\n }\n this.flush()\n }\n\n /** 진행 중 요청이 끝나면 종료. subscriptions/listen 스트림은 끝나지 않으므로 자식이 완료 result 후 닫는다 (§12.5) */\n private retire(child: ServerChild): void {\n child.retiring = true\n this.retired.add(child)\n if (child.inflight === 0) this.stop(child)\n else if (child.proc.connected) child.proc.send({ type: \"retire\" } satisfies DevParentMessage, () => {})\n }\n\n private stop(child: ServerChild): void {\n if (child.proc.exitCode !== null || child.proc.signalCode !== null) return\n // 준비 전 (로드 중) 자식은 shutdown 메시지를 처리하지 않는다\n if (child.port !== undefined && child.proc.connected) {\n child.proc.send({ type: \"shutdown\" } satisfies DevParentMessage, () => {})\n } else child.proc.kill(\"SIGTERM\")\n setTimeout(() => {\n if (child.proc.exitCode === null && child.proc.signalCode === null) child.proc.kill(\"SIGKILL\")\n }, 3_000).unref()\n }\n\n /* -------------------------------------------------------------- 요청 중계 */\n\n private dispatch(req: IncomingMessage, res: ServerResponse): void {\n if (this.pending) {\n this.queue.push(() => this.dispatch(req, res))\n return\n }\n const child = this.current\n if (child?.port !== undefined) return this.proxy(child, req, res)\n this.sendUnavailable(req, res, this.loadError ?? \"the server process is not running\")\n }\n\n private flush(): void {\n const queued = this.queue\n this.queue = []\n for (const run of queued) run()\n }\n\n private proxy(child: ServerChild, req: IncomingMessage, res: ServerResponse): void {\n // 대기 중 클라이언트가 끊은 요청\n if (res.destroyed || req.destroyed) return\n child.inflight++\n let finished = false\n const done = (): void => {\n if (finished) return\n finished = true\n child.inflight--\n if (child.retiring && child.inflight === 0) this.stop(child)\n }\n const headers: Record<string, string | string[]> = {}\n for (const [name, value] of Object.entries(req.headers)) {\n if (value !== undefined && !HOP_HEADERS.has(name)) headers[name] = value\n }\n const upstream = httpRequest({\n host: \"127.0.0.1\",\n port: child.port,\n method: req.method,\n path: req.url,\n headers,\n agent: false,\n })\n upstream.on(\"response\", (up) => {\n const out: Record<string, string | string[]> = {}\n for (const [name, value] of Object.entries(up.headers)) {\n if (value !== undefined && !HOP_HEADERS.has(name)) out[name] = value\n }\n res.writeHead(up.statusCode ?? 502, out)\n res.flushHeaders()\n up.pipe(res)\n up.on(\"error\", () => res.destroy())\n up.on(\"aborted\", () => res.destroy())\n })\n upstream.on(\"error\", (error) => {\n if (res.headersSent) res.destroy()\n else if (!res.destroyed) {\n sendJson(res, 502, rpcError(-32_603, `mext dev: server process did not respond (${error.message}).`))\n }\n done()\n })\n // 클라이언트 연결 종료 (SSE 취소 포함) = 자식으로의 요청도 닫아 ctx.signal abort\n res.on(\"close\", () => {\n if (!res.writableFinished) upstream.destroy()\n done()\n })\n req.pipe(upstream)\n }\n\n /** 자식 없음 (로드 실패) = 503 + JSON-RPC 오류. MCP 엔드포인트 외 경로도 같은 응답 */\n private sendUnavailable(req: IncomingMessage, res: ServerResponse, message: string): void {\n const chunks: Buffer[] = []\n let size = 0\n req.on(\"data\", (chunk: Buffer) => {\n size += chunk.length\n if (size <= 1024 * 1024) chunks.push(chunk)\n })\n req.on(\"end\", () => {\n const text =\n \"mext dev: the project failed to load. Fix the error and save; the server reloads automatically.\\n\" + message\n sendJson(res, 503, rpcError(-32_603, text, { loadError: message }, requestId(Buffer.concat(chunks))))\n })\n }\n\n /* -------------------------------------------------------------- 파일 감시 */\n\n /** commandsDir · routes · resources · prompts (recursive) + 프로젝트 루트 (mext.config.ts · instrumentation.ts · 폴더 생성 · 삭제) */\n watchFiles(): void {\n if (this.closing) return\n for (const w of this.watchers.values()) w.close()\n this.watchers.clear()\n const rootNames = new Set(DEV_WATCHED_ROOT_FILES)\n if (dirname(this.commandsDir) === this.cwd) rootNames.add(basename(this.commandsDir))\n for (const dir of this.optionalDirs) if (dirname(dir) === this.cwd) rootNames.add(basename(dir))\n this.addWatcher(this.cwd, false, (name) => (rootNames.has(name) ? name : undefined))\n for (const dir of new Set([this.commandsDir, ...this.optionalDirs])) {\n if (existsSync(dir)) this.addWatcher(dir, true, (name) => relative(this.cwd, resolve(dir, name)))\n }\n }\n\n private addWatcher(dir: string, recursive: boolean, accept: (name: string) => string | undefined): void {\n try {\n const watcher = watch(dir, { recursive, persistent: false }, (_event, filename) => {\n const name = filename === null ? undefined : accept(filename.toString())\n if (name !== undefined) this.schedule(name)\n })\n watcher.on(\"error\", (error) => {\n this.log(`file watching stopped for ${relative(this.cwd, dir) || \".\"} (${error.message})`)\n watcher.close()\n this.watchers.delete(dir)\n })\n this.watchers.set(dir, watcher)\n } catch (error) {\n // R3: Linux inotify 한도 (ENOSPC) 등. 서버는 계속, 재시작은 수동\n this.log(`cannot watch ${relative(this.cwd, dir) || \".\"} (${(error as Error).message}); restart mext dev after changes`)\n }\n }\n\n private schedule(name: string): void {\n if (this.closing) return\n this.changed.add(name)\n clearTimeout(this.debounce)\n this.debounce = setTimeout(() => {\n const names = [...this.changed]\n this.changed.clear()\n const shown = names.slice(0, 3).join(\", \") + (names.length > 3 ? `, +${names.length - 3} more` : \"\")\n this.log(`change detected (${shown}); reloading`)\n this.spawn()\n }, DEV_DEBOUNCE_MS)\n }\n\n /* -------------------------------------------------------------- 종료 */\n\n async close(): Promise<void> {\n this.closing = true\n clearTimeout(this.debounce)\n for (const w of this.watchers.values()) w.close()\n this.watchers.clear()\n const children = [this.current, this.pending, ...this.retired].filter((c): c is ServerChild => c !== undefined)\n const exited = children.map(\n (c) =>\n new Promise<void>((done) => {\n if (c.proc.exitCode !== null || c.proc.signalCode !== null) return done()\n c.proc.once(\"exit\", () => done())\n this.stop(c)\n }),\n )\n if (this.server) {\n const server = this.server\n server.closeAllConnections()\n await new Promise<void>((done) => server.close(() => done()))\n }\n this.flush()\n await Promise.all(exited)\n }\n}\n\nfunction indent(text: string): string {\n return text\n .split(\"\\n\")\n .map((l) => ` ${l}`)\n .join(\"\\n\")\n}\n\nfunction sendJson(res: ServerResponse, status: number, body: unknown): void {\n if (res.headersSent || res.destroyed) return\n const text = JSON.stringify(body)\n res.writeHead(status, { \"Content-Type\": \"application/json\", \"Content-Length\": Buffer.byteLength(text) })\n res.end(text)\n}\n\nfunction rpcError(code: number, message: string, data?: unknown, id: string | number | null = null) {\n return { jsonrpc: \"2.0\", id, error: data === undefined ? { code, message } : { code, message, data } }\n}\n\nfunction requestId(body: Buffer): string | number | null {\n try {\n const { id } = JSON.parse(body.toString(\"utf8\")) as { id?: unknown }\n return typeof id === \"string\" || typeof id === \"number\" ? id : null\n } catch {\n return null\n }\n}\n\nexport function devHelp(): string {\n const lines = [\n \"Run the development MCP server (MCP 2026-07-28). Reloads on file changes.\",\n \"\",\n \"Usage:\",\n ` ${DEV_PROG} [--port <n>] [--host <host>]`,\n ` ${DEV_PROG} --stdio`,\n \"\",\n \"Modes:\",\n ...table([\n [\n DEV_PROG,\n `Streamable HTTP at POST http://${DEFAULT_HOST}:${DEFAULT_PORT}${MCP_PATH} (mext.config.ts: app · auth · tools · server · oauth)`,\n ],\n [\"\", `Watches commands/, ${DEV_WATCHED_ROOT_FILES.join(\", \")} and restarts the server process; the port stays open`],\n [`${DEV_PROG} --stdio`, \"stdio (line-delimited JSON-RPC). Local principal; other stdout output goes to stderr. No watching\"],\n ]).map((l) => ` ${l}`),\n \"\",\n \"Flags:\",\n ...table([\n [\"--port <n>\", `HTTP port (default server.port or ${DEFAULT_PORT}; 0 = any free port)`],\n [\"--host <host>\", `HTTP bind address (default server.host or ${DEFAULT_HOST})`],\n [\"--stdio\", \"Serve over stdin/stdout instead of HTTP\"],\n [\"-h, --help\", \"Show help\"],\n ]).map((l) => ` ${l}`),\n \"\",\n \"One HTTP dev server per project: .mext/dev/lock records { pid, url, startedAt } (add .mext/ to .gitignore).\",\n 'Register with an MCP client: \"mext mcp install\".',\n ]\n return `${lines.join(\"\\n\")}\\n`\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import { type BrowserOpener } from "../remote/browser.ts";
2
2
  import { type CliIo } from "./io.ts";
3
+ import { type CliErrorFormatter } from "./output.ts";
3
4
  /**
4
5
  * login · logout 명령 공통 설정. mext CLI = { bin: "mext" }, 고객 CLI = { bin, url } (설정의 cli.bin · cli.url).
5
6
  * bin = 안내 문구의 실행 파일 이름 · 환경변수 접두 (<BIN>_URL · <BIN>_CREDENTIALS_FILE · <BIN>_NO_KEYRING) ·
@@ -17,6 +18,8 @@ export interface AuthCommandOptions {
17
18
  fetch?: typeof fetch;
18
19
  /** device flow polling 대기 (테스트 주입) */
19
20
  sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;
21
+ /** cli.errors (고객 CLI). 오류 출력 · exit code 커스텀. 없음 = 기본 형식 */
22
+ formatter?: CliErrorFormatter;
20
23
  }
21
24
  /**
22
25
  * <bin> login — MCP authorization (OAuth 2.1 · PKCE) 로 토큰 발급 · 저장. 서버 URL 별 (키체인 · credentials.json).
@@ -30,3 +33,5 @@ export declare const runLogin: (argv: readonly string[], io: CliIo) => Promise<n
30
33
  export declare function resolveServerUrl(options: AuthCommandOptions, flag: string | undefined, io: CliIo): string | {
31
34
  error: string;
32
35
  };
36
+ /** login · logout 사용법 오류 = INVALID_ARGUMENT (exit 2). 기본 출력 = "error: …" + help (--json 이어도 텍스트) */
37
+ export declare function usageError(io: CliIo, formatter: CliErrorFormatter | undefined, message: string, help: string): number;
package/dist/cli/login.js CHANGED
@@ -4,7 +4,7 @@ import { canonicalServerUrl, credentialStore, envPrefix } from "../remote/creden
4
4
  import { authorizationCodeLogin, deviceLogin, discoverLoginTarget, OAuthFlowError, parseRedirectUrl, } from "../remote/oauth.js";
5
5
  import { table } from "./help.js";
6
6
  import { createLineReader } from "./io.js";
7
- import { CliInterrupted, EXIT, formatJson } from "./output.js";
7
+ import { CliInterrupted, emitError, EXIT, formatJson } from "./output.js";
8
8
  /**
9
9
  * <bin> login — MCP authorization (OAuth 2.1 · PKCE) 로 토큰 발급 · 저장. 서버 URL 별 (키체인 · credentials.json).
10
10
  * redirect = loopback (127.0.0.1) 또는 붙여넣은 redirect URL (TTY). device flow = 인가 서버가 지원할 때 (--device,
@@ -197,15 +197,15 @@ async function runLoginWith(options, argv, io) {
197
197
  }
198
198
  catch (error) {
199
199
  if (controller.signal.aborted || error instanceof CliInterrupted) {
200
- io.stderr.write(opts.json ? formatJson({ code: "INTERRUPTED", message: "Interrupted." }) : "error: Interrupted.\n");
201
- return EXIT.interrupted;
200
+ const body = { code: "INTERRUPTED", message: "Interrupted." };
201
+ return emitError(io, { body, text: "error: Interrupted.\n", exitCode: EXIT.interrupted, json: opts.json }, options.formatter);
202
202
  }
203
203
  const message = error instanceof Error ? error.message : String(error);
204
204
  const unauthorized = error instanceof RemoteUnauthorizedError;
205
205
  const code = error instanceof OAuthFlowError || unauthorized ? "LOGIN_FAILED" : "REMOTE_ERROR";
206
206
  const text = unauthorized && opts.withToken ? `The server rejected the token (${message})` : message;
207
- io.stderr.write(opts.json ? formatJson({ code, message: text }) : `error: login failed: ${text}\n`);
208
- return unauthorized ? EXIT.auth : EXIT.error;
207
+ const exitCode = unauthorized ? EXIT.auth : EXIT.error;
208
+ return emitError(io, { body: { code, message: text }, text: `error: login failed: ${text}\n`, exitCode, json: opts.json }, options.formatter);
209
209
  }
210
210
  finally {
211
211
  reader.close();
@@ -248,8 +248,12 @@ export function resolveServerUrl(options, flag, io) {
248
248
  return url;
249
249
  }
250
250
  function usage(io, options, message) {
251
- io.stderr.write(`error: ${message}\n\n${loginHelp(options)}`);
252
- return EXIT.usage;
251
+ return usageError(io, options.formatter, message, loginHelp(options));
252
+ }
253
+ /** login · logout 사용법 오류 = INVALID_ARGUMENT (exit 2). 기본 출력 = "error: …" + help (--json 이어도 텍스트) */
254
+ export function usageError(io, formatter, message, help) {
255
+ const body = { code: "INVALID_ARGUMENT", message };
256
+ return emitError(io, { body, text: `error: ${message}\n\n${help}`, exitCode: EXIT.usage, json: false }, formatter);
253
257
  }
254
258
  function loginHelp(options) {
255
259
  const { bin } = options;
@@ -1 +1 @@
1
- {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/cli/login.ts"],"names":[],"mappings":"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","sourcesContent":["import { browserDecision, systemBrowserOpener, type BrowserDecision, type BrowserOpener } from \"../remote/browser.ts\"\nimport { createRemoteClient, RemoteUnauthorizedError, type BearerChallenge } from \"../remote/client.ts\"\nimport { canonicalServerUrl, credentialStore, envPrefix, type StoredCredentials } from \"../remote/credentials.ts\"\nimport {\n authorizationCodeLogin,\n deviceLogin,\n discoverLoginTarget,\n OAuthFlowError,\n parseRedirectUrl,\n type DeviceAuthorization,\n} from \"../remote/oauth.ts\"\nimport { table } from \"./help.ts\"\nimport { createLineReader, type CliIo } from \"./io.ts\"\nimport { CliInterrupted, EXIT, formatJson } from \"./output.ts\"\n\n/**\n * login · logout 명령 공통 설정. mext CLI = { bin: \"mext\" }, 고객 CLI = { bin, url } (설정의 cli.bin · cli.url).\n * bin = 안내 문구의 실행 파일 이름 · 환경변수 접두 (<BIN>_URL · <BIN>_CREDENTIALS_FILE · <BIN>_NO_KEYRING) ·\n * 자격 증명 위치 (~/.config/<bin> · 키체인 service \"<bin> credentials\") · 동적 등록 client_name.\n */\nexport interface AuthCommandOptions {\n bin: string\n /** 고정 서버 URL (고객 CLI). --url 로 덮어쓸 수 있다. 없으면 --url 또는 <BIN>_URL 필수 */\n url?: string\n /** 브라우저 열기 (테스트 주입). 기본 = BROWSER · open · xdg-open */\n openBrowser?: BrowserOpener\n /** 브라우저 판정용 (테스트 주입). 기본 process.platform */\n platform?: NodeJS.Platform\n /** 인가 서버 요청 (테스트 주입) */\n fetch?: typeof fetch\n /** device flow polling 대기 (테스트 주입) */\n sleep?: (ms: number, signal?: AbortSignal) => Promise<void>\n}\n\ninterface LoginFlags {\n url?: string\n clientId?: string\n scope?: string\n port?: number\n browser: boolean\n /** true = 강제, false = 끔, undefined = 자동 */\n device?: boolean\n withToken: boolean\n json: boolean\n}\n\n/**\n * <bin> login — MCP authorization (OAuth 2.1 · PKCE) 로 토큰 발급 · 저장. 서버 URL 별 (키체인 · credentials.json).\n * redirect = loopback (127.0.0.1) 또는 붙여넣은 redirect URL (TTY). device flow = 인가 서버가 지원할 때 (--device,\n * 브라우저를 열지 않는 환경이면 자동). --with-token = stdin 한 줄을 API key 로 저장.\n */\nexport function loginCommand(options: AuthCommandOptions): (argv: readonly string[], io: CliIo) => Promise<number> {\n return (argv, io) => runLoginWith(options, argv, io)\n}\n\n/** mext login */\nexport const runLogin = loginCommand({ bin: \"mext\" })\n\nasync function runLoginWith(options: AuthCommandOptions, argv: readonly string[], io: CliIo): Promise<number> {\n const opts: LoginFlags = { browser: true, withToken: false, 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 const value = (): string | undefined => (eq > 0 && tok.startsWith(\"--\") ? tok.slice(eq + 1) : argv[++i])\n if (name === \"-h\" || name === \"--help\") {\n io.stdout.write(loginHelp(options))\n return EXIT.ok\n } else if (name === \"--json\") opts.json = true\n else if (name === \"--no-browser\") opts.browser = false\n else if (name === \"--device\") opts.device = true\n else if (name === \"--no-device\") opts.device = false\n else if (name === \"--with-token\") opts.withToken = true\n else if (name === \"--url\") opts.url = value()\n else if (name === \"--client-id\") opts.clientId = value()\n else if (name === \"--scope\") opts.scope = value()\n else if (name === \"--port\") {\n const raw = value()\n const port = Number(raw)\n if (!Number.isInteger(port) || port < 0 || port > 65_535) {\n return usage(io, options, `--port must be a port number (got \"${raw}\")`)\n }\n opts.port = port\n } else return usage(io, options, `unknown argument ${tok}`)\n }\n const url = resolveServerUrl(options, opts.url, io)\n if (typeof url !== \"string\") return usage(io, options, url.error)\n\n const controller = new AbortController()\n const onAbort = (): void => controller.abort(new CliInterrupted())\n if (io.signal?.aborted) onAbort()\n io.signal?.addEventListener(\"abort\", onAbort, { once: true })\n const reader = createLineReader(io)\n try {\n const store = credentialStore({ env: io.env, bin: options.bin })\n const server = canonicalServerUrl(url)\n if (opts.withToken) {\n const line = await reader.question(io.isTTY ? \"Paste the token and press Enter: \" : \"\", controller.signal)\n if (controller.signal.aborted) throw new CliInterrupted()\n const token = line?.trim() ?? \"\"\n if (token === \"\") return usage(io, options, \"--with-token reads the token from stdin (got nothing)\")\n // 저장 전에 확인 (거부된 토큰은 저장하지 않는다)\n await createRemoteClient({ url, token: () => token }).listTools({ signal: controller.signal })\n await store.set(url, { access_token: token, token_type: \"Bearer\" })\n if (opts.json) io.stdout.write(formatJson({ url: server, storage: store.location, flow: \"token\" }))\n else io.stderr.write(`Token saved for ${server} to ${store.location}.\\n`)\n return EXIT.ok\n }\n\n // 토큰 없는 요청의 401 → WWW-Authenticate (resource_metadata · scope). 401 이 아니면 well-known 탐색\n let challenge: BearerChallenge | undefined\n try {\n await createRemoteClient({ url }).listTools({ signal: controller.signal })\n } catch (error) {\n if (error instanceof RemoteUnauthorizedError) challenge = error.challenge\n else if (controller.signal.aborted) throw new CliInterrupted()\n else throw error\n }\n const doFetch = options.fetch ?? fetch\n const target = await discoverLoginTarget({\n serverUrl: url,\n ...(challenge ? { challenge } : {}),\n ...(opts.scope !== undefined ? { scope: opts.scope } : {}),\n fetch: doFetch,\n })\n const decision: BrowserDecision = opts.browser\n ? browserDecision(io.env, options.platform ?? process.platform)\n : { open: false }\n const open = options.openBrowser ?? systemBrowserOpener(io.env, options.platform ?? process.platform)\n const hasDevice = typeof target.as.device_authorization_endpoint === \"string\"\n if (opts.device === true && !hasDevice) {\n throw new OAuthFlowError(\n `${target.as.issuer} does not support the device authorization grant (no device_authorization_endpoint). ` +\n \"Run login without --device.\",\n )\n }\n // D5: 자동 device flow = 인가 서버 지원 + 환경 때문에 브라우저를 열지 않음 (SSH · display 없음) + --port · --no-device 없음.\n // --no-browser 는 사용자 선택이라 loopback · 붙여넣기 유지\n const useDevice =\n opts.device === true ||\n (opts.device === undefined && hasDevice && decision.reason !== undefined && opts.port === undefined)\n const common = {\n clientName: options.bin,\n signal: controller.signal,\n fetch: doFetch,\n ...(opts.clientId !== undefined ? { clientId: opts.clientId } : {}),\n }\n\n let credentials: StoredCredentials\n if (useDevice) {\n credentials = await deviceLogin(target, {\n ...common,\n ...(options.sleep ? { sleep: options.sleep } : {}),\n onDeviceCode(device) {\n printDeviceCode(io, opts.json, url, device, decision)\n if (decision.open) open(device.verification_uri_complete ?? device.verification_uri)\n },\n })\n } else {\n credentials = await authorizationCodeLogin(target, {\n ...common,\n ...(opts.port !== undefined ? { port: opts.port } : {}),\n onAuthorizationUrl(authorizeUrl, loopback) {\n io.stderr.write(\n [\n decision.open\n ? `Opening a browser to log in to ${url}. If it does not open, visit:`\n : `Open this URL in a browser to log in to ${url}:`,\n \"\",\n ` ${authorizeUrl}`,\n \"\",\n `Waiting for the redirect to ${loopback.redirectUri}`,\n `(browser on another machine: ${io.isTTY ? \"paste the redirect URL from its address bar below, or \" : \"\"}` +\n `ssh -L ${loopback.port}:127.0.0.1:${loopback.port} <this host> with --port)`,\n \"\",\n ].join(\"\\n\"),\n )\n if (decision.open) open(authorizeUrl)\n },\n // 붙여넣기는 TTY 에서만 (파이프 stdin 은 다른 용도일 수 있음)\n ...(io.isTTY\n ? {\n async readRedirect(signal: AbortSignal) {\n for (;;) {\n const line = await reader.question(\"Redirect URL: \", signal)\n if (line === undefined) {\n if (signal.aborted) io.stderr.write(\"\\n\") // loopback 이 먼저: 프롬프트 줄 닫기\n return undefined\n }\n const query = parseRedirectUrl(line)\n if (query) return query\n if (line.trim() !== \"\") io.stderr.write(\"Not a redirect URL. Paste the full URL from the browser address bar.\\n\")\n }\n },\n }\n : {}),\n })\n }\n await store.set(url, credentials)\n // 발급 토큰으로 확인 요청\n await createRemoteClient({ url, token: () => credentials.access_token }).listTools({ signal: controller.signal })\n if (opts.json) {\n const out: Record<string, unknown> = {\n url: server,\n storage: store.location,\n issuer: credentials.issuer,\n flow: useDevice ? \"device\" : \"authorization_code\",\n }\n if (credentials.scope !== undefined) out.scope = credentials.scope\n if (credentials.expires_at !== undefined) out.expires_at = new Date(credentials.expires_at).toISOString()\n io.stdout.write(formatJson(out))\n } else {\n io.stderr.write(`Logged in to ${server}. Token saved to ${store.location}.\\n`)\n }\n return EXIT.ok\n } catch (error) {\n if (controller.signal.aborted || error instanceof CliInterrupted) {\n io.stderr.write(opts.json ? formatJson({ code: \"INTERRUPTED\", message: \"Interrupted.\" }) : \"error: Interrupted.\\n\")\n return EXIT.interrupted\n }\n const message = error instanceof Error ? error.message : String(error)\n const unauthorized = error instanceof RemoteUnauthorizedError\n const code = error instanceof OAuthFlowError || unauthorized ? \"LOGIN_FAILED\" : \"REMOTE_ERROR\"\n const text = unauthorized && opts.withToken ? `The server rejected the token (${message})` : message\n io.stderr.write(opts.json ? formatJson({ code, message: text }) : `error: login failed: ${text}\\n`)\n return unauthorized ? EXIT.auth : EXIT.error\n } finally {\n reader.close()\n io.signal?.removeEventListener(\"abort\", onAbort)\n }\n}\n\n/**\n * device flow 안내 (D5). TTY 이고 --json 아님 = 사람용 텍스트, 그 외 = JSON 한 줄\n * { verification_uri, verification_uri_complete?, user_code, expires_in } (stderr, stdout 은 결과 전용). 이후 polling 계속\n */\nfunction printDeviceCode(io: CliIo, json: boolean, url: string, device: DeviceAuthorization, decision: BrowserDecision): void {\n if (json || !io.isTTY) {\n const line: Record<string, unknown> = { verification_uri: device.verification_uri }\n if (device.verification_uri_complete !== undefined) line.verification_uri_complete = device.verification_uri_complete\n line.user_code = device.user_code\n line.expires_in = device.expires_in\n io.stderr.write(`${JSON.stringify(line)}\\n`)\n return\n }\n const minutes = Math.max(1, Math.round(device.expires_in / 60))\n io.stderr.write(\n [\n `${decision.open ? \"Opening a browser\" : \"Open this URL in a browser\"} to log in to ${url}:`,\n \"\",\n ` ${device.verification_uri_complete ?? device.verification_uri}`,\n \"\",\n `and confirm the code: ${device.user_code} (expires in ${minutes} min)`,\n \"Waiting for authorization...\",\n \"\",\n ].join(\"\\n\"),\n )\n}\n\n/** 서버 URL = --url → 고정 URL (고객 CLI) → <BIN>_URL */\nexport function resolveServerUrl(\n options: AuthCommandOptions,\n flag: string | undefined,\n io: CliIo,\n): string | { error: string } {\n const envName = `${envPrefix(options.bin)}_URL`\n const url = flag ?? options.url ?? (io.env[envName] || undefined)\n if (url === undefined || url === \"\") return { error: `--url <url> is required (or set ${envName})` }\n if (!/^https?:\\/\\//i.test(url)) return { error: `--url must be an http(s) URL (got \"${url}\")` }\n return url\n}\n\nfunction usage(io: CliIo, options: AuthCommandOptions, message: string): number {\n io.stderr.write(`error: ${message}\\n\\n${loginHelp(options)}`)\n return EXIT.usage\n}\n\nfunction loginHelp(options: AuthCommandOptions): string {\n const { bin } = options\n const prefix = envPrefix(bin)\n const rows = [\n [\"--url <url>\", options.url ? `MCP endpoint (default: ${options.url})` : `MCP endpoint (default: ${prefix}_URL)`],\n [\"--client-id <id>\", \"Pre-registered OAuth client ID or Client ID Metadata Document URL (default: dynamic registration)\"],\n [\"--scope <scopes>\", \"Space-separated scopes (default: server challenge or scopes_supported)\"],\n [\"--port <port>\", \"Loopback redirect port on 127.0.0.1 (default: random)\"],\n [\"--no-browser\", \"Print the authorization URL without opening a browser\"],\n [\"--device\", \"Use the device authorization grant (if the authorization server supports it)\"],\n [\"--no-device\", \"Never switch to the device authorization grant automatically\"],\n [\"--with-token\", \"Read a token (API key) from stdin and store it\"],\n [\"--json\", \"Print the result as JSON\"],\n [\"-h, --help\", \"Show help\"],\n ]\n return [\n \"Log in to a remote server (OAuth 2.1 authorization code + PKCE, loopback redirect).\",\n `The token is stored per server URL (OS keychain, or ~/.config/${bin}/credentials.json; ${prefix}_NO_KEYRING=1 = file only).`,\n \"Over SSH or without a display the browser is not opened: paste the redirect URL, or the device flow is used\",\n \"when the authorization server supports it.\",\n \"\",\n \"Usage:\",\n ` ${bin} login${options.url ? \"\" : \" --url <url>\"} [flags]`,\n ` echo \"$TOKEN\" | ${bin} login${options.url ? \"\" : \" --url <url>\"} --with-token`,\n \"\",\n \"Flags:\",\n ...table(rows).map((l) => ` ${l}`),\n \"\",\n ].join(\"\\n\")\n}\n"]}
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/cli/login.ts"],"names":[],"mappings":"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","sourcesContent":["import { browserDecision, systemBrowserOpener, type BrowserDecision, type BrowserOpener } from \"../remote/browser.ts\"\nimport { createRemoteClient, RemoteUnauthorizedError, type BearerChallenge } from \"../remote/client.ts\"\nimport { canonicalServerUrl, credentialStore, envPrefix, type StoredCredentials } from \"../remote/credentials.ts\"\nimport {\n authorizationCodeLogin,\n deviceLogin,\n discoverLoginTarget,\n OAuthFlowError,\n parseRedirectUrl,\n type DeviceAuthorization,\n} from \"../remote/oauth.ts\"\nimport { table } from \"./help.ts\"\nimport { createLineReader, type CliIo } from \"./io.ts\"\nimport { CliInterrupted, emitError, EXIT, formatJson, type CliErrorFormatter } from \"./output.ts\"\n\n/**\n * login · logout 명령 공통 설정. mext CLI = { bin: \"mext\" }, 고객 CLI = { bin, url } (설정의 cli.bin · cli.url).\n * bin = 안내 문구의 실행 파일 이름 · 환경변수 접두 (<BIN>_URL · <BIN>_CREDENTIALS_FILE · <BIN>_NO_KEYRING) ·\n * 자격 증명 위치 (~/.config/<bin> · 키체인 service \"<bin> credentials\") · 동적 등록 client_name.\n */\nexport interface AuthCommandOptions {\n bin: string\n /** 고정 서버 URL (고객 CLI). --url 로 덮어쓸 수 있다. 없으면 --url 또는 <BIN>_URL 필수 */\n url?: string\n /** 브라우저 열기 (테스트 주입). 기본 = BROWSER · open · xdg-open */\n openBrowser?: BrowserOpener\n /** 브라우저 판정용 (테스트 주입). 기본 process.platform */\n platform?: NodeJS.Platform\n /** 인가 서버 요청 (테스트 주입) */\n fetch?: typeof fetch\n /** device flow polling 대기 (테스트 주입) */\n sleep?: (ms: number, signal?: AbortSignal) => Promise<void>\n /** cli.errors (고객 CLI). 오류 출력 · exit code 커스텀. 없음 = 기본 형식 */\n formatter?: CliErrorFormatter\n}\n\ninterface LoginFlags {\n url?: string\n clientId?: string\n scope?: string\n port?: number\n browser: boolean\n /** true = 강제, false = 끔, undefined = 자동 */\n device?: boolean\n withToken: boolean\n json: boolean\n}\n\n/**\n * <bin> login — MCP authorization (OAuth 2.1 · PKCE) 로 토큰 발급 · 저장. 서버 URL 별 (키체인 · credentials.json).\n * redirect = loopback (127.0.0.1) 또는 붙여넣은 redirect URL (TTY). device flow = 인가 서버가 지원할 때 (--device,\n * 브라우저를 열지 않는 환경이면 자동). --with-token = stdin 한 줄을 API key 로 저장.\n */\nexport function loginCommand(options: AuthCommandOptions): (argv: readonly string[], io: CliIo) => Promise<number> {\n return (argv, io) => runLoginWith(options, argv, io)\n}\n\n/** mext login */\nexport const runLogin = loginCommand({ bin: \"mext\" })\n\nasync function runLoginWith(options: AuthCommandOptions, argv: readonly string[], io: CliIo): Promise<number> {\n const opts: LoginFlags = { browser: true, withToken: false, 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 const value = (): string | undefined => (eq > 0 && tok.startsWith(\"--\") ? tok.slice(eq + 1) : argv[++i])\n if (name === \"-h\" || name === \"--help\") {\n io.stdout.write(loginHelp(options))\n return EXIT.ok\n } else if (name === \"--json\") opts.json = true\n else if (name === \"--no-browser\") opts.browser = false\n else if (name === \"--device\") opts.device = true\n else if (name === \"--no-device\") opts.device = false\n else if (name === \"--with-token\") opts.withToken = true\n else if (name === \"--url\") opts.url = value()\n else if (name === \"--client-id\") opts.clientId = value()\n else if (name === \"--scope\") opts.scope = value()\n else if (name === \"--port\") {\n const raw = value()\n const port = Number(raw)\n if (!Number.isInteger(port) || port < 0 || port > 65_535) {\n return usage(io, options, `--port must be a port number (got \"${raw}\")`)\n }\n opts.port = port\n } else return usage(io, options, `unknown argument ${tok}`)\n }\n const url = resolveServerUrl(options, opts.url, io)\n if (typeof url !== \"string\") return usage(io, options, url.error)\n\n const controller = new AbortController()\n const onAbort = (): void => controller.abort(new CliInterrupted())\n if (io.signal?.aborted) onAbort()\n io.signal?.addEventListener(\"abort\", onAbort, { once: true })\n const reader = createLineReader(io)\n try {\n const store = credentialStore({ env: io.env, bin: options.bin })\n const server = canonicalServerUrl(url)\n if (opts.withToken) {\n const line = await reader.question(io.isTTY ? \"Paste the token and press Enter: \" : \"\", controller.signal)\n if (controller.signal.aborted) throw new CliInterrupted()\n const token = line?.trim() ?? \"\"\n if (token === \"\") return usage(io, options, \"--with-token reads the token from stdin (got nothing)\")\n // 저장 전에 확인 (거부된 토큰은 저장하지 않는다)\n await createRemoteClient({ url, token: () => token }).listTools({ signal: controller.signal })\n await store.set(url, { access_token: token, token_type: \"Bearer\" })\n if (opts.json) io.stdout.write(formatJson({ url: server, storage: store.location, flow: \"token\" }))\n else io.stderr.write(`Token saved for ${server} to ${store.location}.\\n`)\n return EXIT.ok\n }\n\n // 토큰 없는 요청의 401 → WWW-Authenticate (resource_metadata · scope). 401 이 아니면 well-known 탐색\n let challenge: BearerChallenge | undefined\n try {\n await createRemoteClient({ url }).listTools({ signal: controller.signal })\n } catch (error) {\n if (error instanceof RemoteUnauthorizedError) challenge = error.challenge\n else if (controller.signal.aborted) throw new CliInterrupted()\n else throw error\n }\n const doFetch = options.fetch ?? fetch\n const target = await discoverLoginTarget({\n serverUrl: url,\n ...(challenge ? { challenge } : {}),\n ...(opts.scope !== undefined ? { scope: opts.scope } : {}),\n fetch: doFetch,\n })\n const decision: BrowserDecision = opts.browser\n ? browserDecision(io.env, options.platform ?? process.platform)\n : { open: false }\n const open = options.openBrowser ?? systemBrowserOpener(io.env, options.platform ?? process.platform)\n const hasDevice = typeof target.as.device_authorization_endpoint === \"string\"\n if (opts.device === true && !hasDevice) {\n throw new OAuthFlowError(\n `${target.as.issuer} does not support the device authorization grant (no device_authorization_endpoint). ` +\n \"Run login without --device.\",\n )\n }\n // D5: 자동 device flow = 인가 서버 지원 + 환경 때문에 브라우저를 열지 않음 (SSH · display 없음) + --port · --no-device 없음.\n // --no-browser 는 사용자 선택이라 loopback · 붙여넣기 유지\n const useDevice =\n opts.device === true ||\n (opts.device === undefined && hasDevice && decision.reason !== undefined && opts.port === undefined)\n const common = {\n clientName: options.bin,\n signal: controller.signal,\n fetch: doFetch,\n ...(opts.clientId !== undefined ? { clientId: opts.clientId } : {}),\n }\n\n let credentials: StoredCredentials\n if (useDevice) {\n credentials = await deviceLogin(target, {\n ...common,\n ...(options.sleep ? { sleep: options.sleep } : {}),\n onDeviceCode(device) {\n printDeviceCode(io, opts.json, url, device, decision)\n if (decision.open) open(device.verification_uri_complete ?? device.verification_uri)\n },\n })\n } else {\n credentials = await authorizationCodeLogin(target, {\n ...common,\n ...(opts.port !== undefined ? { port: opts.port } : {}),\n onAuthorizationUrl(authorizeUrl, loopback) {\n io.stderr.write(\n [\n decision.open\n ? `Opening a browser to log in to ${url}. If it does not open, visit:`\n : `Open this URL in a browser to log in to ${url}:`,\n \"\",\n ` ${authorizeUrl}`,\n \"\",\n `Waiting for the redirect to ${loopback.redirectUri}`,\n `(browser on another machine: ${io.isTTY ? \"paste the redirect URL from its address bar below, or \" : \"\"}` +\n `ssh -L ${loopback.port}:127.0.0.1:${loopback.port} <this host> with --port)`,\n \"\",\n ].join(\"\\n\"),\n )\n if (decision.open) open(authorizeUrl)\n },\n // 붙여넣기는 TTY 에서만 (파이프 stdin 은 다른 용도일 수 있음)\n ...(io.isTTY\n ? {\n async readRedirect(signal: AbortSignal) {\n for (;;) {\n const line = await reader.question(\"Redirect URL: \", signal)\n if (line === undefined) {\n if (signal.aborted) io.stderr.write(\"\\n\") // loopback 이 먼저: 프롬프트 줄 닫기\n return undefined\n }\n const query = parseRedirectUrl(line)\n if (query) return query\n if (line.trim() !== \"\") io.stderr.write(\"Not a redirect URL. Paste the full URL from the browser address bar.\\n\")\n }\n },\n }\n : {}),\n })\n }\n await store.set(url, credentials)\n // 발급 토큰으로 확인 요청\n await createRemoteClient({ url, token: () => credentials.access_token }).listTools({ signal: controller.signal })\n if (opts.json) {\n const out: Record<string, unknown> = {\n url: server,\n storage: store.location,\n issuer: credentials.issuer,\n flow: useDevice ? \"device\" : \"authorization_code\",\n }\n if (credentials.scope !== undefined) out.scope = credentials.scope\n if (credentials.expires_at !== undefined) out.expires_at = new Date(credentials.expires_at).toISOString()\n io.stdout.write(formatJson(out))\n } else {\n io.stderr.write(`Logged in to ${server}. Token saved to ${store.location}.\\n`)\n }\n return EXIT.ok\n } catch (error) {\n if (controller.signal.aborted || error instanceof CliInterrupted) {\n const body = { code: \"INTERRUPTED\", message: \"Interrupted.\" }\n return emitError(io, { body, text: \"error: Interrupted.\\n\", exitCode: EXIT.interrupted, json: opts.json }, options.formatter)\n }\n const message = error instanceof Error ? error.message : String(error)\n const unauthorized = error instanceof RemoteUnauthorizedError\n const code = error instanceof OAuthFlowError || unauthorized ? \"LOGIN_FAILED\" : \"REMOTE_ERROR\"\n const text = unauthorized && opts.withToken ? `The server rejected the token (${message})` : message\n const exitCode = unauthorized ? EXIT.auth : EXIT.error\n return emitError(io, { body: { code, message: text }, text: `error: login failed: ${text}\\n`, exitCode, json: opts.json }, options.formatter)\n } finally {\n reader.close()\n io.signal?.removeEventListener(\"abort\", onAbort)\n }\n}\n\n/**\n * device flow 안내 (D5). TTY 이고 --json 아님 = 사람용 텍스트, 그 외 = JSON 한 줄\n * { verification_uri, verification_uri_complete?, user_code, expires_in } (stderr, stdout 은 결과 전용). 이후 polling 계속\n */\nfunction printDeviceCode(io: CliIo, json: boolean, url: string, device: DeviceAuthorization, decision: BrowserDecision): void {\n if (json || !io.isTTY) {\n const line: Record<string, unknown> = { verification_uri: device.verification_uri }\n if (device.verification_uri_complete !== undefined) line.verification_uri_complete = device.verification_uri_complete\n line.user_code = device.user_code\n line.expires_in = device.expires_in\n io.stderr.write(`${JSON.stringify(line)}\\n`)\n return\n }\n const minutes = Math.max(1, Math.round(device.expires_in / 60))\n io.stderr.write(\n [\n `${decision.open ? \"Opening a browser\" : \"Open this URL in a browser\"} to log in to ${url}:`,\n \"\",\n ` ${device.verification_uri_complete ?? device.verification_uri}`,\n \"\",\n `and confirm the code: ${device.user_code} (expires in ${minutes} min)`,\n \"Waiting for authorization...\",\n \"\",\n ].join(\"\\n\"),\n )\n}\n\n/** 서버 URL = --url → 고정 URL (고객 CLI) → <BIN>_URL */\nexport function resolveServerUrl(\n options: AuthCommandOptions,\n flag: string | undefined,\n io: CliIo,\n): string | { error: string } {\n const envName = `${envPrefix(options.bin)}_URL`\n const url = flag ?? options.url ?? (io.env[envName] || undefined)\n if (url === undefined || url === \"\") return { error: `--url <url> is required (or set ${envName})` }\n if (!/^https?:\\/\\//i.test(url)) return { error: `--url must be an http(s) URL (got \"${url}\")` }\n return url\n}\n\nfunction usage(io: CliIo, options: AuthCommandOptions, message: string): number {\n return usageError(io, options.formatter, message, loginHelp(options))\n}\n\n/** login · logout 사용법 오류 = INVALID_ARGUMENT (exit 2). 기본 출력 = \"error: …\" + help (--json 이어도 텍스트) */\nexport function usageError(io: CliIo, formatter: CliErrorFormatter | undefined, message: string, help: string): number {\n const body = { code: \"INVALID_ARGUMENT\", message }\n return emitError(io, { body, text: `error: ${message}\\n\\n${help}`, exitCode: EXIT.usage, json: false }, formatter)\n}\n\nfunction loginHelp(options: AuthCommandOptions): string {\n const { bin } = options\n const prefix = envPrefix(bin)\n const rows = [\n [\"--url <url>\", options.url ? `MCP endpoint (default: ${options.url})` : `MCP endpoint (default: ${prefix}_URL)`],\n [\"--client-id <id>\", \"Pre-registered OAuth client ID or Client ID Metadata Document URL (default: dynamic registration)\"],\n [\"--scope <scopes>\", \"Space-separated scopes (default: server challenge or scopes_supported)\"],\n [\"--port <port>\", \"Loopback redirect port on 127.0.0.1 (default: random)\"],\n [\"--no-browser\", \"Print the authorization URL without opening a browser\"],\n [\"--device\", \"Use the device authorization grant (if the authorization server supports it)\"],\n [\"--no-device\", \"Never switch to the device authorization grant automatically\"],\n [\"--with-token\", \"Read a token (API key) from stdin and store it\"],\n [\"--json\", \"Print the result as JSON\"],\n [\"-h, --help\", \"Show help\"],\n ]\n return [\n \"Log in to a remote server (OAuth 2.1 authorization code + PKCE, loopback redirect).\",\n `The token is stored per server URL (OS keychain, or ~/.config/${bin}/credentials.json; ${prefix}_NO_KEYRING=1 = file only).`,\n \"Over SSH or without a display the browser is not opened: paste the redirect URL, or the device flow is used\",\n \"when the authorization server supports it.\",\n \"\",\n \"Usage:\",\n ` ${bin} login${options.url ? \"\" : \" --url <url>\"} [flags]`,\n ` echo \"$TOKEN\" | ${bin} login${options.url ? \"\" : \" --url <url>\"} --with-token`,\n \"\",\n \"Flags:\",\n ...table(rows).map((l) => ` ${l}`),\n \"\",\n ].join(\"\\n\")\n}\n"]}
@@ -1,8 +1,8 @@
1
1
  import { canonicalServerUrl, credentialStore, envPrefix } from "../remote/credentials.js";
2
2
  import { revokeCredentials } from "../remote/oauth.js";
3
3
  import { table } from "./help.js";
4
- import { resolveServerUrl } from "./login.js";
5
- import { EXIT, formatJson } from "./output.js";
4
+ import { resolveServerUrl, usageError } from "./login.js";
5
+ import { emitError, EXIT, formatJson } from "./output.js";
6
6
  /**
7
7
  * <bin> logout — 저장된 토큰 폐기 · 삭제. 인가 서버 메타데이터에 revocation_endpoint (RFC 7009) 가 있으면
8
8
  * refresh token → access token 순서로 폐기 요청 (best effort: 실패는 경고, 삭제는 계속), 그다음 키체인 · 파일에서 삭제.
@@ -53,8 +53,7 @@ async function runLogoutWith(options, argv, io) {
53
53
  }
54
54
  catch (error) {
55
55
  const message = `Cannot remove stored credentials from ${store.location}: ${error instanceof Error ? error.message : String(error)}`;
56
- io.stderr.write(json ? formatJson({ code: "LOGOUT_FAILED", message }) : `error: ${message}\n`);
57
- return EXIT.error;
56
+ return emitError(io, { body: { code: "LOGOUT_FAILED", message }, text: `error: ${message}\n`, exitCode: EXIT.error, json }, options.formatter);
58
57
  }
59
58
  if (json) {
60
59
  const out = {
@@ -80,8 +79,7 @@ async function runLogoutWith(options, argv, io) {
80
79
  return EXIT.ok;
81
80
  }
82
81
  function usage(io, options, message) {
83
- io.stderr.write(`error: ${message}\n\n${logoutHelp(options)}`);
84
- return EXIT.usage;
82
+ return usageError(io, options.formatter, message, logoutHelp(options));
85
83
  }
86
84
  function logoutHelp(options) {
87
85
  const { bin } = options;