@obov/mext 0.4.0 → 0.6.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 (164) hide show
  1. package/dist/approval.d.ts +33 -0
  2. package/dist/approval.js +36 -0
  3. package/dist/approval.js.map +1 -0
  4. package/dist/audit.d.ts +123 -0
  5. package/dist/audit.js +221 -0
  6. package/dist/audit.js.map +1 -0
  7. package/dist/build-cli.d.ts +1 -0
  8. package/dist/build-cli.js +2 -1
  9. package/dist/build-cli.js.map +1 -1
  10. package/dist/build.d.ts +2 -0
  11. package/dist/build.js +30 -3
  12. package/dist/build.js.map +1 -1
  13. package/dist/caller.d.ts +53 -0
  14. package/dist/caller.js +51 -0
  15. package/dist/caller.js.map +1 -0
  16. package/dist/cli/build.js +6 -3
  17. package/dist/cli/build.js.map +1 -1
  18. package/dist/cli/dev-audit.d.ts +25 -0
  19. package/dist/cli/dev-audit.js +84 -0
  20. package/dist/cli/dev-audit.js.map +1 -0
  21. package/dist/cli/dev-lock.d.ts +3 -1
  22. package/dist/cli/dev-lock.js +12 -5
  23. package/dist/cli/dev-lock.js.map +1 -1
  24. package/dist/cli/dev-server.d.ts +9 -0
  25. package/dist/cli/dev-server.js +24 -1
  26. package/dist/cli/dev-server.js.map +1 -1
  27. package/dist/cli/dev-tap.d.ts +20 -0
  28. package/dist/cli/dev-tap.js +70 -0
  29. package/dist/cli/dev-tap.js.map +1 -0
  30. package/dist/cli/dev.js +16 -4
  31. package/dist/cli/dev.js.map +1 -1
  32. package/dist/cli/help.js +2 -0
  33. package/dist/cli/help.js.map +1 -1
  34. package/dist/cli/inspect.d.ts +7 -0
  35. package/dist/cli/inspect.js +699 -0
  36. package/dist/cli/inspect.js.map +1 -0
  37. package/dist/cli/main.js +8 -0
  38. package/dist/cli/main.js.map +1 -1
  39. package/dist/cli/output.d.ts +1 -1
  40. package/dist/cli/output.js +3 -2
  41. package/dist/cli/output.js.map +1 -1
  42. package/dist/cli/run.js +28 -4
  43. package/dist/cli/run.js.map +1 -1
  44. package/dist/cli/types.d.ts +9 -0
  45. package/dist/cli/types.js +77 -0
  46. package/dist/cli/types.js.map +1 -0
  47. package/dist/client/index.d.ts +10 -0
  48. package/dist/client/index.js +7 -0
  49. package/dist/client/index.js.map +1 -0
  50. package/dist/client/manifest.js +6 -2
  51. package/dist/client/manifest.js.map +1 -1
  52. package/dist/client/runner.js +37 -3
  53. package/dist/client/runner.js.map +1 -1
  54. package/dist/client/typed.d.ts +54 -0
  55. package/dist/client/typed.js +490 -0
  56. package/dist/client/typed.js.map +1 -0
  57. package/dist/client/types.d.ts +196 -0
  58. package/dist/client/types.js +2 -0
  59. package/dist/client/types.js.map +1 -0
  60. package/dist/command.d.ts +61 -5
  61. package/dist/command.js +42 -1
  62. package/dist/command.js.map +1 -1
  63. package/dist/config.d.ts +42 -10
  64. package/dist/config.js +32 -7
  65. package/dist/config.js.map +1 -1
  66. package/dist/errors.d.ts +21 -3
  67. package/dist/errors.js +13 -0
  68. package/dist/errors.js.map +1 -1
  69. package/dist/expose.d.ts +9 -0
  70. package/dist/expose.js +52 -0
  71. package/dist/expose.js.map +1 -0
  72. package/dist/index.d.ts +15 -6
  73. package/dist/index.js +7 -2
  74. package/dist/index.js.map +1 -1
  75. package/dist/inspect/agent.d.ts +104 -0
  76. package/dist/inspect/agent.js +125 -0
  77. package/dist/inspect/agent.js.map +1 -0
  78. package/dist/inspect/audit.d.ts +46 -0
  79. package/dist/inspect/audit.js +133 -0
  80. package/dist/inspect/audit.js.map +1 -0
  81. package/dist/inspect/compare.d.ts +12 -0
  82. package/dist/inspect/compare.js +31 -0
  83. package/dist/inspect/compare.js.map +1 -0
  84. package/dist/inspect/index.d.ts +17 -0
  85. package/dist/inspect/index.js +12 -0
  86. package/dist/inspect/index.js.map +1 -0
  87. package/dist/inspect/inspector.d.ts +168 -0
  88. package/dist/inspect/inspector.js +392 -0
  89. package/dist/inspect/inspector.js.map +1 -0
  90. package/dist/inspect/profiles.d.ts +95 -0
  91. package/dist/inspect/profiles.js +235 -0
  92. package/dist/inspect/profiles.js.map +1 -0
  93. package/dist/inspect/scenario.d.ts +126 -0
  94. package/dist/inspect/scenario.js +555 -0
  95. package/dist/inspect/scenario.js.map +1 -0
  96. package/dist/inspect/ui-server.d.ts +31 -0
  97. package/dist/inspect/ui-server.js +378 -0
  98. package/dist/inspect/ui-server.js.map +1 -0
  99. package/dist/inspect/ui.html +917 -0
  100. package/dist/instrumentation.d.ts +13 -2
  101. package/dist/instrumentation.js +11 -1
  102. package/dist/instrumentation.js.map +1 -1
  103. package/dist/invoke.d.ts +32 -5
  104. package/dist/invoke.js +150 -16
  105. package/dist/invoke.js.map +1 -1
  106. package/dist/manifest.d.ts +13 -2
  107. package/dist/manifest.js +5 -1
  108. package/dist/manifest.js.map +1 -1
  109. package/dist/mcp/constants.d.ts +5 -0
  110. package/dist/mcp/constants.js +5 -0
  111. package/dist/mcp/constants.js.map +1 -1
  112. package/dist/mcp/dispatch.d.ts +1 -1
  113. package/dist/mcp/dispatch.js +14 -3
  114. package/dist/mcp/dispatch.js.map +1 -1
  115. package/dist/mcp/help.d.ts +2 -0
  116. package/dist/mcp/help.js +6 -1
  117. package/dist/mcp/help.js.map +1 -1
  118. package/dist/mcp/http.d.ts +16 -2
  119. package/dist/mcp/http.js +76 -7
  120. package/dist/mcp/http.js.map +1 -1
  121. package/dist/mcp/index.d.ts +1 -1
  122. package/dist/mcp/index.js +1 -1
  123. package/dist/mcp/index.js.map +1 -1
  124. package/dist/mcp/install.d.ts +1 -1
  125. package/dist/mcp/install.js +3 -2
  126. package/dist/mcp/install.js.map +1 -1
  127. package/dist/mcp/server.d.ts +12 -1
  128. package/dist/mcp/server.js +63 -17
  129. package/dist/mcp/server.js.map +1 -1
  130. package/dist/mcp/stdio.d.ts +4 -0
  131. package/dist/mcp/stdio.js +28 -0
  132. package/dist/mcp/stdio.js.map +1 -1
  133. package/dist/mcp/tasks.d.ts +3 -1
  134. package/dist/mcp/tasks.js +6 -3
  135. package/dist/mcp/tasks.js.map +1 -1
  136. package/dist/principal.d.ts +22 -0
  137. package/dist/principal.js +29 -0
  138. package/dist/principal.js.map +1 -1
  139. package/dist/registry.d.ts +5 -0
  140. package/dist/registry.js +21 -0
  141. package/dist/registry.js.map +1 -1
  142. package/dist/remote/client.d.ts +2 -0
  143. package/dist/remote/client.js +3 -2
  144. package/dist/remote/client.js.map +1 -1
  145. package/dist/remote/oauth.d.ts +1 -1
  146. package/dist/remote/oauth.js +1 -1
  147. package/dist/remote/oauth.js.map +1 -1
  148. package/dist/runtime.d.ts +10 -0
  149. package/dist/runtime.js +11 -0
  150. package/dist/runtime.js.map +1 -0
  151. package/dist/start.js +6 -2
  152. package/dist/start.js.map +1 -1
  153. package/dist/suggest.js +1 -1
  154. package/dist/suggest.js.map +1 -1
  155. package/dist/typegen.d.ts +27 -0
  156. package/dist/typegen.js +62 -0
  157. package/dist/typegen.js.map +1 -0
  158. package/dist/version-constant.d.ts +5 -0
  159. package/dist/version-constant.js +6 -0
  160. package/dist/version-constant.js.map +1 -0
  161. package/dist/version.d.ts +1 -2
  162. package/dist/version.js +1 -2
  163. package/dist/version.js.map +1 -1
  164. package/package.json +14 -3
package/dist/build.js CHANGED
@@ -14,12 +14,14 @@ import { buildCustomerCli, CLI_DIR, customerCliIssues, projectVersion } from "./
14
14
  import { cliBuildIssues } from "./cli/args.js";
15
15
  import { CONFIG_FILE, loadConfig, resolveCommandsDir, resolvePromptsDir, resolveResourcesDir, resolveRoutesDir } from "./config.js";
16
16
  import { MextBuildError } from "./errors.js";
17
+ import { exposedRegistry } from "./expose.js";
17
18
  import { buildManifest, manifestHash, MANIFEST_SCHEMA_VERSION } from "./manifest.js";
18
19
  import { collectPrompts, collectPromptSet, describePrompt } from "./prompt.js";
19
20
  import { collectRegistry } from "./registry.js";
20
21
  import { collectResources, collectResourceSet, describeResource, resourceEntries } from "./resource.js";
21
22
  import { collectRoutes } from "./route.js";
22
23
  import { collectCommands } from "./scan.js";
24
+ import { resolveTypesPath, writeTypes } from "./typegen.js";
23
25
  import { mextVersion } from "./version.js";
24
26
  /** mext build 산출 폴더 (도입 프로젝트 루트 기준) */
25
27
  export const BUILD_DIR = ".mext";
@@ -194,7 +196,10 @@ export async function buildProject(options = {}) {
194
196
  ...(hasInstrumentation ? { instrumentation: "instrumentation.js" } : {}),
195
197
  ...(base.description !== undefined ? { description: base.description } : {}),
196
198
  namespaces: base.namespaces,
197
- commands: base.commands.map((c) => ({ ...c, module: moduleOf.get(c.id) })),
199
+ commands: base.commands.map((c) => {
200
+ const expose = registry.commands.get(c.id)?.command.expose;
201
+ return { ...c, module: moduleOf.get(c.id), ...(expose ? { expose: { ...expose } } : {}) };
202
+ }),
198
203
  ...(resourceList.length > 0
199
204
  ? { resources: resourceList.map((r) => ({ ...describeResource(r), module: resourceModuleOf.get(r.uri) })) }
200
205
  : {}),
@@ -231,16 +236,38 @@ export async function buildProject(options = {}) {
231
236
  if (localBin)
232
237
  chmodSync(join(outDir, LOCAL_BIN_FILE), 0o755);
233
238
  // 고객 CLI (.mext/cli/, §5): manifest · buildId 확정 후, manifest.json 쓰기 전. 로컬 bin 이면 만들지 않는다
234
- const cli = config.cli && !local ? await buildCustomerCli({ rolldown, cwd, outDir, cli: config.cli, manifest }) : undefined;
239
+ // 고객 CLI = 원격 실행의 기본 표면 (mcp) 에서 보이는 명령어 · 그 manifestHash (§4 expose). 숨긴 명령어가 없으면 manifest 그대로
240
+ const mcpView = exposedRegistry(registry, "mcp");
241
+ const cliManifest = mcpView === registry
242
+ ? manifest
243
+ : {
244
+ ...manifest,
245
+ namespaces: buildManifest(mcpView).namespaces,
246
+ commands: manifest.commands.filter((c) => mcpView.commands.has(c.id)),
247
+ manifestHash: manifestHash(base.commands.filter((c) => mcpView.commands.has(c.id)), { resources: resourceList.map((r) => r.uri), prompts: promptList.map((p) => ({ name: p.name, argsSchema: p.argsSchema })) }),
248
+ };
249
+ const cli = config.cli && !local ? await buildCustomerCli({ rolldown, cwd, outDir, cli: config.cli, manifest: cliManifest }) : undefined;
235
250
  // manifest.json 은 마지막: 중간 실패한 빌드는 manifest 가 없어 mext start 가 "mext build 먼저" 로 거부
236
251
  writeFileSync(join(outDir, BUILD_MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}\n`);
252
+ // 명령어 타입 (specs/client.md §4): config.types 가 있을 때만. 산출 폴더 밖 (프로젝트 소스 옆) 에 쓴다
253
+ const typesPath = resolveTypesPath(cwd, config.types);
254
+ if (typesPath !== undefined)
255
+ writeTypes(commandsDir, typesPath);
237
256
  const files = [
238
257
  ...emitted,
239
258
  ...Object.keys(generated),
240
259
  BUILD_MANIFEST_FILE,
241
260
  ...(cli?.files.map((f) => `${CLI_DIR}/${f}`) ?? []),
242
261
  ].sort();
243
- return { outDir, manifest, files, warnings, ...(cli ? { cli } : {}), ...(localBin ? { localBin } : {}) };
262
+ return {
263
+ outDir,
264
+ manifest,
265
+ files,
266
+ warnings,
267
+ ...(cli ? { cli } : {}),
268
+ ...(localBin ? { localBin } : {}),
269
+ ...(typesPath !== undefined ? { types: typesPath } : {}),
270
+ };
244
271
  }
245
272
  /**
246
273
  * .mext/bin.js (로컬 bin, cli.local). 계약: mainLocalBin(.mext 폴더 URL, { bin, version, errors? }).
package/dist/build.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"build.js","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\"\nimport { chmodSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\"\nimport { isBuiltin } from \"node:module\"\nimport { basename, isAbsolute, join, relative, resolve, sep } from \"node:path\"\nimport { buildCustomerCli, CLI_DIR, customerCliIssues, projectVersion, type CustomerCliBuild } from \"./build-cli.ts\"\nimport { cliBuildIssues } from \"./cli/args.ts\"\nimport { CONFIG_FILE, loadConfig, resolveCommandsDir, resolvePromptsDir, resolveResourcesDir, resolveRoutesDir } from \"./config.ts\"\nimport { MextBuildError } from \"./errors.ts\"\nimport { buildManifest, manifestHash, MANIFEST_SCHEMA_VERSION, type BuildManifest } from \"./manifest.ts\"\nimport { collectPrompts, collectPromptSet, describePrompt } from \"./prompt.ts\"\nimport { collectRegistry } from \"./registry.ts\"\nimport { collectResources, collectResourceSet, describeResource, resourceEntries } from \"./resource.ts\"\nimport { collectRoutes } from \"./route.ts\"\nimport { collectCommands } from \"./scan.ts\"\nimport { mextVersion } from \"./version.ts\"\n\n/** mext build 산출 폴더 (도입 프로젝트 루트 기준) */\nexport const BUILD_DIR = \".mext\"\nexport const BUILD_MANIFEST_FILE = \"manifest.json\"\nexport const INSTRUMENTATION_FILE = \"instrumentation.ts\"\n/** 생성 파일 (server.js · handler.js) 이 import 하는 런타임 엔트리 */\nexport const START_ENTRY = \"@obov/mext/start\"\n/** 로컬 bin (cli.local) 실행 파일 · cli.errors 번들 */\nexport const LOCAL_BIN_FILE = \"bin.js\"\nexport const LOCAL_BIN_ERRORS = \"cli-errors\"\n/** 빌드가 지우지 않는 .mext/ 하위 (mext dev 산출 · 잠금) */\nconst PRESERVED_ENTRIES = new Set([\"dev\"])\n\n/** rolldown 모듈 중 mext build 가 쓰는 부분 */\nexport interface RolldownModule {\n build(options: Record<string, unknown>): Promise<{ output: readonly RolldownOutputItem[] }>\n}\n\nexport interface RolldownOutputItem {\n type: \"chunk\" | \"asset\"\n fileName: string\n /** chunk 코드 */\n code?: string\n isEntry?: boolean\n name?: string\n}\n\nexport interface BuildOptions {\n /** 도입 프로젝트 루트 (mext.config.ts · package.json · instrumentation.ts 위치). 기본 process.cwd() */\n cwd?: string\n /** 산출 폴더. 기본 <cwd>/.mext. 기존 내용은 dev/ 외 삭제 */\n outDir?: string\n /** rolldown 로더 (테스트 주입). 기본 import(\"rolldown\") (선택 peer dependency) */\n importRolldown?: () => Promise<RolldownModule>\n}\n\nexport interface BuildWarning {\n /**\n * UNDECLARED_DEPENDENCY = 외부로 남긴 패키지가 package.json dependencies · peerDependencies · optionalDependencies 에 없음.\n * LOCAL_BIN_UNDECLARED = cli.local 인데 package.json bin[\"<bin>\"] 이 .mext/bin.js 가 아님\n */\n code: \"UNDECLARED_DEPENDENCY\" | \"BUNDLER_WARNING\" | \"LOCAL_BIN_UNDECLARED\"\n message: string\n}\n\nexport interface BuildResult {\n /** 산출 폴더 절대 경로 */\n outDir: string\n manifest: BuildManifest\n /** outDir 기준 생성 파일 (posix, 정렬) */\n files: string[]\n warnings: BuildWarning[]\n /** 고객 CLI (.mext/cli/). config.cli 가 있고 local 이 아닐 때 */\n cli?: CustomerCliBuild\n /** 로컬 bin (.mext/bin.js). config.cli.local 일 때 */\n localBin?: { bin: string; version: string }\n}\n\n/** rolldown 을 찾을 수 없음. message 에 설치 명령 */\nexport class RolldownUnavailableError extends Error {\n readonly installCommand: string\n\n constructor(installCommand: string, cause?: unknown) {\n super(`mext build requires rolldown (optional peer dependency of @obov/mext). Install it: ${installCommand}`, { cause })\n this.name = \"RolldownUnavailableError\"\n this.installCommand = installCommand\n }\n}\n\n/**\n * mext build: commands/ → .mext/ (§10).\n * 1. rolldown 확인 (없으면 RolldownUnavailableError)\n * 2. 검증: 파일 규칙 · import · Registry (ID · 별칭 · 스키마) · CLI 변환 issue 를 모두 모아 MextBuildError 한 번\n * 3. rolldown 다중 엔트리 번들: commands/**\\/*.js (명령어별) · config.js · instrumentation.js · chunks/. 패키지 import 는 외부\n * 4. server.js · handler.js (얇은 생성 파일, 런타임 = @obov/mext/start) · package.json (type module) · manifest.json (마지막)\n */\nexport async function buildProject(options: BuildOptions = {}): Promise<BuildResult> {\n const cwd = resolve(options.cwd ?? process.cwd())\n const outDir = resolve(cwd, options.outDir ?? BUILD_DIR)\n // 빌드 전 outDir 을 비우므로 프로젝트 폴더 자체 · 상위는 거부\n const up = relative(outDir, cwd)\n if (up === \"\" || (!up.startsWith(\"..\") && !isAbsolute(up))) {\n throw new Error(`mext build: outDir must not be the project directory or its parent (${outDir})`)\n }\n const rolldown = await (options.importRolldown ?? importRolldown)().catch((error: unknown) => {\n if (isModuleNotFound(error, \"rolldown\")) throw new RolldownUnavailableError(installCommand(cwd), error)\n throw error\n })\n\n const config = await loadConfig(cwd)\n const commandsDir = resolveCommandsDir(cwd, config)\n const scanned = await collectCommands(commandsDir)\n const { registry, issues: registryIssues } = collectRegistry(scanned)\n const routesDir = resolveRoutesDir(cwd, config)\n const routes = await collectRoutes(routesDir)\n const resourcesDir = resolveResourcesDir(cwd, config)\n const scannedResources = await collectResources(resourcesDir)\n const { resources, issues: resourceIssues } = collectResourceSet(scannedResources.inputs, basename(resourcesDir))\n const promptsDir = resolvePromptsDir(cwd, config)\n const scannedPrompts = await collectPrompts(promptsDir)\n const { prompts, issues: promptIssues } = collectPromptSet(scannedPrompts.inputs, basename(promptsDir))\n const issues = [\n ...scanned.issues,\n ...registryIssues,\n ...cliBuildIssues(registry),\n ...customerCliIssues(config.cli, registry),\n ...scannedResources.issues,\n ...resourceIssues,\n ...scannedPrompts.issues,\n ...promptIssues,\n ...routes.issues,\n ]\n if (issues.length > 0) throw new MextBuildError(issues)\n\n // 엔트리 이름 = 출력 경로 (확장자 제외). 명령어 = commands/ 아래 소스 경로 그대로\n const input: Record<string, string> = {}\n const moduleOf = new Map<string, string>()\n for (const entry of registry.commands.values()) {\n const file = entry.file!\n const name = `commands/${file.replace(/\\.ts$/, \"\")}`\n input[name] = join(commandsDir, file)\n moduleOf.set(entry.id, `${name}.js`)\n }\n // 자원 = resources/ 아래 소스 경로 그대로 (§12.3)\n const resourceList = resourceEntries(resources).sort((a, b) => (a.uri < b.uri ? -1 : a.uri > b.uri ? 1 : 0))\n const resourceModuleOf = new Map<string, string>()\n for (const entry of resourceList) {\n const name = `resources/${entry.file!.replace(/\\.ts$/, \"\")}`\n input[name] = join(resourcesDir, entry.file!)\n resourceModuleOf.set(entry.uri, `${name}.js`)\n }\n // 프롬프트 = prompts/ 아래 소스 경로 그대로 (§12.3)\n const promptList = [...prompts.values()]\n const promptModuleOf = new Map<string, string>()\n for (const entry of promptList) {\n const name = `prompts/${entry.file!.replace(/\\.ts$/, \"\")}`\n input[name] = join(promptsDir, entry.file!)\n promptModuleOf.set(entry.name, `${name}.js`)\n }\n for (const route of routes.routes) input[routeModuleName(route.file)] = join(routesDir, route.file)\n const hasConfig = existsSync(join(cwd, CONFIG_FILE))\n if (hasConfig) input.config = join(cwd, CONFIG_FILE)\n const hasInstrumentation = existsSync(join(cwd, INSTRUMENTATION_FILE))\n if (hasInstrumentation) input.instrumentation = join(cwd, INSTRUMENTATION_FILE)\n const local = config.cli?.local === true ? config.cli : undefined\n if (local?.errors !== undefined) {\n const errorsFile = resolve(cwd, local.errors)\n if (!existsSync(errorsFile)) throw new MextBuildError([{ code: \"INVALID_CONFIG\", message: `cli.errors file not found: ${local.errors}` }])\n input[LOCAL_BIN_ERRORS] = errorsFile\n }\n\n cleanOutDir(outDir)\n\n const warnings: BuildWarning[] = []\n /** 외부 패키지 이름 → 처음 import 한 파일 */\n const externals = new Map<string, string | undefined>()\n let output: readonly RolldownOutputItem[]\n try {\n ;({ output } = await rolldown.build({\n cwd,\n input,\n platform: \"node\",\n // 상대 · 절대 경로 · # (package.json imports) = 번들. 그 외 bare import = 외부 (도입 프로젝트 node_modules 에서 해석)\n external: (id: string, importer: string | undefined): boolean => {\n if (id.startsWith(\".\") || id.startsWith(\"#\") || id.startsWith(\"\\0\") || isAbsolute(id)) return false\n if (id.startsWith(\"node:\") || isBuiltin(id)) return true\n const pkg = packageName(id)\n if (!externals.has(pkg) && importer !== undefined && !importer.startsWith(\"\\0\")) externals.set(pkg, importer)\n return true\n },\n transform: { target: \"node22\" },\n logLevel: \"warn\",\n onLog: (_level: string, log: { message: string }) => warnings.push({ code: \"BUNDLER_WARNING\", message: log.message }),\n output: {\n dir: outDir,\n format: \"esm\",\n entryFileNames: \"[name].js\",\n chunkFileNames: \"chunks/[name]-[hash].js\",\n sourcemap: true,\n },\n }))\n } catch (error) {\n throw new MextBuildError([{ code: \"BUNDLE_FAILED\", message: error instanceof Error ? error.message : String(error) }])\n }\n\n const declared = declaredDependencies(cwd)\n for (const [pkg, importer] of externals) {\n if (declared.has(pkg)) continue\n const from = importer === undefined ? \"\" : ` (imported by ${toPosix(relative(cwd, importer))})`\n warnings.push({\n code: \"UNDECLARED_DEPENDENCY\",\n message: `\"${pkg}\" is not in package.json dependencies${from}. It stays external and must be installed where .mext/ runs`,\n })\n }\n\n const emitted = new Set(output.map((o) => o.fileName))\n for (const name of Object.keys(input)) {\n if (!emitted.has(`${name}.js`)) throw new Error(`mext build: rolldown did not emit ${name}.js`)\n }\n\n const base = buildManifest(registry)\n const hash = manifestHash(base.commands, {\n resources: resourceList.map((r) => r.uri),\n prompts: promptList.map((p) => ({ name: p.name, argsSchema: p.argsSchema })),\n })\n const version = mextVersion()\n const manifest: BuildManifest = {\n schemaVersion: MANIFEST_SCHEMA_VERSION,\n mextVersion: version,\n buildId: buildIdOf(version, hash, output),\n manifestHash: hash,\n tools: config.tools ?? \"execute\",\n ...(hasConfig ? { config: \"config.js\" } : {}),\n ...(hasInstrumentation ? { instrumentation: \"instrumentation.js\" } : {}),\n ...(base.description !== undefined ? { description: base.description } : {}),\n namespaces: base.namespaces,\n commands: base.commands.map((c) => ({ ...c, module: moduleOf.get(c.id)! })),\n ...(resourceList.length > 0\n ? { resources: resourceList.map((r) => ({ ...describeResource(r), module: resourceModuleOf.get(r.uri)! })) }\n : {}),\n ...(promptList.length > 0\n ? { prompts: promptList.map((p) => ({ ...describePrompt(p), module: promptModuleOf.get(p.name)! })) }\n : {}),\n ...(routes.routes.length > 0\n ? {\n routes: routes.routes\n .map((r) => ({ path: r.path, file: r.file, methods: r.methods, module: `${routeModuleName(r.file)}.js` }))\n .sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0)),\n }\n : {}),\n }\n\n const generated: Record<string, string> = {\n \"package.json\": `${JSON.stringify({ type: \"module\" }, null, 2)}\\n`,\n \"server.js\": SERVER_JS,\n \"handler.js\": HANDLER_JS,\n }\n const localBin = local ? { bin: local.bin, version: local.version ?? projectVersion(cwd) ?? \"0.0.0\" } : undefined\n if (localBin) {\n generated[LOCAL_BIN_FILE] = localBinJs({ ...localBin, ...(local?.errors !== undefined ? { errors: `${LOCAL_BIN_ERRORS}.js` } : {}) })\n const declaredBin = packageBin(cwd, localBin.bin)\n const expected = `${toPosix(relative(cwd, outDir))}/${LOCAL_BIN_FILE}`\n if (declaredBin === undefined || declaredBin.replace(/^\\.\\//, \"\") !== expected) {\n warnings.push({\n code: \"LOCAL_BIN_UNDECLARED\",\n message: `cli.local: add \"bin\": { \"${localBin.bin}\": \"${expected}\" } to package.json (and include ${toPosix(relative(cwd, outDir))} in \"files\")`,\n })\n }\n }\n for (const [file, content] of Object.entries(generated)) writeFileSync(join(outDir, file), content)\n if (localBin) chmodSync(join(outDir, LOCAL_BIN_FILE), 0o755)\n\n // 고객 CLI (.mext/cli/, §5): manifest · buildId 확정 후, manifest.json 쓰기 전. 로컬 bin 이면 만들지 않는다\n const cli = config.cli && !local ? await buildCustomerCli({ rolldown, cwd, outDir, cli: config.cli, manifest }) : undefined\n\n // manifest.json 은 마지막: 중간 실패한 빌드는 manifest 가 없어 mext start 가 \"mext build 먼저\" 로 거부\n writeFileSync(join(outDir, BUILD_MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}\\n`)\n\n const files = [\n ...emitted,\n ...Object.keys(generated),\n BUILD_MANIFEST_FILE,\n ...(cli?.files.map((f) => `${CLI_DIR}/${f}`) ?? []),\n ].sort()\n return { outDir, manifest, files, warnings, ...(cli ? { cli } : {}), ...(localBin ? { localBin } : {}) }\n}\n\n/**\n * .mext/bin.js (로컬 bin, cli.local). 계약: mainLocalBin(.mext 폴더 URL, { bin, version, errors? }).\n * 도입 프로젝트 package.json bin 이 이 파일을 가리킨다 (npm 이 symlink 해도 import.meta.url = 실제 경로)\n */\nexport function localBinJs(options: { bin: string; version: string; errors?: string }): string {\n return `#!/usr/bin/env node\n// Generated by mext build. Do not edit.\n// Local bin (cli.local): ${options.bin} help · ${options.bin} <namespace> <command> · ${options.bin} mcp serve\nimport { mainLocalBin } from \"${START_ENTRY}\"\n\nawait mainLocalBin(new URL(\".\", import.meta.url), ${JSON.stringify(options)})\n`\n}\n\n/** package.json bin[name] (문자열 bin = 패키지 이름이 name 일 때) */\nfunction packageBin(cwd: string, name: string): string | undefined {\n try {\n const pkg = JSON.parse(readFileSync(join(cwd, \"package.json\"), \"utf8\")) as { name?: unknown; bin?: unknown }\n if (typeof pkg.bin === \"string\") return pkg.name === name ? pkg.bin : undefined\n if (typeof pkg.bin === \"object\" && pkg.bin !== null) {\n const v = (pkg.bin as Record<string, unknown>)[name]\n return typeof v === \"string\" ? v : undefined\n }\n } catch {\n // package.json 없음 · 형식 오류 = 미선언\n }\n return undefined\n}\n\n/**\n * .mext/server.js. 계약: startFromBuild(.mext 폴더 URL, { argv, env }) → exit code.\n * argv = server.js 뒤 인자 (--stdio), env = PORT · HOST\n */\nexport const SERVER_JS = `// Generated by mext build. Do not edit.\n// node .mext/server.js [--stdio] (= mext start). Environment: PORT · HOST\nimport { startFromBuild } from \"${START_ENTRY}\"\n\nprocess.exitCode = await startFromBuild(new URL(\".\", import.meta.url), { argv: process.argv.slice(2), env: process.env })\n`\n\n/** .mext/handler.js. 계약: createFetchHandler(.mext 폴더 URL) → { fetch(request: Request): Promise<Response> } (동기 반환) */\nexport const HANDLER_JS = `// Generated by mext build. Do not edit.\n// Web fetch handler (Request → Response) for other runtimes and platforms\nimport { createFetchHandler } from \"${START_ENTRY}\"\n\nexport default createFetchHandler(new URL(\".\", import.meta.url))\n`\n\nasync function importRolldown(): Promise<RolldownModule> {\n // 문자열 변수: 타입 검사 · 번들러가 선택 peer 를 정적 의존으로 취급하지 않게\n const specifier = \"rolldown\"\n return (await import(specifier)) as RolldownModule\n}\n\nfunction isModuleNotFound(error: unknown, pkg: string): boolean {\n const e = error as { code?: unknown; message?: unknown } | null\n if (typeof e !== \"object\" || e === null) return false\n if (e.code !== \"ERR_MODULE_NOT_FOUND\" && e.code !== \"MODULE_NOT_FOUND\") return false\n return typeof e.message !== \"string\" || e.message.includes(`'${pkg}'`) || e.message.includes(`\"${pkg}\"`)\n}\n\n/** 도입 프로젝트의 lock 파일로 패키지 관리자 추정 */\nfunction installCommand(cwd: string): string {\n for (let dir = cwd; ; dir = resolve(dir, \"..\")) {\n if (existsSync(join(dir, \"pnpm-lock.yaml\"))) return \"pnpm add -D rolldown\"\n if (existsSync(join(dir, \"yarn.lock\"))) return \"yarn add -D rolldown\"\n if (existsSync(join(dir, \"bun.lock\")) || existsSync(join(dir, \"bun.lockb\"))) return \"bun add -d rolldown\"\n if (existsSync(join(dir, \"package-lock.json\")) || resolve(dir, \"..\") === dir) return \"npm install --save-dev rolldown\"\n }\n}\n\nfunction cleanOutDir(outDir: string): void {\n mkdirSync(outDir, { recursive: true })\n for (const name of readdirSync(outDir)) {\n if (!PRESERVED_ENTRIES.has(name)) rmSync(join(outDir, name), { recursive: true, force: true })\n }\n}\n\n/**\n * route 엔트리 이름 = routes/ 아래 소스 경로, [name] → _name_ (rolldown 이 [ ] 를 바꾸므로 직접 정한다).\n * `_` 접두 파일 · 폴더는 route 가 아니라 충돌 없음. routes/items/[id].ts → routes/items/_id_\n */\nfunction routeModuleName(file: string): string {\n return `routes/${file.replace(/\\.ts$/, \"\").replace(/\\[([^\\]/]+)\\]/g, \"_$1_\")}`\n}\n\n/** \"@scope/pkg/sub\" → \"@scope/pkg\" · \"pkg/sub\" → \"pkg\" */\nfunction packageName(specifier: string): string {\n const parts = specifier.split(\"/\")\n return specifier.startsWith(\"@\") ? parts.slice(0, 2).join(\"/\") : parts[0]!\n}\n\nfunction declaredDependencies(cwd: string): Set<string> {\n let pkg: Record<string, unknown>\n try {\n pkg = JSON.parse(readFileSync(join(cwd, \"package.json\"), \"utf8\")) as Record<string, unknown>\n } catch {\n return new Set()\n }\n const names = new Set<string>()\n if (typeof pkg.name === \"string\") names.add(pkg.name)\n for (const field of [\"dependencies\", \"peerDependencies\", \"optionalDependencies\"]) {\n const deps = pkg[field]\n if (typeof deps === \"object\" && deps !== null) for (const name of Object.keys(deps)) names.add(name)\n }\n return names\n}\n\n/** D3: mextVersion · manifestHash · 번들 chunk (파일 이름 · 코드) 의 sha256 앞 16자. 같은 입력 = 같은 buildId */\nfunction buildIdOf(version: string, hash: string, output: readonly RolldownOutputItem[]): string {\n const h = createHash(\"sha256\").update(`${version}\\n${hash}\\n`)\n for (const item of [...output].sort((a, b) => (a.fileName < b.fileName ? -1 : 1))) {\n if (item.type !== \"chunk\") continue\n h.update(`${item.fileName}\\0${item.code ?? \"\"}\\0`)\n }\n return h.digest(\"hex\").slice(0, 16)\n}\n\nfunction toPosix(path: string): string {\n return path.split(sep).join(\"/\")\n}\n"]}
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\"\nimport { chmodSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\"\nimport { isBuiltin } from \"node:module\"\nimport { basename, isAbsolute, join, relative, resolve, sep } from \"node:path\"\nimport { buildCustomerCli, CLI_DIR, customerCliIssues, projectVersion, type CustomerCliBuild } from \"./build-cli.ts\"\nimport { cliBuildIssues } from \"./cli/args.ts\"\nimport { CONFIG_FILE, loadConfig, resolveCommandsDir, resolvePromptsDir, resolveResourcesDir, resolveRoutesDir } from \"./config.ts\"\nimport { MextBuildError } from \"./errors.ts\"\nimport { exposedRegistry } from \"./expose.ts\"\nimport { buildManifest, manifestHash, MANIFEST_SCHEMA_VERSION, type BuildManifest } from \"./manifest.ts\"\nimport { collectPrompts, collectPromptSet, describePrompt } from \"./prompt.ts\"\nimport { collectRegistry } from \"./registry.ts\"\nimport { collectResources, collectResourceSet, describeResource, resourceEntries } from \"./resource.ts\"\nimport { collectRoutes } from \"./route.ts\"\nimport { collectCommands } from \"./scan.ts\"\nimport { resolveTypesPath, writeTypes } from \"./typegen.ts\"\nimport { mextVersion } from \"./version.ts\"\n\n/** mext build 산출 폴더 (도입 프로젝트 루트 기준) */\nexport const BUILD_DIR = \".mext\"\nexport const BUILD_MANIFEST_FILE = \"manifest.json\"\nexport const INSTRUMENTATION_FILE = \"instrumentation.ts\"\n/** 생성 파일 (server.js · handler.js) 이 import 하는 런타임 엔트리 */\nexport const START_ENTRY = \"@obov/mext/start\"\n/** 로컬 bin (cli.local) 실행 파일 · cli.errors 번들 */\nexport const LOCAL_BIN_FILE = \"bin.js\"\nexport const LOCAL_BIN_ERRORS = \"cli-errors\"\n/** 빌드가 지우지 않는 .mext/ 하위 (mext dev 산출 · 잠금) */\nconst PRESERVED_ENTRIES = new Set([\"dev\"])\n\n/** rolldown 모듈 중 mext build 가 쓰는 부분 */\nexport interface RolldownModule {\n build(options: Record<string, unknown>): Promise<{ output: readonly RolldownOutputItem[] }>\n}\n\nexport interface RolldownOutputItem {\n type: \"chunk\" | \"asset\"\n fileName: string\n /** chunk 코드 */\n code?: string\n isEntry?: boolean\n name?: string\n}\n\nexport interface BuildOptions {\n /** 도입 프로젝트 루트 (mext.config.ts · package.json · instrumentation.ts 위치). 기본 process.cwd() */\n cwd?: string\n /** 산출 폴더. 기본 <cwd>/.mext. 기존 내용은 dev/ 외 삭제 */\n outDir?: string\n /** rolldown 로더 (테스트 주입). 기본 import(\"rolldown\") (선택 peer dependency) */\n importRolldown?: () => Promise<RolldownModule>\n}\n\nexport interface BuildWarning {\n /**\n * UNDECLARED_DEPENDENCY = 외부로 남긴 패키지가 package.json dependencies · peerDependencies · optionalDependencies 에 없음.\n * LOCAL_BIN_UNDECLARED = cli.local 인데 package.json bin[\"<bin>\"] 이 .mext/bin.js 가 아님\n */\n code: \"UNDECLARED_DEPENDENCY\" | \"BUNDLER_WARNING\" | \"LOCAL_BIN_UNDECLARED\"\n message: string\n}\n\nexport interface BuildResult {\n /** 산출 폴더 절대 경로 */\n outDir: string\n manifest: BuildManifest\n /** outDir 기준 생성 파일 (posix, 정렬) */\n files: string[]\n warnings: BuildWarning[]\n /** 고객 CLI (.mext/cli/). config.cli 가 있고 local 이 아닐 때 */\n cli?: CustomerCliBuild\n /** 로컬 bin (.mext/bin.js). config.cli.local 일 때 */\n localBin?: { bin: string; version: string }\n /** 명령어 타입 생성 파일 (config.types 가 있을 때, specs/client.md §4). 절대 경로 */\n types?: string\n}\n\n/** rolldown 을 찾을 수 없음. message 에 설치 명령 */\nexport class RolldownUnavailableError extends Error {\n readonly installCommand: string\n\n constructor(installCommand: string, cause?: unknown) {\n super(`mext build requires rolldown (optional peer dependency of @obov/mext). Install it: ${installCommand}`, { cause })\n this.name = \"RolldownUnavailableError\"\n this.installCommand = installCommand\n }\n}\n\n/**\n * mext build: commands/ → .mext/ (§10).\n * 1. rolldown 확인 (없으면 RolldownUnavailableError)\n * 2. 검증: 파일 규칙 · import · Registry (ID · 별칭 · 스키마) · CLI 변환 issue 를 모두 모아 MextBuildError 한 번\n * 3. rolldown 다중 엔트리 번들: commands/**\\/*.js (명령어별) · config.js · instrumentation.js · chunks/. 패키지 import 는 외부\n * 4. server.js · handler.js (얇은 생성 파일, 런타임 = @obov/mext/start) · package.json (type module) · manifest.json (마지막)\n */\nexport async function buildProject(options: BuildOptions = {}): Promise<BuildResult> {\n const cwd = resolve(options.cwd ?? process.cwd())\n const outDir = resolve(cwd, options.outDir ?? BUILD_DIR)\n // 빌드 전 outDir 을 비우므로 프로젝트 폴더 자체 · 상위는 거부\n const up = relative(outDir, cwd)\n if (up === \"\" || (!up.startsWith(\"..\") && !isAbsolute(up))) {\n throw new Error(`mext build: outDir must not be the project directory or its parent (${outDir})`)\n }\n const rolldown = await (options.importRolldown ?? importRolldown)().catch((error: unknown) => {\n if (isModuleNotFound(error, \"rolldown\")) throw new RolldownUnavailableError(installCommand(cwd), error)\n throw error\n })\n\n const config = await loadConfig(cwd)\n const commandsDir = resolveCommandsDir(cwd, config)\n const scanned = await collectCommands(commandsDir)\n const { registry, issues: registryIssues } = collectRegistry(scanned)\n const routesDir = resolveRoutesDir(cwd, config)\n const routes = await collectRoutes(routesDir)\n const resourcesDir = resolveResourcesDir(cwd, config)\n const scannedResources = await collectResources(resourcesDir)\n const { resources, issues: resourceIssues } = collectResourceSet(scannedResources.inputs, basename(resourcesDir))\n const promptsDir = resolvePromptsDir(cwd, config)\n const scannedPrompts = await collectPrompts(promptsDir)\n const { prompts, issues: promptIssues } = collectPromptSet(scannedPrompts.inputs, basename(promptsDir))\n const issues = [\n ...scanned.issues,\n ...registryIssues,\n ...cliBuildIssues(registry),\n ...customerCliIssues(config.cli, registry),\n ...scannedResources.issues,\n ...resourceIssues,\n ...scannedPrompts.issues,\n ...promptIssues,\n ...routes.issues,\n ]\n if (issues.length > 0) throw new MextBuildError(issues)\n\n // 엔트리 이름 = 출력 경로 (확장자 제외). 명령어 = commands/ 아래 소스 경로 그대로\n const input: Record<string, string> = {}\n const moduleOf = new Map<string, string>()\n for (const entry of registry.commands.values()) {\n const file = entry.file!\n const name = `commands/${file.replace(/\\.ts$/, \"\")}`\n input[name] = join(commandsDir, file)\n moduleOf.set(entry.id, `${name}.js`)\n }\n // 자원 = resources/ 아래 소스 경로 그대로 (§12.3)\n const resourceList = resourceEntries(resources).sort((a, b) => (a.uri < b.uri ? -1 : a.uri > b.uri ? 1 : 0))\n const resourceModuleOf = new Map<string, string>()\n for (const entry of resourceList) {\n const name = `resources/${entry.file!.replace(/\\.ts$/, \"\")}`\n input[name] = join(resourcesDir, entry.file!)\n resourceModuleOf.set(entry.uri, `${name}.js`)\n }\n // 프롬프트 = prompts/ 아래 소스 경로 그대로 (§12.3)\n const promptList = [...prompts.values()]\n const promptModuleOf = new Map<string, string>()\n for (const entry of promptList) {\n const name = `prompts/${entry.file!.replace(/\\.ts$/, \"\")}`\n input[name] = join(promptsDir, entry.file!)\n promptModuleOf.set(entry.name, `${name}.js`)\n }\n for (const route of routes.routes) input[routeModuleName(route.file)] = join(routesDir, route.file)\n const hasConfig = existsSync(join(cwd, CONFIG_FILE))\n if (hasConfig) input.config = join(cwd, CONFIG_FILE)\n const hasInstrumentation = existsSync(join(cwd, INSTRUMENTATION_FILE))\n if (hasInstrumentation) input.instrumentation = join(cwd, INSTRUMENTATION_FILE)\n const local = config.cli?.local === true ? config.cli : undefined\n if (local?.errors !== undefined) {\n const errorsFile = resolve(cwd, local.errors)\n if (!existsSync(errorsFile)) throw new MextBuildError([{ code: \"INVALID_CONFIG\", message: `cli.errors file not found: ${local.errors}` }])\n input[LOCAL_BIN_ERRORS] = errorsFile\n }\n\n cleanOutDir(outDir)\n\n const warnings: BuildWarning[] = []\n /** 외부 패키지 이름 → 처음 import 한 파일 */\n const externals = new Map<string, string | undefined>()\n let output: readonly RolldownOutputItem[]\n try {\n ;({ output } = await rolldown.build({\n cwd,\n input,\n platform: \"node\",\n // 상대 · 절대 경로 · # (package.json imports) = 번들. 그 외 bare import = 외부 (도입 프로젝트 node_modules 에서 해석)\n external: (id: string, importer: string | undefined): boolean => {\n if (id.startsWith(\".\") || id.startsWith(\"#\") || id.startsWith(\"\\0\") || isAbsolute(id)) return false\n if (id.startsWith(\"node:\") || isBuiltin(id)) return true\n const pkg = packageName(id)\n if (!externals.has(pkg) && importer !== undefined && !importer.startsWith(\"\\0\")) externals.set(pkg, importer)\n return true\n },\n transform: { target: \"node22\" },\n logLevel: \"warn\",\n onLog: (_level: string, log: { message: string }) => warnings.push({ code: \"BUNDLER_WARNING\", message: log.message }),\n output: {\n dir: outDir,\n format: \"esm\",\n entryFileNames: \"[name].js\",\n chunkFileNames: \"chunks/[name]-[hash].js\",\n sourcemap: true,\n },\n }))\n } catch (error) {\n throw new MextBuildError([{ code: \"BUNDLE_FAILED\", message: error instanceof Error ? error.message : String(error) }])\n }\n\n const declared = declaredDependencies(cwd)\n for (const [pkg, importer] of externals) {\n if (declared.has(pkg)) continue\n const from = importer === undefined ? \"\" : ` (imported by ${toPosix(relative(cwd, importer))})`\n warnings.push({\n code: \"UNDECLARED_DEPENDENCY\",\n message: `\"${pkg}\" is not in package.json dependencies${from}. It stays external and must be installed where .mext/ runs`,\n })\n }\n\n const emitted = new Set(output.map((o) => o.fileName))\n for (const name of Object.keys(input)) {\n if (!emitted.has(`${name}.js`)) throw new Error(`mext build: rolldown did not emit ${name}.js`)\n }\n\n const base = buildManifest(registry)\n const hash = manifestHash(base.commands, {\n resources: resourceList.map((r) => r.uri),\n prompts: promptList.map((p) => ({ name: p.name, argsSchema: p.argsSchema })),\n })\n const version = mextVersion()\n const manifest: BuildManifest = {\n schemaVersion: MANIFEST_SCHEMA_VERSION,\n mextVersion: version,\n buildId: buildIdOf(version, hash, output),\n manifestHash: hash,\n tools: config.tools ?? \"execute\",\n ...(hasConfig ? { config: \"config.js\" } : {}),\n ...(hasInstrumentation ? { instrumentation: \"instrumentation.js\" } : {}),\n ...(base.description !== undefined ? { description: base.description } : {}),\n namespaces: base.namespaces,\n commands: base.commands.map((c) => {\n const expose = registry.commands.get(c.id)?.command.expose\n return { ...c, module: moduleOf.get(c.id)!, ...(expose ? { expose: { ...expose } as Record<string, boolean> } : {}) }\n }),\n ...(resourceList.length > 0\n ? { resources: resourceList.map((r) => ({ ...describeResource(r), module: resourceModuleOf.get(r.uri)! })) }\n : {}),\n ...(promptList.length > 0\n ? { prompts: promptList.map((p) => ({ ...describePrompt(p), module: promptModuleOf.get(p.name)! })) }\n : {}),\n ...(routes.routes.length > 0\n ? {\n routes: routes.routes\n .map((r) => ({ path: r.path, file: r.file, methods: r.methods, module: `${routeModuleName(r.file)}.js` }))\n .sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0)),\n }\n : {}),\n }\n\n const generated: Record<string, string> = {\n \"package.json\": `${JSON.stringify({ type: \"module\" }, null, 2)}\\n`,\n \"server.js\": SERVER_JS,\n \"handler.js\": HANDLER_JS,\n }\n const localBin = local ? { bin: local.bin, version: local.version ?? projectVersion(cwd) ?? \"0.0.0\" } : undefined\n if (localBin) {\n generated[LOCAL_BIN_FILE] = localBinJs({ ...localBin, ...(local?.errors !== undefined ? { errors: `${LOCAL_BIN_ERRORS}.js` } : {}) })\n const declaredBin = packageBin(cwd, localBin.bin)\n const expected = `${toPosix(relative(cwd, outDir))}/${LOCAL_BIN_FILE}`\n if (declaredBin === undefined || declaredBin.replace(/^\\.\\//, \"\") !== expected) {\n warnings.push({\n code: \"LOCAL_BIN_UNDECLARED\",\n message: `cli.local: add \"bin\": { \"${localBin.bin}\": \"${expected}\" } to package.json (and include ${toPosix(relative(cwd, outDir))} in \"files\")`,\n })\n }\n }\n for (const [file, content] of Object.entries(generated)) writeFileSync(join(outDir, file), content)\n if (localBin) chmodSync(join(outDir, LOCAL_BIN_FILE), 0o755)\n\n // 고객 CLI (.mext/cli/, §5): manifest · buildId 확정 후, manifest.json 쓰기 전. 로컬 bin 이면 만들지 않는다\n // 고객 CLI = 원격 실행의 기본 표면 (mcp) 에서 보이는 명령어 · 그 manifestHash (§4 expose). 숨긴 명령어가 없으면 manifest 그대로\n const mcpView = exposedRegistry(registry, \"mcp\")\n const cliManifest: BuildManifest =\n mcpView === registry\n ? manifest\n : {\n ...manifest,\n namespaces: buildManifest(mcpView).namespaces,\n commands: manifest.commands.filter((c) => mcpView.commands.has(c.id)),\n manifestHash: manifestHash(\n base.commands.filter((c) => mcpView.commands.has(c.id)),\n { resources: resourceList.map((r) => r.uri), prompts: promptList.map((p) => ({ name: p.name, argsSchema: p.argsSchema })) },\n ),\n }\n const cli = config.cli && !local ? await buildCustomerCli({ rolldown, cwd, outDir, cli: config.cli, manifest: cliManifest }) : undefined\n\n // manifest.json 은 마지막: 중간 실패한 빌드는 manifest 가 없어 mext start 가 \"mext build 먼저\" 로 거부\n writeFileSync(join(outDir, BUILD_MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}\\n`)\n\n // 명령어 타입 (specs/client.md §4): config.types 가 있을 때만. 산출 폴더 밖 (프로젝트 소스 옆) 에 쓴다\n const typesPath = resolveTypesPath(cwd, config.types)\n if (typesPath !== undefined) writeTypes(commandsDir, typesPath)\n\n const files = [\n ...emitted,\n ...Object.keys(generated),\n BUILD_MANIFEST_FILE,\n ...(cli?.files.map((f) => `${CLI_DIR}/${f}`) ?? []),\n ].sort()\n return {\n outDir,\n manifest,\n files,\n warnings,\n ...(cli ? { cli } : {}),\n ...(localBin ? { localBin } : {}),\n ...(typesPath !== undefined ? { types: typesPath } : {}),\n }\n}\n\n/**\n * .mext/bin.js (로컬 bin, cli.local). 계약: mainLocalBin(.mext 폴더 URL, { bin, version, errors? }).\n * 도입 프로젝트 package.json bin 이 이 파일을 가리킨다 (npm 이 symlink 해도 import.meta.url = 실제 경로)\n */\nexport function localBinJs(options: { bin: string; version: string; errors?: string }): string {\n return `#!/usr/bin/env node\n// Generated by mext build. Do not edit.\n// Local bin (cli.local): ${options.bin} help · ${options.bin} <namespace> <command> · ${options.bin} mcp serve\nimport { mainLocalBin } from \"${START_ENTRY}\"\n\nawait mainLocalBin(new URL(\".\", import.meta.url), ${JSON.stringify(options)})\n`\n}\n\n/** package.json bin[name] (문자열 bin = 패키지 이름이 name 일 때) */\nfunction packageBin(cwd: string, name: string): string | undefined {\n try {\n const pkg = JSON.parse(readFileSync(join(cwd, \"package.json\"), \"utf8\")) as { name?: unknown; bin?: unknown }\n if (typeof pkg.bin === \"string\") return pkg.name === name ? pkg.bin : undefined\n if (typeof pkg.bin === \"object\" && pkg.bin !== null) {\n const v = (pkg.bin as Record<string, unknown>)[name]\n return typeof v === \"string\" ? v : undefined\n }\n } catch {\n // package.json 없음 · 형식 오류 = 미선언\n }\n return undefined\n}\n\n/**\n * .mext/server.js. 계약: startFromBuild(.mext 폴더 URL, { argv, env }) → exit code.\n * argv = server.js 뒤 인자 (--stdio), env = PORT · HOST\n */\nexport const SERVER_JS = `// Generated by mext build. Do not edit.\n// node .mext/server.js [--stdio] (= mext start). Environment: PORT · HOST\nimport { startFromBuild } from \"${START_ENTRY}\"\n\nprocess.exitCode = await startFromBuild(new URL(\".\", import.meta.url), { argv: process.argv.slice(2), env: process.env })\n`\n\n/** .mext/handler.js. 계약: createFetchHandler(.mext 폴더 URL) → { fetch(request: Request): Promise<Response> } (동기 반환) */\nexport const HANDLER_JS = `// Generated by mext build. Do not edit.\n// Web fetch handler (Request → Response) for other runtimes and platforms\nimport { createFetchHandler } from \"${START_ENTRY}\"\n\nexport default createFetchHandler(new URL(\".\", import.meta.url))\n`\n\nasync function importRolldown(): Promise<RolldownModule> {\n // 문자열 변수: 타입 검사 · 번들러가 선택 peer 를 정적 의존으로 취급하지 않게\n const specifier = \"rolldown\"\n return (await import(specifier)) as RolldownModule\n}\n\nfunction isModuleNotFound(error: unknown, pkg: string): boolean {\n const e = error as { code?: unknown; message?: unknown } | null\n if (typeof e !== \"object\" || e === null) return false\n if (e.code !== \"ERR_MODULE_NOT_FOUND\" && e.code !== \"MODULE_NOT_FOUND\") return false\n return typeof e.message !== \"string\" || e.message.includes(`'${pkg}'`) || e.message.includes(`\"${pkg}\"`)\n}\n\n/** 도입 프로젝트의 lock 파일로 패키지 관리자 추정 */\nfunction installCommand(cwd: string): string {\n for (let dir = cwd; ; dir = resolve(dir, \"..\")) {\n if (existsSync(join(dir, \"pnpm-lock.yaml\"))) return \"pnpm add -D rolldown\"\n if (existsSync(join(dir, \"yarn.lock\"))) return \"yarn add -D rolldown\"\n if (existsSync(join(dir, \"bun.lock\")) || existsSync(join(dir, \"bun.lockb\"))) return \"bun add -d rolldown\"\n if (existsSync(join(dir, \"package-lock.json\")) || resolve(dir, \"..\") === dir) return \"npm install --save-dev rolldown\"\n }\n}\n\nfunction cleanOutDir(outDir: string): void {\n mkdirSync(outDir, { recursive: true })\n for (const name of readdirSync(outDir)) {\n if (!PRESERVED_ENTRIES.has(name)) rmSync(join(outDir, name), { recursive: true, force: true })\n }\n}\n\n/**\n * route 엔트리 이름 = routes/ 아래 소스 경로, [name] → _name_ (rolldown 이 [ ] 를 바꾸므로 직접 정한다).\n * `_` 접두 파일 · 폴더는 route 가 아니라 충돌 없음. routes/items/[id].ts → routes/items/_id_\n */\nfunction routeModuleName(file: string): string {\n return `routes/${file.replace(/\\.ts$/, \"\").replace(/\\[([^\\]/]+)\\]/g, \"_$1_\")}`\n}\n\n/** \"@scope/pkg/sub\" → \"@scope/pkg\" · \"pkg/sub\" → \"pkg\" */\nfunction packageName(specifier: string): string {\n const parts = specifier.split(\"/\")\n return specifier.startsWith(\"@\") ? parts.slice(0, 2).join(\"/\") : parts[0]!\n}\n\nfunction declaredDependencies(cwd: string): Set<string> {\n let pkg: Record<string, unknown>\n try {\n pkg = JSON.parse(readFileSync(join(cwd, \"package.json\"), \"utf8\")) as Record<string, unknown>\n } catch {\n return new Set()\n }\n const names = new Set<string>()\n if (typeof pkg.name === \"string\") names.add(pkg.name)\n for (const field of [\"dependencies\", \"peerDependencies\", \"optionalDependencies\"]) {\n const deps = pkg[field]\n if (typeof deps === \"object\" && deps !== null) for (const name of Object.keys(deps)) names.add(name)\n }\n return names\n}\n\n/** D3: mextVersion · manifestHash · 번들 chunk (파일 이름 · 코드) 의 sha256 앞 16자. 같은 입력 = 같은 buildId */\nfunction buildIdOf(version: string, hash: string, output: readonly RolldownOutputItem[]): string {\n const h = createHash(\"sha256\").update(`${version}\\n${hash}\\n`)\n for (const item of [...output].sort((a, b) => (a.fileName < b.fileName ? -1 : 1))) {\n if (item.type !== \"chunk\") continue\n h.update(`${item.fileName}\\0${item.code ?? \"\"}\\0`)\n }\n return h.digest(\"hex\").slice(0, 16)\n}\n\nfunction toPosix(path: string): string {\n return path.split(sep).join(\"/\")\n}\n"]}
@@ -0,0 +1,53 @@
1
+ import type { Transport } from "./instrumentation.ts";
2
+ import type { Actor, Principal } from "./principal.ts";
3
+ /**
4
+ * 호출자 맥락 (ctx.caller, spec §4). 서버가 정한 값 (surface · transport · actor) 과 자가 신고 값 (client) 을 나눈다.
5
+ * 권한 · 노출 판정에는 surface · actor 만 쓴다
6
+ */
7
+ /** 어댑터 기본 표면: mext run · 로컬 bin = cli, POST /mcp = mcp, stdio = stdio */
8
+ export type BuiltinSurface = "cli" | "mcp" | "stdio";
9
+ /** 논리 표면. 어댑터 기본 또는 auth · localPrincipal 이 principal.surface 로 정한 kebab-case 이름 (예: "web") */
10
+ export type Surface = BuiltinSurface | (string & {});
11
+ /**
12
+ * 클라이언트가 보낸 MCP clientInfo 그대로. 자가 신고 값이라 검증되지 않는다.
13
+ * 권한 · 노출 · 행위자 판정의 근거로 쓰지 않는다 (기록 · 표시용)
14
+ */
15
+ export interface ReportedClient {
16
+ name: string;
17
+ version?: string;
18
+ }
19
+ /** expose 의 기본값 키: 적지 않은 표면 전부 */
20
+ export declare const ANY_SURFACE = "*";
21
+ /**
22
+ * 표면별 노출 (defineCommand expose, spec §4). 키 = 논리 표면 (ctx.caller.surface 와 같은 값) 또는 "*" (적지 않은 표면 전부).
23
+ * 판정 = expose[surface] → expose["*"] → true.
24
+ * { mcp: false } 숨김 목록: mcp 에서만 숨긴다
25
+ * { "*": false, cli: true, web: true } 허용 목록: cli · web 에만 노출
26
+ */
27
+ export type Exposure = {
28
+ readonly [K in BuiltinSurface | typeof ANY_SURFACE]?: boolean;
29
+ } & {
30
+ readonly [surface: string]: boolean | undefined;
31
+ };
32
+ /** 표면에 노출되는지. expose 없음 = 모든 표면 노출 */
33
+ export declare function isExposedOn(expose: Exposure | undefined, surface: Surface): boolean;
34
+ /** defineCommand 의 expose 형식 문제. 없으면 undefined */
35
+ export declare function exposeProblem(value: unknown): string | undefined;
36
+ export interface Caller {
37
+ /** 논리 표면. principal.surface, 없으면 어댑터 기본 (cli · mcp · stdio) */
38
+ surface: Surface;
39
+ /** 핸들러를 실행한 어댑터. principal.surface 와 무관 */
40
+ transport: Transport;
41
+ /** principal.actor (auth · localPrincipal 이 정한 값). 없음 = 서버가 정하지 않음. mext 는 추정하지 않는다 */
42
+ actor?: Actor;
43
+ /** 자가 신고 (ReportedClient). HTTP 2025 요청 · 로컬 CLI = 없음 */
44
+ client?: ReportedClient;
45
+ }
46
+ /** 어댑터 기본 표면 */
47
+ export declare function defaultSurface(transport: Transport): BuiltinSurface;
48
+ /** 주체의 논리 표면: principal.surface, 없으면 어댑터 기본 */
49
+ export declare function surfaceOf(principal: Principal, transport: Transport): Surface;
50
+ /** ctx.caller. actor = principal.actor 만 (client 신고 값은 행위자를 정하지 않는다) */
51
+ export declare function callerOf(principal: Principal, transport: Transport, client?: ReportedClient): Caller;
52
+ /** 신고된 clientInfo → ReportedClient. name 이 문자열이 아니면 undefined, version 은 문자열일 때만 */
53
+ export declare function reportedClient(value: unknown): ReportedClient | undefined;
package/dist/caller.js ADDED
@@ -0,0 +1,51 @@
1
+ import { isSegment } from "./ids.js";
2
+ /** expose 의 기본값 키: 적지 않은 표면 전부 */
3
+ export const ANY_SURFACE = "*";
4
+ /** 표면에 노출되는지. expose 없음 = 모든 표면 노출 */
5
+ export function isExposedOn(expose, surface) {
6
+ if (expose === undefined)
7
+ return true;
8
+ if (Object.hasOwn(expose, surface))
9
+ return expose[surface] !== false;
10
+ return expose[ANY_SURFACE] !== false;
11
+ }
12
+ /** defineCommand 의 expose 형식 문제. 없으면 undefined */
13
+ export function exposeProblem(value) {
14
+ if (typeof value !== "object" || value === null || Array.isArray(value))
15
+ return 'expose must be an object (e.g. { mcp: false })';
16
+ for (const [key, exposed] of Object.entries(value)) {
17
+ if (key !== ANY_SURFACE && !isSegment(key))
18
+ return `expose key "${key}" must be a surface name (kebab-case) or "*"`;
19
+ if (typeof exposed !== "boolean")
20
+ return `expose.${key} must be a boolean`;
21
+ }
22
+ return undefined;
23
+ }
24
+ const DEFAULT_SURFACE = { local: "cli", http: "mcp", stdio: "stdio" };
25
+ /** 어댑터 기본 표면 */
26
+ export function defaultSurface(transport) {
27
+ return DEFAULT_SURFACE[transport];
28
+ }
29
+ /** 주체의 논리 표면: principal.surface, 없으면 어댑터 기본 */
30
+ export function surfaceOf(principal, transport) {
31
+ return principal.surface ?? defaultSurface(transport);
32
+ }
33
+ /** ctx.caller. actor = principal.actor 만 (client 신고 값은 행위자를 정하지 않는다) */
34
+ export function callerOf(principal, transport, client) {
35
+ return {
36
+ surface: surfaceOf(principal, transport),
37
+ transport,
38
+ ...(principal.actor !== undefined ? { actor: principal.actor } : {}),
39
+ ...(client !== undefined ? { client } : {}),
40
+ };
41
+ }
42
+ /** 신고된 clientInfo → ReportedClient. name 이 문자열이 아니면 undefined, version 은 문자열일 때만 */
43
+ export function reportedClient(value) {
44
+ if (typeof value !== "object" || value === null)
45
+ return undefined;
46
+ const { name, version } = value;
47
+ if (typeof name !== "string" || name === "")
48
+ return undefined;
49
+ return typeof version === "string" ? { name, version } : { name };
50
+ }
51
+ //# sourceMappingURL=caller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caller.js","sourceRoot":"","sources":["../src/caller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAwBpC,kCAAkC;AAClC,MAAM,CAAC,MAAM,WAAW,GAAG,GAAG,CAAA;AAU9B,sCAAsC;AACtC,MAAM,UAAU,WAAW,CAAC,MAA4B,EAAE,OAAgB;IACxE,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,IAAI,CAAA;IACrC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;QAAE,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,KAAK,CAAA;IACpE,OAAO,MAAM,CAAC,WAAW,CAAC,KAAK,KAAK,CAAA;AACtC,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,gDAAgD,CAAA;IAChI,KAAK,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACnD,IAAI,GAAG,KAAK,WAAW,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;YAAE,OAAO,eAAe,GAAG,8CAA8C,CAAA;QACnH,IAAI,OAAO,OAAO,KAAK,SAAS;YAAE,OAAO,UAAU,GAAG,oBAAoB,CAAA;IAC5E,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAaD,MAAM,eAAe,GAAgD,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAA;AAElH,gBAAgB;AAChB,MAAM,UAAU,cAAc,CAAC,SAAoB;IACjD,OAAO,eAAe,CAAC,SAAS,CAAC,CAAA;AACnC,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,SAAS,CAAC,SAAoB,EAAE,SAAoB;IAClE,OAAO,SAAS,CAAC,OAAO,IAAI,cAAc,CAAC,SAAS,CAAC,CAAA;AACvD,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,QAAQ,CAAC,SAAoB,EAAE,SAAoB,EAAE,MAAuB;IAC1F,OAAO;QACL,OAAO,EAAE,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC;QACxC,SAAS;QACT,GAAG,CAAC,SAAS,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5C,CAAA;AACH,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAA;IACjE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,KAA8C,CAAA;IACxE,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,SAAS,CAAA;IAC7D,OAAO,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAA;AACnE,CAAC","sourcesContent":["import { isSegment } from \"./ids.ts\"\nimport type { Transport } from \"./instrumentation.ts\"\nimport type { Actor, Principal } from \"./principal.ts\"\n\n/**\n * 호출자 맥락 (ctx.caller, spec §4). 서버가 정한 값 (surface · transport · actor) 과 자가 신고 값 (client) 을 나눈다.\n * 권한 · 노출 판정에는 surface · actor 만 쓴다\n */\n\n/** 어댑터 기본 표면: mext run · 로컬 bin = cli, POST /mcp = mcp, stdio = stdio */\nexport type BuiltinSurface = \"cli\" | \"mcp\" | \"stdio\"\n\n/** 논리 표면. 어댑터 기본 또는 auth · localPrincipal 이 principal.surface 로 정한 kebab-case 이름 (예: \"web\") */\nexport type Surface = BuiltinSurface | (string & {})\n\n/**\n * 클라이언트가 보낸 MCP clientInfo 그대로. 자가 신고 값이라 검증되지 않는다.\n * 권한 · 노출 · 행위자 판정의 근거로 쓰지 않는다 (기록 · 표시용)\n */\nexport interface ReportedClient {\n name: string\n version?: string\n}\n\n/** expose 의 기본값 키: 적지 않은 표면 전부 */\nexport const ANY_SURFACE = \"*\"\n\n/**\n * 표면별 노출 (defineCommand expose, spec §4). 키 = 논리 표면 (ctx.caller.surface 와 같은 값) 또는 \"*\" (적지 않은 표면 전부).\n * 판정 = expose[surface] → expose[\"*\"] → true.\n * { mcp: false } 숨김 목록: mcp 에서만 숨긴다\n * { \"*\": false, cli: true, web: true } 허용 목록: cli · web 에만 노출\n */\nexport type Exposure = { readonly [K in BuiltinSurface | typeof ANY_SURFACE]?: boolean } & { readonly [surface: string]: boolean | undefined }\n\n/** 표면에 노출되는지. expose 없음 = 모든 표면 노출 */\nexport function isExposedOn(expose: Exposure | undefined, surface: Surface): boolean {\n if (expose === undefined) return true\n if (Object.hasOwn(expose, surface)) return expose[surface] !== false\n return expose[ANY_SURFACE] !== false\n}\n\n/** defineCommand 의 expose 형식 문제. 없으면 undefined */\nexport function exposeProblem(value: unknown): string | undefined {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return 'expose must be an object (e.g. { mcp: false })'\n for (const [key, exposed] of Object.entries(value)) {\n if (key !== ANY_SURFACE && !isSegment(key)) return `expose key \"${key}\" must be a surface name (kebab-case) or \"*\"`\n if (typeof exposed !== \"boolean\") return `expose.${key} must be a boolean`\n }\n return undefined\n}\n\nexport interface Caller {\n /** 논리 표면. principal.surface, 없으면 어댑터 기본 (cli · mcp · stdio) */\n surface: Surface\n /** 핸들러를 실행한 어댑터. principal.surface 와 무관 */\n transport: Transport\n /** principal.actor (auth · localPrincipal 이 정한 값). 없음 = 서버가 정하지 않음. mext 는 추정하지 않는다 */\n actor?: Actor\n /** 자가 신고 (ReportedClient). HTTP 2025 요청 · 로컬 CLI = 없음 */\n client?: ReportedClient\n}\n\nconst DEFAULT_SURFACE: Readonly<Record<Transport, BuiltinSurface>> = { local: \"cli\", http: \"mcp\", stdio: \"stdio\" }\n\n/** 어댑터 기본 표면 */\nexport function defaultSurface(transport: Transport): BuiltinSurface {\n return DEFAULT_SURFACE[transport]\n}\n\n/** 주체의 논리 표면: principal.surface, 없으면 어댑터 기본 */\nexport function surfaceOf(principal: Principal, transport: Transport): Surface {\n return principal.surface ?? defaultSurface(transport)\n}\n\n/** ctx.caller. actor = principal.actor 만 (client 신고 값은 행위자를 정하지 않는다) */\nexport function callerOf(principal: Principal, transport: Transport, client?: ReportedClient): Caller {\n return {\n surface: surfaceOf(principal, transport),\n transport,\n ...(principal.actor !== undefined ? { actor: principal.actor } : {}),\n ...(client !== undefined ? { client } : {}),\n }\n}\n\n/** 신고된 clientInfo → ReportedClient. name 이 문자열이 아니면 undefined, version 은 문자열일 때만 */\nexport function reportedClient(value: unknown): ReportedClient | undefined {\n if (typeof value !== \"object\" || value === null) return undefined\n const { name, version } = value as { name?: unknown; version?: unknown }\n if (typeof name !== \"string\" || name === \"\") return undefined\n return typeof version === \"string\" ? { name, version } : { name }\n}\n"]}
package/dist/cli/build.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { relative } from "node:path";
2
2
  import { buildProject } from "../build.js";
3
+ import { runtimeExec } from "../runtime.js";
3
4
  import { table } from "./help.js";
4
5
  import { EXIT, exitCodeOf, formatError } from "./output.js";
5
6
  export const BUILD_PROG = "mext build";
@@ -45,7 +46,7 @@ export function formatBuildSummary(result, cwd) {
45
46
  ...(manifest.routes?.length
46
47
  ? [...table([["Route", "Methods"], ...manifest.routes.map((r) => [r.path, r.methods.join(" · ")])]).map((l) => ` ${l}`), ""]
47
48
  : []),
48
- `Start: node ${dir}/server.js [--stdio]`,
49
+ `Start: ${runtimeExec} ${dir}/server.js [--stdio]`,
49
50
  ];
50
51
  const cli = result.cli;
51
52
  if (cli) {
@@ -55,14 +56,16 @@ export function formatBuildSummary(result, cwd) {
55
56
  const local = result.localBin;
56
57
  if (local)
57
58
  lines.push(`Local bin: ${dir}/bin.js (bin ${local.bin}@${local.version}). Run: ${local.bin} help (after npm link · npm install -g)`);
59
+ if (result.types !== undefined)
60
+ lines.push(`Types: ${relative(cwd, result.types) || result.types} (createClient<Commands>() from "@obov/mext/client")`);
58
61
  return `${lines.join("\n")}\n`;
59
62
  }
60
- /** readOnly · destructive · confirm. 아무것도 없으면 write */
63
+ /** readOnly · destructive · confirm (조건식 = confirm?). 아무것도 없으면 write */
61
64
  function safetyOf(c) {
62
65
  const flags = [
63
66
  ...(c.readOnly ? ["readOnly"] : []),
64
67
  ...(c.destructive ? ["destructive"] : []),
65
- ...(c.requiresConfirmation ? ["confirm"] : []),
68
+ ...(c.requiresConfirmation ? ["confirm"] : c.needsApproval !== undefined ? ["confirm?"] : []),
66
69
  ];
67
70
  return flags.length === 0 ? "write" : flags.join(" · ");
68
71
  }
@@ -1 +1 @@
1
- {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/cli/build.ts"],"names":[],"mappings":"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","sourcesContent":["import { relative } from \"node:path\"\nimport { buildProject, type BuildOptions, type BuildResult } from \"../build.ts\"\nimport type { BuildManifestCommand } from \"../manifest.ts\"\nimport { table } from \"./help.ts\"\nimport type { CliIo } from \"./io.ts\"\nimport { EXIT, exitCodeOf, formatError } from \"./output.ts\"\n\nexport const BUILD_PROG = \"mext build\"\n\n/**\n * mext build: commands/ → .mext/. 경고 · 오류 = stderr, 성공 요약 · 명령어 표 = stdout.\n * 검증 오류는 MextBuildError 하나에 모아 한 번에 출력, exit 1\n */\nexport async function runBuild(argv: readonly string[], io: CliIo, options: Omit<BuildOptions, \"cwd\"> = {}): Promise<number> {\n for (const tok of argv) {\n if (tok === \"--help\" || tok === \"-h\") {\n io.stdout.write(buildHelp())\n return EXIT.ok\n }\n io.stderr.write(`error: unexpected argument \"${tok}\"\\nRun \"${BUILD_PROG} --help\" for usage.\\n`)\n return EXIT.usage\n }\n let result: BuildResult\n try {\n result = await buildProject({ ...options, cwd: io.cwd })\n } catch (error) {\n io.stderr.write(formatError(error, BUILD_PROG))\n return exitCodeOf(error)\n }\n for (const w of result.warnings) io.stderr.write(`warning: ${w.message}\\n`)\n io.stdout.write(formatBuildSummary(result, io.cwd))\n return EXIT.ok\n}\n\n/** 성공 요약 + 명령어 표 (ID · 안전성 · scopes), next build 의 route 표와 같은 역할 */\nexport function formatBuildSummary(result: BuildResult, cwd: string): string {\n const { manifest } = result\n const dir = relative(cwd, result.outDir) || \".\"\n const n = manifest.commands.length\n const lines = [\n `Built ${dir}/ (${n} command${n === 1 ? \"\" : \"s\"}, buildId ${manifest.buildId})`,\n \"\",\n ...table([\n [\"Command\", \"Safety\", \"Scopes\"],\n ...manifest.commands.map((c) => [c.id, safetyOf(c), c.scopes.join(\", \") || \"-\"]),\n ]).map((l) => ` ${l}`),\n \"\",\n ...(manifest.routes?.length\n ? [...table([[\"Route\", \"Methods\"], ...manifest.routes.map((r) => [r.path, r.methods.join(\" · \")])]).map((l) => ` ${l}`), \"\"]\n : []),\n `Start: node ${dir}/server.js [--stdio]`,\n ]\n const cli = result.cli\n if (cli) {\n const kb = (cli.size / 1024).toFixed(1)\n lines.push(\n `Customer CLI: ${dir}/cli/ (${cli.packageName}@${cli.version}, bin ${cli.bin}, ${cli.form}, ${kb} KB). Publish: npm publish ${dir}/cli`,\n )\n }\n const local = result.localBin\n if (local) lines.push(`Local bin: ${dir}/bin.js (bin ${local.bin}@${local.version}). Run: ${local.bin} help (after npm link · npm install -g)`)\n return `${lines.join(\"\\n\")}\\n`\n}\n\n/** readOnly · destructive · confirm. 아무것도 없으면 write */\nfunction safetyOf(c: BuildManifestCommand): string {\n const flags = [\n ...(c.readOnly ? [\"readOnly\"] : []),\n ...(c.destructive ? [\"destructive\"] : []),\n ...(c.requiresConfirmation ? [\"confirm\"] : []),\n ]\n return flags.length === 0 ? \"write\" : flags.join(\" · \")\n}\n\nexport function buildHelp(): string {\n const lines = [\n \"Build commands/ into .mext/ for production (mext start · node .mext/server.js).\",\n \"\",\n \"Usage:\",\n ` ${BUILD_PROG}`,\n \"\",\n \"Output (.mext/):\",\n ...table([\n [\"manifest.json\", \"schemaVersion · mextVersion · buildId · manifestHash · namespaces · commands · resources · prompts · routes (+ module)\"],\n [\"server.js\", \"node .mext/server.js [--stdio]. PORT · HOST environment variables\"],\n [\"handler.js\", \"export default { fetch(request) } (Web Request → Response)\"],\n [\"config.js\", \"mext.config.ts bundle (when present)\"],\n [\"instrumentation.js\", \"instrumentation.ts bundle (when present)\"],\n [\"commands/**/*.js\", \"one module per command\"],\n [\"resources/**/*.js\", \"one module per MCP resource (resources/, when present)\"],\n [\"prompts/**/*.js\", \"one module per MCP prompt (prompts/, when present)\"],\n [\"routes/**/*.js\", \"one module per HTTP route (routes/, when present)\"],\n [\"chunks/\", \"shared code\"],\n [\"cli/\", \"customer CLI npm package (when mext.config.ts has cli): package.json · bin.js · README.md\"],\n [\"bin.js\", \"local bin (cli.local: true, instead of cli/). package.json bin points here\"],\n [\"cli-errors.js\", \"cli.errors bundle for the local bin\"],\n ]).map((l) => ` ${l}`),\n \"\",\n \"Requires rolldown (npm install --save-dev rolldown). Package imports stay external.\",\n \"All validation errors are reported at once (exit 1).\",\n ]\n return `${lines.join(\"\\n\")}\\n`\n}\n"]}
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/cli/build.ts"],"names":[],"mappings":"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","sourcesContent":["import { relative } from \"node:path\"\nimport { buildProject, type BuildOptions, type BuildResult } from \"../build.ts\"\nimport type { BuildManifestCommand } from \"../manifest.ts\"\nimport { runtimeExec } from \"../runtime.ts\"\nimport { table } from \"./help.ts\"\nimport type { CliIo } from \"./io.ts\"\nimport { EXIT, exitCodeOf, formatError } from \"./output.ts\"\n\nexport const BUILD_PROG = \"mext build\"\n\n/**\n * mext build: commands/ → .mext/. 경고 · 오류 = stderr, 성공 요약 · 명령어 표 = stdout.\n * 검증 오류는 MextBuildError 하나에 모아 한 번에 출력, exit 1\n */\nexport async function runBuild(argv: readonly string[], io: CliIo, options: Omit<BuildOptions, \"cwd\"> = {}): Promise<number> {\n for (const tok of argv) {\n if (tok === \"--help\" || tok === \"-h\") {\n io.stdout.write(buildHelp())\n return EXIT.ok\n }\n io.stderr.write(`error: unexpected argument \"${tok}\"\\nRun \"${BUILD_PROG} --help\" for usage.\\n`)\n return EXIT.usage\n }\n let result: BuildResult\n try {\n result = await buildProject({ ...options, cwd: io.cwd })\n } catch (error) {\n io.stderr.write(formatError(error, BUILD_PROG))\n return exitCodeOf(error)\n }\n for (const w of result.warnings) io.stderr.write(`warning: ${w.message}\\n`)\n io.stdout.write(formatBuildSummary(result, io.cwd))\n return EXIT.ok\n}\n\n/** 성공 요약 + 명령어 표 (ID · 안전성 · scopes), next build 의 route 표와 같은 역할 */\nexport function formatBuildSummary(result: BuildResult, cwd: string): string {\n const { manifest } = result\n const dir = relative(cwd, result.outDir) || \".\"\n const n = manifest.commands.length\n const lines = [\n `Built ${dir}/ (${n} command${n === 1 ? \"\" : \"s\"}, buildId ${manifest.buildId})`,\n \"\",\n ...table([\n [\"Command\", \"Safety\", \"Scopes\"],\n ...manifest.commands.map((c) => [c.id, safetyOf(c), c.scopes.join(\", \") || \"-\"]),\n ]).map((l) => ` ${l}`),\n \"\",\n ...(manifest.routes?.length\n ? [...table([[\"Route\", \"Methods\"], ...manifest.routes.map((r) => [r.path, r.methods.join(\" · \")])]).map((l) => ` ${l}`), \"\"]\n : []),\n `Start: ${runtimeExec} ${dir}/server.js [--stdio]`,\n ]\n const cli = result.cli\n if (cli) {\n const kb = (cli.size / 1024).toFixed(1)\n lines.push(\n `Customer CLI: ${dir}/cli/ (${cli.packageName}@${cli.version}, bin ${cli.bin}, ${cli.form}, ${kb} KB). Publish: npm publish ${dir}/cli`,\n )\n }\n const local = result.localBin\n if (local) lines.push(`Local bin: ${dir}/bin.js (bin ${local.bin}@${local.version}). Run: ${local.bin} help (after npm link · npm install -g)`)\n if (result.types !== undefined) lines.push(`Types: ${relative(cwd, result.types) || result.types} (createClient<Commands>() from \"@obov/mext/client\")`)\n return `${lines.join(\"\\n\")}\\n`\n}\n\n/** readOnly · destructive · confirm (조건식 = confirm?). 아무것도 없으면 write */\nfunction safetyOf(c: BuildManifestCommand): string {\n const flags = [\n ...(c.readOnly ? [\"readOnly\"] : []),\n ...(c.destructive ? [\"destructive\"] : []),\n ...(c.requiresConfirmation ? [\"confirm\"] : c.needsApproval !== undefined ? [\"confirm?\"] : []),\n ]\n return flags.length === 0 ? \"write\" : flags.join(\" · \")\n}\n\nexport function buildHelp(): string {\n const lines = [\n \"Build commands/ into .mext/ for production (mext start · node .mext/server.js).\",\n \"\",\n \"Usage:\",\n ` ${BUILD_PROG}`,\n \"\",\n \"Output (.mext/):\",\n ...table([\n [\"manifest.json\", \"schemaVersion · mextVersion · buildId · manifestHash · namespaces · commands · resources · prompts · routes (+ module)\"],\n [\"server.js\", \"node .mext/server.js [--stdio]. PORT · HOST environment variables\"],\n [\"handler.js\", \"export default { fetch(request) } (Web Request → Response)\"],\n [\"config.js\", \"mext.config.ts bundle (when present)\"],\n [\"instrumentation.js\", \"instrumentation.ts bundle (when present)\"],\n [\"commands/**/*.js\", \"one module per command\"],\n [\"resources/**/*.js\", \"one module per MCP resource (resources/, when present)\"],\n [\"prompts/**/*.js\", \"one module per MCP prompt (prompts/, when present)\"],\n [\"routes/**/*.js\", \"one module per HTTP route (routes/, when present)\"],\n [\"chunks/\", \"shared code\"],\n [\"cli/\", \"customer CLI npm package (when mext.config.ts has cli): package.json · bin.js · README.md\"],\n [\"bin.js\", \"local bin (cli.local: true, instead of cli/). package.json bin points here\"],\n [\"cli-errors.js\", \"cli.errors bundle for the local bin\"],\n ]).map((l) => ` ${l}`),\n \"\",\n \"Requires rolldown (npm install --save-dev rolldown). Package imports stay external.\",\n \"All validation errors are reported at once (exit 1).\",\n ]\n return `${lines.join(\"\\n\")}\\n`\n}\n"]}
@@ -0,0 +1,25 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import type { AuditEvent } from "../audit.ts";
3
+ /**
4
+ * mext dev 의 감사 tap, 감독 프로세스 쪽 (spec §10 감사 tap): 자식이 넘긴 이벤트를 메모리에 보관하고
5
+ * dev 전용 endpoint 로 내보낸다. 디스크에 쓰지 않는다. mext dev (HTTP) 만 만든다
6
+ */
7
+ /** 감독 프로세스의 endpoint 경로. routes/ 는 `_` 접두 폴더를 건너뛰므로 이 경로를 만들 수 없다 */
8
+ export declare const DEV_AUDIT_PATH = "/__mext/dev/audit";
9
+ /** 보관하는 이벤트 수 */
10
+ export declare const DEV_AUDIT_LIMIT = 200;
11
+ /** endpoint 한 줄 */
12
+ export interface DevAuditLine {
13
+ /** 1부터 증가 (dev 실행 동안) */
14
+ seq: number;
15
+ event: AuditEvent;
16
+ }
17
+ export interface DevAuditHub {
18
+ push(event: AuditEvent): void;
19
+ /** DEV_AUDIT_PATH 요청이면 처리하고 true */
20
+ handle(req: IncomingMessage, res: ServerResponse): boolean;
21
+ close(): void;
22
+ }
23
+ /** 실행마다 새 토큰 (lock 파일의 auditToken) */
24
+ export declare function newAuditToken(): string;
25
+ export declare function createDevAuditHub(token: string): DevAuditHub;
@@ -0,0 +1,84 @@
1
+ import { randomBytes, timingSafeEqual } from "node:crypto";
2
+ /**
3
+ * mext dev 의 감사 tap, 감독 프로세스 쪽 (spec §10 감사 tap): 자식이 넘긴 이벤트를 메모리에 보관하고
4
+ * dev 전용 endpoint 로 내보낸다. 디스크에 쓰지 않는다. mext dev (HTTP) 만 만든다
5
+ */
6
+ /** 감독 프로세스의 endpoint 경로. routes/ 는 `_` 접두 폴더를 건너뛰므로 이 경로를 만들 수 없다 */
7
+ export const DEV_AUDIT_PATH = "/__mext/dev/audit";
8
+ /** 보관하는 이벤트 수 */
9
+ export const DEV_AUDIT_LIMIT = 200;
10
+ const KEEPALIVE_MS = 15_000;
11
+ const LOOPBACK = new Set(["localhost", "127.0.0.1", "[::1]"]);
12
+ /** 실행마다 새 토큰 (lock 파일의 auditToken) */
13
+ export function newAuditToken() {
14
+ return randomBytes(24).toString("base64url");
15
+ }
16
+ export function createDevAuditHub(token) {
17
+ const lines = [];
18
+ const streams = new Set();
19
+ let seq = 0;
20
+ const expected = Buffer.from(`Bearer ${token}`);
21
+ const authorized = (header) => {
22
+ const given = Buffer.from(header ?? "");
23
+ return given.length === expected.length && timingSafeEqual(given, expected);
24
+ };
25
+ const keepalive = setInterval(() => {
26
+ for (const res of streams)
27
+ res.write("\n");
28
+ }, KEEPALIVE_MS);
29
+ keepalive.unref();
30
+ return {
31
+ push(event) {
32
+ const line = { seq: ++seq, event };
33
+ lines.push(line);
34
+ if (lines.length > DEV_AUDIT_LIMIT)
35
+ lines.splice(0, lines.length - DEV_AUDIT_LIMIT);
36
+ const text = `${JSON.stringify(line)}\n`;
37
+ for (const res of streams)
38
+ res.write(text);
39
+ },
40
+ handle(req, res) {
41
+ const url = new URL(req.url ?? "/", "http://localhost");
42
+ if (url.pathname !== DEV_AUDIT_PATH)
43
+ return false;
44
+ req.resume();
45
+ const deny = (status, message, headers = {}) => {
46
+ res.writeHead(status, { "content-type": "application/json", "cache-control": "no-store", ...headers });
47
+ res.end(`${JSON.stringify({ error: message })}\n`);
48
+ return true;
49
+ };
50
+ if (req.method !== "GET")
51
+ return deny(405, "Method not allowed.", { allow: "GET" });
52
+ const origin = req.headers.origin;
53
+ if (origin !== undefined && origin !== "" && !loopbackOrigin(origin))
54
+ return deny(403, "Forbidden.");
55
+ if (!authorized(req.headers.authorization))
56
+ return deny(403, "Forbidden.");
57
+ const after = Number(url.searchParams.get("after") ?? 0);
58
+ res.writeHead(200, { "content-type": "application/x-ndjson", "cache-control": "no-store", "x-accel-buffering": "no" });
59
+ res.flushHeaders();
60
+ for (const line of lines)
61
+ if (!(line.seq <= after))
62
+ res.write(`${JSON.stringify(line)}\n`);
63
+ streams.add(res);
64
+ res.on("close", () => streams.delete(res));
65
+ return true;
66
+ },
67
+ close() {
68
+ clearInterval(keepalive);
69
+ for (const res of streams)
70
+ res.end();
71
+ streams.clear();
72
+ },
73
+ };
74
+ }
75
+ function loopbackOrigin(origin) {
76
+ try {
77
+ const url = new URL(origin);
78
+ return (url.protocol === "http:" || url.protocol === "https:") && LOOPBACK.has(url.hostname);
79
+ }
80
+ catch {
81
+ return false;
82
+ }
83
+ }
84
+ //# sourceMappingURL=dev-audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-audit.js","sourceRoot":"","sources":["../../src/cli/dev-audit.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomBytes, timingSafeEqual } from \"node:crypto\"\nimport type { IncomingMessage, ServerResponse } from \"node:http\"\nimport type { AuditEvent } from \"../audit.ts\"\n\n/**\n * mext dev 의 감사 tap, 감독 프로세스 쪽 (spec §10 감사 tap): 자식이 넘긴 이벤트를 메모리에 보관하고\n * dev 전용 endpoint 로 내보낸다. 디스크에 쓰지 않는다. mext dev (HTTP) 만 만든다\n */\n\n/** 감독 프로세스의 endpoint 경로. routes/ 는 `_` 접두 폴더를 건너뛰므로 이 경로를 만들 수 없다 */\nexport const DEV_AUDIT_PATH = \"/__mext/dev/audit\"\n/** 보관하는 이벤트 수 */\nexport const DEV_AUDIT_LIMIT = 200\nconst KEEPALIVE_MS = 15_000\nconst LOOPBACK = new Set([\"localhost\", \"127.0.0.1\", \"[::1]\"])\n\n/** endpoint 한 줄 */\nexport interface DevAuditLine {\n /** 1부터 증가 (dev 실행 동안) */\n seq: number\n event: AuditEvent\n}\n\nexport interface DevAuditHub {\n push(event: AuditEvent): void\n /** DEV_AUDIT_PATH 요청이면 처리하고 true */\n handle(req: IncomingMessage, res: ServerResponse): boolean\n close(): void\n}\n\n/** 실행마다 새 토큰 (lock 파일의 auditToken) */\nexport function newAuditToken(): string {\n return randomBytes(24).toString(\"base64url\")\n}\n\nexport function createDevAuditHub(token: string): DevAuditHub {\n const lines: DevAuditLine[] = []\n const streams = new Set<ServerResponse>()\n let seq = 0\n const expected = Buffer.from(`Bearer ${token}`)\n const authorized = (header: string | undefined): boolean => {\n const given = Buffer.from(header ?? \"\")\n return given.length === expected.length && timingSafeEqual(given, expected)\n }\n const keepalive = setInterval(() => {\n for (const res of streams) res.write(\"\\n\")\n }, KEEPALIVE_MS)\n keepalive.unref()\n\n return {\n push(event) {\n const line: DevAuditLine = { seq: ++seq, event }\n lines.push(line)\n if (lines.length > DEV_AUDIT_LIMIT) lines.splice(0, lines.length - DEV_AUDIT_LIMIT)\n const text = `${JSON.stringify(line)}\\n`\n for (const res of streams) res.write(text)\n },\n handle(req, res) {\n const url = new URL(req.url ?? \"/\", \"http://localhost\")\n if (url.pathname !== DEV_AUDIT_PATH) return false\n req.resume()\n const deny = (status: number, message: string, headers: Record<string, string> = {}): true => {\n res.writeHead(status, { \"content-type\": \"application/json\", \"cache-control\": \"no-store\", ...headers })\n res.end(`${JSON.stringify({ error: message })}\\n`)\n return true\n }\n if (req.method !== \"GET\") return deny(405, \"Method not allowed.\", { allow: \"GET\" })\n const origin = req.headers.origin\n if (origin !== undefined && origin !== \"\" && !loopbackOrigin(origin)) return deny(403, \"Forbidden.\")\n if (!authorized(req.headers.authorization)) return deny(403, \"Forbidden.\")\n const after = Number(url.searchParams.get(\"after\") ?? 0)\n res.writeHead(200, { \"content-type\": \"application/x-ndjson\", \"cache-control\": \"no-store\", \"x-accel-buffering\": \"no\" })\n res.flushHeaders()\n for (const line of lines) if (!(line.seq <= after)) res.write(`${JSON.stringify(line)}\\n`)\n streams.add(res)\n res.on(\"close\", () => streams.delete(res))\n return true\n },\n close() {\n clearInterval(keepalive)\n for (const res of streams) res.end()\n streams.clear()\n },\n }\n}\n\nfunction loopbackOrigin(origin: string): boolean {\n try {\n const url = new URL(origin)\n return (url.protocol === \"http:\" || url.protocol === \"https:\") && LOOPBACK.has(url.hostname)\n } catch {\n return false\n }\n}\n"]}
@@ -3,6 +3,8 @@ export interface DevLock {
3
3
  pid: number;
4
4
  url: string | null;
5
5
  startedAt: string;
6
+ /** 감사 tap endpoint 의 토큰 (spec §10). 이전 버전의 잠금 = 없음. 로그 · 오류 메시지에 출력하지 않는다 */
7
+ auditToken?: string;
6
8
  }
7
9
  /** <cwd>/.mext/dev/lock */
8
10
  export declare function devLockPath(cwd: string): string;
@@ -12,7 +14,7 @@ export declare function readDevLock(cwd: string): DevLock | undefined;
12
14
  * 잠금 획득 (O_EXCL 생성). 이미 살아 있는 다른 프로세스의 잠금 = { running }.
13
15
  * 죽은 pid · 깨진 파일 = 오래된 잠금으로 보고 교체
14
16
  */
15
- export declare function acquireDevLock(cwd: string, url?: string | null): {
17
+ export declare function acquireDevLock(cwd: string, url?: string | null, auditToken?: string): {
16
18
  acquired: DevLock;
17
19
  } | {
18
20
  running: DevLock;