@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
@@ -61,6 +61,11 @@ interface OtelTracer {
61
61
  }, context: unknown, fn: (span: OtelSpan) => T): T;
62
62
  }
63
63
  interface OtelSpan {
64
+ /** 없는 구현 (테스트 대역) 도 허용 */
65
+ spanContext?(): {
66
+ traceId?: unknown;
67
+ spanId?: unknown;
68
+ } | undefined;
64
69
  setAttribute(key: string, value: string): unknown;
65
70
  setStatus(status: {
66
71
  code: number;
@@ -79,6 +84,11 @@ export declare function loadProjectInstrumentation(cwd?: string, options?: LoadI
79
84
  * source 없음 = hooks 없이 span 만. 빌드 산출물 (.mext/server/instrumentation.js) 도 같은 함수.
80
85
  */
81
86
  export declare function loadInstrumentation(source?: string | URL | InstrumentationModule, options?: LoadInstrumentationOptions): Promise<Instrumentation>;
87
+ /** span 식별자 (감사 이벤트의 traceId · spanId, §11.1). 유효하지 않은 (전부 0) 값은 넘기지 않는다 */
88
+ export interface TraceIds {
89
+ traceId: string;
90
+ spanId?: string;
91
+ }
82
92
  export interface ObserveOptions {
83
93
  instrumentation?: Instrumentation;
84
94
  transport?: Transport;
@@ -91,13 +101,14 @@ export interface ObserveOptions {
91
101
  * 속성 = mext.command.id · mext.transport · mext.principal.kind. 인자 · 결과 · 토큰은 기록하지 않는다.
92
102
  * 실패: status ERROR + mext.error.code. 핸들러 예외만 recordException (MextError · CommandError 메시지는 입력 일부를 담을 수 있어 제외).
93
103
  * 취소 (signal abort · MRTR 대기) = status 없음.
104
+ * fn 인자 = span 의 traceId · spanId (span 없음 = undefined)
94
105
  */
95
- export declare function observeCommand<T>(command: string, options: ObserveOptions, signal: () => AbortSignal | undefined, fn: () => Promise<T>): Promise<T>;
106
+ export declare function observeCommand<T>(command: string, options: ObserveOptions, signal: () => AbortSignal | undefined, fn: (trace?: TraceIds) => Promise<T>): Promise<T>;
96
107
  /**
97
108
  * observeCommand 의 일반형 (자원 = `mext.resource <uri 템플릿>`, §12.3).
98
109
  * attributes 에 mext.transport · mext.principal.kind 를 더한다. 실패 · 취소 처리는 observeCommand 와 같다
99
110
  */
100
- export declare function observeSpan<T>(name: string, attributes: Record<string, string>, options: ObserveOptions, signal: () => AbortSignal | undefined, fn: () => Promise<T>): Promise<T>;
111
+ export declare function observeSpan<T>(name: string, attributes: Record<string, string>, options: ObserveOptions, signal: () => AbortSignal | undefined, fn: (trace?: TraceIds) => Promise<T>): Promise<T>;
101
112
  /**
102
113
  * 핸들러 예외 → onCommandError (await). MextError · CommandError · 취소 · MRTR 대기는 보고하지 않는다.
103
114
  * onCommandError 자체의 예외 = onerror (기본 stderr), 호출자에게 전파하지 않는다.
@@ -97,6 +97,7 @@ const TRACER_NAME = "@obov/mext";
97
97
  * 속성 = mext.command.id · mext.transport · mext.principal.kind. 인자 · 결과 · 토큰은 기록하지 않는다.
98
98
  * 실패: status ERROR + mext.error.code. 핸들러 예외만 recordException (MextError · CommandError 메시지는 입력 일부를 담을 수 있어 제외).
99
99
  * 취소 (signal abort · MRTR 대기) = status 없음.
100
+ * fn 인자 = span 의 traceId · spanId (span 없음 = undefined)
100
101
  */
101
102
  export function observeCommand(command, options, signal, fn) {
102
103
  return observeSpan(`mext.command ${command}`, { "mext.command.id": command }, options, signal, fn);
@@ -118,7 +119,7 @@ export function observeSpan(name, attributes, options, signal, fn) {
118
119
  const tracer = otel.trace.getTracer(TRACER_NAME);
119
120
  return tracer.startActiveSpan(name, { attributes: all }, parent, async (span) => {
120
121
  try {
121
- return await fn();
122
+ return await fn(traceIds(span));
122
123
  }
123
124
  catch (error) {
124
125
  if (!signal()?.aborted) {
@@ -139,6 +140,15 @@ export function observeSpan(name, attributes, options, signal, fn) {
139
140
  }
140
141
  });
141
142
  }
143
+ /** span 의 traceId · spanId. SDK 미등록 (non-recording span, 전부 0) · 형식 오류 = undefined */
144
+ function traceIds(span) {
145
+ const context = span.spanContext?.();
146
+ const traceId = context?.traceId;
147
+ if (typeof traceId !== "string" || traceId === "" || /^0+$/.test(traceId))
148
+ return undefined;
149
+ const spanId = context?.spanId;
150
+ return typeof spanId === "string" && spanId !== "" && !/^0+$/.test(spanId) ? { traceId, spanId } : { traceId };
151
+ }
142
152
  /**
143
153
  * 핸들러 예외 → onCommandError (await). MextError · CommandError · 취소 · MRTR 대기는 보고하지 않는다.
144
154
  * onCommandError 자체의 예외 = onerror (기본 stderr), 호출자에게 전파하지 않는다.
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentation.js","sourceRoot":"","sources":["../src/instrumentation.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\"\nimport { isAbsolute, join, resolve } from \"node:path\"\nimport { pathToFileURL } from \"node:url\"\nimport { isDeclaredError } from \"./errors.ts\"\nimport type { Principal } from \"./principal.ts\"\n\n/**\n * instrumentation.ts (프로젝트 루트, 선택) · OpenTelemetry span (§11).\n * register() = 프로세스당 1회, 첫 명령어 실행 전. onCommandError = 핸들러 예외 보고.\n * span = @opentelemetry/api (선택 peer) 가 있을 때만. 없으면 no-op (실패한 import 1회 캐시).\n */\n\nexport const INSTRUMENTATION_FILE = \"instrumentation.ts\"\n\n/** 핸들러를 실행한 어댑터. 원격 CLI 는 핸들러를 실행하지 않으므로 없다 */\nexport type Transport = \"http\" | \"stdio\" | \"local\"\n\nexport interface CommandErrorInfo {\n /** 정식 명령어 ID. 자원 핸들러 (read · list · complete) 오류 = 자원 uri (템플릿 원문), 프롬프트 핸들러 오류 = 프롬프트 이름 */\n command: string\n /** 자원 핸들러 오류일 때 자원 uri (템플릿 원문, §12.3) */\n resource?: string\n /** 프롬프트 핸들러 (render · complete) 오류일 때 프롬프트 이름 (§12.3) */\n prompt?: string\n transport: Transport\n /** scopes · claims 는 넘기지 않는다 */\n principal: { id: string; kind: Principal[\"kind\"] }\n}\n\n/** instrumentation.ts 의 export */\nexport interface InstrumentationModule {\n register?: () => unknown\n onCommandError?: (error: unknown, info: CommandErrorInfo) => unknown\n}\n\n/** 어댑터가 InvokeOptions.instrumentation 으로 넘기는 로드 결과 */\nexport interface Instrumentation {\n /** 핸들러 예외 (MextError 외, 취소 · MRTR 대기 제외). 자체 예외는 stderr 로 보고하고 응답은 바꾸지 않는다 */\n onCommandError?: (error: unknown, info: CommandErrorInfo) => unknown\n /** @opentelemetry/api. undefined = span 없음 */\n otel?: OtelApi\n /** onCommandError 의 예외 보고. 기본 stderr */\n onerror?: (error: unknown) => void\n}\n\nexport interface LoadInstrumentationOptions {\n /** @opentelemetry/api 로더 (테스트 주입). 기본 = 동적 import, 결과는 프로세스당 캐시 */\n importOtel?: () => Promise<unknown>\n onerror?: (error: unknown) => void\n}\n\n/** mext 가 쓰는 @opentelemetry/api 의 부분 (타입 의존 없이) */\nexport interface OtelApi {\n trace: { getTracer(name: string, version?: string): OtelTracer }\n context: { active(): unknown }\n propagation: { extract(context: unknown, carrier: unknown): unknown }\n SpanStatusCode: { ERROR: number }\n}\n\ninterface OtelTracer {\n startActiveSpan<T>(name: string, options: { attributes: Record<string, string> }, context: unknown, fn: (span: OtelSpan) => T): T\n}\n\ninterface OtelSpan {\n setAttribute(key: string, value: string): unknown\n setStatus(status: { code: number; message?: string }): unknown\n recordException(exception: unknown): unknown\n end(): void\n}\n\n/** cwd 의 instrumentation.ts 절대 경로. 없으면 undefined */\nexport function findInstrumentation(cwd: string = process.cwd()): string | undefined {\n const file = join(resolve(cwd), INSTRUMENTATION_FILE)\n return existsSync(file) ? file : undefined\n}\n\n/** findInstrumentation(cwd) → loadInstrumentation. mext dev · mext run (로컬) · stdio 용 */\nexport function loadProjectInstrumentation(\n cwd: string = process.cwd(),\n options: LoadInstrumentationOptions = {},\n): Promise<Instrumentation> {\n return loadInstrumentation(findInstrumentation(cwd), options)\n}\n\nconst loaded = new Map<string, Promise<InstrumentationModule>>()\nconst loadedModules = new WeakMap<object, Promise<InstrumentationModule>>()\n\n/**\n * instrumentation 모듈 (파일 경로 · URL · import 된 모듈) 을 프로세스당 1회 import 하고 register() 를 await.\n * 같은 모듈의 두 번째 호출 = register 재호출 없이 같은 hooks. register 실패 = reject (다음 호출에서 재시도).\n * source 없음 = hooks 없이 span 만. 빌드 산출물 (.mext/server/instrumentation.js) 도 같은 함수.\n */\nexport async function loadInstrumentation(\n source?: string | URL | InstrumentationModule,\n options: LoadInstrumentationOptions = {},\n): Promise<Instrumentation> {\n const [mod, otel] = await Promise.all([\n source === undefined ? Promise.resolve<InstrumentationModule>({}) : registerOnce(source),\n options.importOtel ? resolveOtel(options.importOtel) : defaultOtel(),\n ])\n return {\n ...(mod.onCommandError ? { onCommandError: mod.onCommandError } : {}),\n ...(otel ? { otel } : {}),\n ...(options.onerror ? { onerror: options.onerror } : {}),\n }\n}\n\nfunction registerOnce(source: string | URL | InstrumentationModule): Promise<InstrumentationModule> {\n if (typeof source === \"string\" || source instanceof URL) {\n const isPath = typeof source === \"string\" && (isAbsolute(source) || !/^[a-z][a-z0-9+.-]+:/i.test(source))\n const href = isPath ? pathToFileURL(resolve(source as string)).href : String(source)\n return memo(loaded, href, () => import(href).then((m: unknown) => register(m, href)))\n }\n return memo(loadedModules, source, () => register(source, \"instrumentation\"))\n}\n\nfunction memo<K>(\n cache: { get(k: K): Promise<InstrumentationModule> | undefined; set(k: K, v: Promise<InstrumentationModule>): unknown; delete(k: K): unknown },\n key: K,\n load: () => Promise<InstrumentationModule>,\n): Promise<InstrumentationModule> {\n let pending = cache.get(key)\n if (!pending) {\n pending = load().catch((error: unknown) => {\n cache.delete(key)\n throw error\n })\n cache.set(key, pending)\n }\n return pending\n}\n\nasync function register(value: unknown, label: string): Promise<InstrumentationModule> {\n const mod = (value ?? {}) as Record<string, unknown>\n for (const key of [\"register\", \"onCommandError\"]) {\n if (mod[key] !== undefined && typeof mod[key] !== \"function\") {\n throw new TypeError(`${label}: export ${key} must be a function`)\n }\n }\n const hooks = mod as InstrumentationModule\n await hooks.register?.()\n return hooks\n}\n\n/* @opentelemetry/api (선택 peer). 번들러가 해석 · 포함하지 않도록 specifier 는 변수 (R5) */\n\nconst OTEL_API = \"@opentelemetry/api\"\nlet otelDefault: Promise<OtelApi | undefined> | undefined\n\nfunction defaultOtel(): Promise<OtelApi | undefined> {\n otelDefault ??= resolveOtel(() => import(OTEL_API))\n return otelDefault\n}\n\nasync function resolveOtel(importer: () => Promise<unknown>): Promise<OtelApi | undefined> {\n try {\n const mod = (await importer()) as Partial<OtelApi> & { default?: Partial<OtelApi> }\n const api = mod.trace ? mod : mod.default\n return api?.trace && api.context && api.propagation && api.SpanStatusCode ? (api as OtelApi) : undefined\n } catch {\n return undefined\n }\n}\n\n/* invoke 에서 사용 */\n\nconst TRACER_NAME = \"@obov/mext\"\n\nexport interface ObserveOptions {\n instrumentation?: Instrumentation\n transport?: Transport\n principal: Principal\n /** W3C trace context carrier (MCP params._meta 의 traceparent · tracestate) */\n traceContext?: Record<string, unknown>\n}\n\n/**\n * 명령어 실행 1회를 `mext.command <id>` span 으로 감싼다 (otel 있을 때만, 없으면 fn 그대로).\n * 속성 = mext.command.id · mext.transport · mext.principal.kind. 인자 · 결과 · 토큰은 기록하지 않는다.\n * 실패: status ERROR + mext.error.code. 핸들러 예외만 recordException (MextError · CommandError 메시지는 입력 일부를 담을 수 있어 제외).\n * 취소 (signal abort · MRTR 대기) = status 없음.\n */\nexport function observeCommand<T>(\n command: string,\n options: ObserveOptions,\n signal: () => AbortSignal | undefined,\n fn: () => Promise<T>,\n): Promise<T> {\n return observeSpan(`mext.command ${command}`, { \"mext.command.id\": command }, options, signal, fn)\n}\n\n/**\n * observeCommand 의 일반형 (자원 = `mext.resource <uri 템플릿>`, §12.3).\n * attributes 에 mext.transport · mext.principal.kind 를 더한다. 실패 · 취소 처리는 observeCommand 와 같다\n */\nexport function observeSpan<T>(\n name: string,\n attributes: Record<string, string>,\n options: ObserveOptions,\n signal: () => AbortSignal | undefined,\n fn: () => Promise<T>,\n): Promise<T> {\n const otel = options.instrumentation?.otel\n if (!otel) return fn()\n const parent = options.traceContext ? otel.propagation.extract(otel.context.active(), options.traceContext) : otel.context.active()\n const all = {\n ...attributes,\n \"mext.transport\": options.transport ?? \"local\",\n \"mext.principal.kind\": options.principal.kind,\n }\n const tracer = otel.trace.getTracer(TRACER_NAME)\n return tracer.startActiveSpan(name, { attributes: all }, parent, async (span) => {\n try {\n return await fn()\n } catch (error) {\n if (!signal()?.aborted) {\n if (isDeclaredError(error)) {\n span.setAttribute(\"mext.error.code\", error.code)\n span.setStatus({ code: otel.SpanStatusCode.ERROR, message: error.code })\n } else {\n span.setAttribute(\"mext.error.code\", \"EXECUTION_ERROR\")\n span.recordException(error)\n span.setStatus({ code: otel.SpanStatusCode.ERROR, message: error instanceof Error ? error.message : String(error) })\n }\n }\n throw error\n } finally {\n span.end()\n }\n })\n}\n\n/**\n * 핸들러 예외 → onCommandError (await). MextError · CommandError · 취소 · MRTR 대기는 보고하지 않는다.\n * onCommandError 자체의 예외 = onerror (기본 stderr), 호출자에게 전파하지 않는다.\n */\nexport async function reportCommandError(\n error: unknown,\n command: string,\n options: ObserveOptions,\n signal: AbortSignal | undefined,\n extra: { resource?: string; prompt?: string } = {},\n): Promise<void> {\n const hook = options.instrumentation?.onCommandError\n if (!hook || isDeclaredError(error) || signal?.aborted) return\n const info: CommandErrorInfo = {\n command,\n ...extra,\n transport: options.transport ?? \"local\",\n principal: { id: options.principal.id, kind: options.principal.kind },\n }\n try {\n await hook(error, info)\n } catch (hookError) {\n const onerror = options.instrumentation?.onerror ?? defaultOnError\n try {\n onerror(hookError)\n } catch {\n // 보고는 응답을 바꾸지 않는다\n }\n }\n}\n\nfunction defaultOnError(error: unknown): void {\n const message = error instanceof Error ? (error.stack ?? error.message) : String(error)\n process.stderr.write(`mext: onCommandError threw: ${message}\\n`)\n}\n"]}
1
+ {"version":3,"file":"instrumentation.js","sourceRoot":"","sources":["../src/instrumentation.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\"\nimport { isAbsolute, join, resolve } from \"node:path\"\nimport { pathToFileURL } from \"node:url\"\nimport { isDeclaredError } from \"./errors.ts\"\nimport type { Principal } from \"./principal.ts\"\n\n/**\n * instrumentation.ts (프로젝트 루트, 선택) · OpenTelemetry span (§11).\n * register() = 프로세스당 1회, 첫 명령어 실행 전. onCommandError = 핸들러 예외 보고.\n * span = @opentelemetry/api (선택 peer) 가 있을 때만. 없으면 no-op (실패한 import 1회 캐시).\n */\n\nexport const INSTRUMENTATION_FILE = \"instrumentation.ts\"\n\n/** 핸들러를 실행한 어댑터. 원격 CLI 는 핸들러를 실행하지 않으므로 없다 */\nexport type Transport = \"http\" | \"stdio\" | \"local\"\n\nexport interface CommandErrorInfo {\n /** 정식 명령어 ID. 자원 핸들러 (read · list · complete) 오류 = 자원 uri (템플릿 원문), 프롬프트 핸들러 오류 = 프롬프트 이름 */\n command: string\n /** 자원 핸들러 오류일 때 자원 uri (템플릿 원문, §12.3) */\n resource?: string\n /** 프롬프트 핸들러 (render · complete) 오류일 때 프롬프트 이름 (§12.3) */\n prompt?: string\n transport: Transport\n /** scopes · claims 는 넘기지 않는다 */\n principal: { id: string; kind: Principal[\"kind\"] }\n}\n\n/** instrumentation.ts 의 export */\nexport interface InstrumentationModule {\n register?: () => unknown\n onCommandError?: (error: unknown, info: CommandErrorInfo) => unknown\n}\n\n/** 어댑터가 InvokeOptions.instrumentation 으로 넘기는 로드 결과 */\nexport interface Instrumentation {\n /** 핸들러 예외 (MextError 외, 취소 · MRTR 대기 제외). 자체 예외는 stderr 로 보고하고 응답은 바꾸지 않는다 */\n onCommandError?: (error: unknown, info: CommandErrorInfo) => unknown\n /** @opentelemetry/api. undefined = span 없음 */\n otel?: OtelApi\n /** onCommandError 의 예외 보고. 기본 stderr */\n onerror?: (error: unknown) => void\n}\n\nexport interface LoadInstrumentationOptions {\n /** @opentelemetry/api 로더 (테스트 주입). 기본 = 동적 import, 결과는 프로세스당 캐시 */\n importOtel?: () => Promise<unknown>\n onerror?: (error: unknown) => void\n}\n\n/** mext 가 쓰는 @opentelemetry/api 의 부분 (타입 의존 없이) */\nexport interface OtelApi {\n trace: { getTracer(name: string, version?: string): OtelTracer }\n context: { active(): unknown }\n propagation: { extract(context: unknown, carrier: unknown): unknown }\n SpanStatusCode: { ERROR: number }\n}\n\ninterface OtelTracer {\n startActiveSpan<T>(name: string, options: { attributes: Record<string, string> }, context: unknown, fn: (span: OtelSpan) => T): T\n}\n\ninterface OtelSpan {\n /** 없는 구현 (테스트 대역) 도 허용 */\n spanContext?(): { traceId?: unknown; spanId?: unknown } | undefined\n setAttribute(key: string, value: string): unknown\n setStatus(status: { code: number; message?: string }): unknown\n recordException(exception: unknown): unknown\n end(): void\n}\n\n/** cwd 의 instrumentation.ts 절대 경로. 없으면 undefined */\nexport function findInstrumentation(cwd: string = process.cwd()): string | undefined {\n const file = join(resolve(cwd), INSTRUMENTATION_FILE)\n return existsSync(file) ? file : undefined\n}\n\n/** findInstrumentation(cwd) → loadInstrumentation. mext dev · mext run (로컬) · stdio 용 */\nexport function loadProjectInstrumentation(\n cwd: string = process.cwd(),\n options: LoadInstrumentationOptions = {},\n): Promise<Instrumentation> {\n return loadInstrumentation(findInstrumentation(cwd), options)\n}\n\nconst loaded = new Map<string, Promise<InstrumentationModule>>()\nconst loadedModules = new WeakMap<object, Promise<InstrumentationModule>>()\n\n/**\n * instrumentation 모듈 (파일 경로 · URL · import 된 모듈) 을 프로세스당 1회 import 하고 register() 를 await.\n * 같은 모듈의 두 번째 호출 = register 재호출 없이 같은 hooks. register 실패 = reject (다음 호출에서 재시도).\n * source 없음 = hooks 없이 span 만. 빌드 산출물 (.mext/server/instrumentation.js) 도 같은 함수.\n */\nexport async function loadInstrumentation(\n source?: string | URL | InstrumentationModule,\n options: LoadInstrumentationOptions = {},\n): Promise<Instrumentation> {\n const [mod, otel] = await Promise.all([\n source === undefined ? Promise.resolve<InstrumentationModule>({}) : registerOnce(source),\n options.importOtel ? resolveOtel(options.importOtel) : defaultOtel(),\n ])\n return {\n ...(mod.onCommandError ? { onCommandError: mod.onCommandError } : {}),\n ...(otel ? { otel } : {}),\n ...(options.onerror ? { onerror: options.onerror } : {}),\n }\n}\n\nfunction registerOnce(source: string | URL | InstrumentationModule): Promise<InstrumentationModule> {\n if (typeof source === \"string\" || source instanceof URL) {\n const isPath = typeof source === \"string\" && (isAbsolute(source) || !/^[a-z][a-z0-9+.-]+:/i.test(source))\n const href = isPath ? pathToFileURL(resolve(source as string)).href : String(source)\n return memo(loaded, href, () => import(href).then((m: unknown) => register(m, href)))\n }\n return memo(loadedModules, source, () => register(source, \"instrumentation\"))\n}\n\nfunction memo<K>(\n cache: { get(k: K): Promise<InstrumentationModule> | undefined; set(k: K, v: Promise<InstrumentationModule>): unknown; delete(k: K): unknown },\n key: K,\n load: () => Promise<InstrumentationModule>,\n): Promise<InstrumentationModule> {\n let pending = cache.get(key)\n if (!pending) {\n pending = load().catch((error: unknown) => {\n cache.delete(key)\n throw error\n })\n cache.set(key, pending)\n }\n return pending\n}\n\nasync function register(value: unknown, label: string): Promise<InstrumentationModule> {\n const mod = (value ?? {}) as Record<string, unknown>\n for (const key of [\"register\", \"onCommandError\"]) {\n if (mod[key] !== undefined && typeof mod[key] !== \"function\") {\n throw new TypeError(`${label}: export ${key} must be a function`)\n }\n }\n const hooks = mod as InstrumentationModule\n await hooks.register?.()\n return hooks\n}\n\n/* @opentelemetry/api (선택 peer). 번들러가 해석 · 포함하지 않도록 specifier 는 변수 (R5) */\n\nconst OTEL_API = \"@opentelemetry/api\"\nlet otelDefault: Promise<OtelApi | undefined> | undefined\n\nfunction defaultOtel(): Promise<OtelApi | undefined> {\n otelDefault ??= resolveOtel(() => import(OTEL_API))\n return otelDefault\n}\n\nasync function resolveOtel(importer: () => Promise<unknown>): Promise<OtelApi | undefined> {\n try {\n const mod = (await importer()) as Partial<OtelApi> & { default?: Partial<OtelApi> }\n const api = mod.trace ? mod : mod.default\n return api?.trace && api.context && api.propagation && api.SpanStatusCode ? (api as OtelApi) : undefined\n } catch {\n return undefined\n }\n}\n\n/* invoke 에서 사용 */\n\nconst TRACER_NAME = \"@obov/mext\"\n\n/** span 식별자 (감사 이벤트의 traceId · spanId, §11.1). 유효하지 않은 (전부 0) 값은 넘기지 않는다 */\nexport interface TraceIds {\n traceId: string\n spanId?: string\n}\n\nexport interface ObserveOptions {\n instrumentation?: Instrumentation\n transport?: Transport\n principal: Principal\n /** W3C trace context carrier (MCP params._meta 의 traceparent · tracestate) */\n traceContext?: Record<string, unknown>\n}\n\n/**\n * 명령어 실행 1회를 `mext.command <id>` span 으로 감싼다 (otel 있을 때만, 없으면 fn 그대로).\n * 속성 = mext.command.id · mext.transport · mext.principal.kind. 인자 · 결과 · 토큰은 기록하지 않는다.\n * 실패: status ERROR + mext.error.code. 핸들러 예외만 recordException (MextError · CommandError 메시지는 입력 일부를 담을 수 있어 제외).\n * 취소 (signal abort · MRTR 대기) = status 없음.\n * fn 인자 = span 의 traceId · spanId (span 없음 = undefined)\n */\nexport function observeCommand<T>(\n command: string,\n options: ObserveOptions,\n signal: () => AbortSignal | undefined,\n fn: (trace?: TraceIds) => Promise<T>,\n): Promise<T> {\n return observeSpan(`mext.command ${command}`, { \"mext.command.id\": command }, options, signal, fn)\n}\n\n/**\n * observeCommand 의 일반형 (자원 = `mext.resource <uri 템플릿>`, §12.3).\n * attributes 에 mext.transport · mext.principal.kind 를 더한다. 실패 · 취소 처리는 observeCommand 와 같다\n */\nexport function observeSpan<T>(\n name: string,\n attributes: Record<string, string>,\n options: ObserveOptions,\n signal: () => AbortSignal | undefined,\n fn: (trace?: TraceIds) => Promise<T>,\n): Promise<T> {\n const otel = options.instrumentation?.otel\n if (!otel) return fn()\n const parent = options.traceContext ? otel.propagation.extract(otel.context.active(), options.traceContext) : otel.context.active()\n const all = {\n ...attributes,\n \"mext.transport\": options.transport ?? \"local\",\n \"mext.principal.kind\": options.principal.kind,\n }\n const tracer = otel.trace.getTracer(TRACER_NAME)\n return tracer.startActiveSpan(name, { attributes: all }, parent, async (span) => {\n try {\n return await fn(traceIds(span))\n } catch (error) {\n if (!signal()?.aborted) {\n if (isDeclaredError(error)) {\n span.setAttribute(\"mext.error.code\", error.code)\n span.setStatus({ code: otel.SpanStatusCode.ERROR, message: error.code })\n } else {\n span.setAttribute(\"mext.error.code\", \"EXECUTION_ERROR\")\n span.recordException(error)\n span.setStatus({ code: otel.SpanStatusCode.ERROR, message: error instanceof Error ? error.message : String(error) })\n }\n }\n throw error\n } finally {\n span.end()\n }\n })\n}\n\n/** span 의 traceId · spanId. SDK 미등록 (non-recording span, 전부 0) · 형식 오류 = undefined */\nfunction traceIds(span: OtelSpan): TraceIds | undefined {\n const context = span.spanContext?.()\n const traceId = context?.traceId\n if (typeof traceId !== \"string\" || traceId === \"\" || /^0+$/.test(traceId)) return undefined\n const spanId = context?.spanId\n return typeof spanId === \"string\" && spanId !== \"\" && !/^0+$/.test(spanId) ? { traceId, spanId } : { traceId }\n}\n\n/**\n * 핸들러 예외 → onCommandError (await). MextError · CommandError · 취소 · MRTR 대기는 보고하지 않는다.\n * onCommandError 자체의 예외 = onerror (기본 stderr), 호출자에게 전파하지 않는다.\n */\nexport async function reportCommandError(\n error: unknown,\n command: string,\n options: ObserveOptions,\n signal: AbortSignal | undefined,\n extra: { resource?: string; prompt?: string } = {},\n): Promise<void> {\n const hook = options.instrumentation?.onCommandError\n if (!hook || isDeclaredError(error) || signal?.aborted) return\n const info: CommandErrorInfo = {\n command,\n ...extra,\n transport: options.transport ?? \"local\",\n principal: { id: options.principal.id, kind: options.principal.kind },\n }\n try {\n await hook(error, info)\n } catch (hookError) {\n const onerror = options.instrumentation?.onerror ?? defaultOnError\n try {\n onerror(hookError)\n } catch {\n // 보고는 응답을 바꾸지 않는다\n }\n }\n}\n\nfunction defaultOnError(error: unknown): void {\n const message = error instanceof Error ? (error.stack ?? error.message) : String(error)\n process.stderr.write(`mext: onCommandError threw: ${message}\\n`)\n}\n"]}
package/dist/invoke.d.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  import * as z from "zod";
2
+ import { type ApprovalConfig } from "./approval.ts";
3
+ import { type AuditConfig } from "./audit.ts";
4
+ import { type ReportedClient } from "./caller.ts";
2
5
  import type { CommandContext, InputSchema, MextApp, ProgressUpdate } from "./command.ts";
3
6
  import { MextError } from "./errors.ts";
4
7
  import { type Instrumentation, type Transport } from "./instrumentation.ts";
@@ -34,25 +37,48 @@ export interface InvokeOptions {
34
37
  app?: MextApp;
35
38
  /** readOnly 명령어만 허용 (split 의 query 도구). 그 외 = PERMISSION_DENIED */
36
39
  readOnly?: boolean;
40
+ /**
41
+ * 응답을 기다리게 하지 않을 작업 (숨긴 명령어 호출 시도의 감사 전달, §11.1) 을 넘겨받는다. MCP 어댑터 = waitUntil 또는 그대로 둠.
42
+ * 없음 = invoke 가 끝까지 기다린다 (로컬 실행: 프로세스가 곧 끝난다)
43
+ */
44
+ background?: (work: Promise<void>) => void;
37
45
  /** loadInstrumentation 결과. onCommandError · mext.command span. 기본 = 없음 */
38
46
  instrumentation?: Instrumentation;
39
- /** 실행 어댑터 (onCommandError · span 속성). 기본 "local" */
47
+ /** 실행 어댑터 (onCommandError · span 속성 · ctx.caller.transport · 기본 표면). 기본 "local" */
40
48
  transport?: Transport;
49
+ /** 클라이언트가 신고한 clientInfo (ctx.caller.client). 자가 신고 값. 기본 = 없음 */
50
+ client?: ReportedClient;
41
51
  /** W3C trace context carrier (MCP params._meta 의 traceparent · tracestate). span 의 부모 */
42
52
  traceContext?: Record<string, unknown>;
43
53
  /** ctx.resourceUpdated (§12.5). 기본 = no-op */
44
54
  resourceUpdated?: (uri: string) => Promise<void>;
45
55
  /**
46
- * tasks 확장 (§12.6). 입력 검증 · 권한 · requiresConfirmation 통과 후 execute 직전에 호출.
56
+ * tasks 확장 (§12.6). 입력 검증 · 권한 · 승인 (§4) 통과 후 execute 직전에 호출.
47
57
  * 반환 = 분리 실행: invoke 는 handle 로 바로 resolve, execute 는 반환된 signal · ask · progress 로 계속 실행 후 settle.
48
58
  * undefined = 동기 실행 (지금과 같음). span · onCommandError 는 분리 실행 전체를 덮는다
49
59
  */
50
60
  detach?: (entry: RegisteredCommand) => Promise<DetachedExecution | undefined>;
61
+ /** 감사 (config.audit, §11.1). 없음 = 이벤트 없음 */
62
+ audit?: AuditConfig;
63
+ /** 승인의 표면별 확인 방식 (config.approval, §4 승인). 없음 = 모든 표면 ask */
64
+ approval?: ApprovalConfig;
65
+ /**
66
+ * 요청에 확인 표시가 실려 있음 (MCP params._meta["dev.mext/approval"] = { confirmed: true }). 클라이언트가 실은 값이다:
67
+ * client 방식 표면 + 서버가 정한 행위자 human 일 때만 인정한다. 기본 false
68
+ */
69
+ confirmed?: boolean;
70
+ /**
71
+ * 이 호출이 입력 대기로 끝났는지 (MRTR 라운드: 답 없는 ctx.ask 가 있어 결과를 버리고 InputRequiredResult 를 돌려준다).
72
+ * true = 감사 이벤트 없음 (답을 받아 끝난 라운드가 1건)
73
+ */
74
+ pendingInput?: () => boolean;
51
75
  }
52
76
  /** detach 의 반환. execute 의 ctx 를 요청과 분리한다 (R2: 응답 종료 ≠ 취소) */
53
77
  export interface DetachedExecution {
54
78
  /** invoke 결과의 detached (MCP = CreateTaskResult) */
55
79
  handle: unknown;
80
+ /** 감사 이벤트의 taskId (§11.1) */
81
+ taskId?: string;
56
82
  signal: AbortSignal;
57
83
  ask: AskHandler;
58
84
  progress: (update: ProgressUpdate) => void;
@@ -71,10 +97,11 @@ export interface InvokeResult {
71
97
  detached?: unknown;
72
98
  }
73
99
  /**
74
- * 어댑터 공통 실행기: ID 해석 (별칭 포함) → 권한 → (lazy 면 모듈 import) → Zod safeParse 1회 → 확인 (requiresConfirmation) → execute.
75
- * 실패는 MextError (UNKNOWN_COMMAND · PERMISSION_DENIED · INVALID_ARGUMENT · INPUT_UNAVAILABLE · INPUT_DECLINED).
100
+ * 어댑터 공통 실행기: ID 해석 (별칭 포함. 주체의 표면에서 숨긴 명령어 = 없는 ID, §4 expose) → 권한 → (lazy 면 모듈 import) → Zod safeParse 1회 → 가드 (authorize, §4) → 승인 (needsApproval · requiresConfirmation, §4) → execute.
101
+ * 실패는 MextError (UNKNOWN_COMMAND · PERMISSION_DENIED · INVALID_ARGUMENT · APPROVAL_REQUIRED · INPUT_UNAVAILABLE · INPUT_DECLINED).
76
102
  * 핸들러 예외는 그대로 전파 (instrumentation 있으면 onCommandError 보고 후).
77
103
  * instrumentation.otel 있으면 findCommand 뒤 전체를 `mext.command <id>` span 으로 감싼다.
104
+ * options.audit 있으면 호출 1건 = 감사 이벤트 1건 (§11.1. UNKNOWN_COMMAND · 입력 검증 실패 · 입력 대기 라운드 제외).
78
105
  */
79
106
  export declare function invoke(registry: Registry, id: string, rawInput: unknown, options: InvokeOptions): Promise<InvokeResult>;
80
107
  /** ID · 별칭 → 명령어. 없으면 UNKNOWN_COMMAND (suggested · usage). 구현 = lookup.ts (help · 고객 CLI 공용) */
@@ -96,7 +123,7 @@ export declare class OutputValidationError extends Error {
96
123
  export declare function createContext(entry: RegisteredCommand, options: InvokeOptions): CommandContext;
97
124
  /** ctx.resourceUpdated uri: 비어 있지 않은 문자열. 아니면 TypeError (핸들러 버그) */
98
125
  export declare function assertResourceUri(uri: unknown): asserts uri is string;
99
- /** requiresConfirmation 확인 문구. 검증된 입력을 포함 (무엇을 승인하는지) */
126
+ /** 승인 확인 문구 (ask 방식). 검증된 입력을 포함 (무엇을 승인하는지) */
100
127
  export declare function confirmationMessage(entry: RegisteredCommand, input: unknown): string;
101
128
  /** INVALID_ARGUMENT (missing_fields · issues · expected_schema · examples). 프롬프트 인자 (§12.3) 도 사용 */
102
129
  export declare function invalidArgument(command: string, raw: unknown, zodIssues: readonly z.core.$ZodIssue[], expectedSchema: JsonSchema, examples: unknown[]): MextError<"INVALID_ARGUMENT">;
package/dist/invoke.js CHANGED
@@ -1,47 +1,82 @@
1
1
  import * as z from "zod";
2
- import { inputDeclined, MextError } from "./errors.js";
2
+ import { approvalModeOf } from "./approval.js";
3
+ import { auditHidden, startAudit } from "./audit.js";
4
+ import { callerOf, surfaceOf } from "./caller.js";
5
+ import { approvalRequired, inputDeclined, isCommandError, isMextError, MextError } from "./errors.js";
6
+ import { exposedRegistry } from "./expose.js";
3
7
  import { observeCommand, reportCommandError } from "./instrumentation.js";
4
8
  import { findCommand } from "./lookup.js";
5
9
  import { hasScope } from "./principal.js";
6
- import { loadCommand } from "./registry.js";
10
+ import { loadCommand, resolveCommand } from "./registry.js";
7
11
  /**
8
- * 어댑터 공통 실행기: ID 해석 (별칭 포함) → 권한 → (lazy 면 모듈 import) → Zod safeParse 1회 → 확인 (requiresConfirmation) → execute.
9
- * 실패는 MextError (UNKNOWN_COMMAND · PERMISSION_DENIED · INVALID_ARGUMENT · INPUT_UNAVAILABLE · INPUT_DECLINED).
12
+ * 어댑터 공통 실행기: ID 해석 (별칭 포함. 주체의 표면에서 숨긴 명령어 = 없는 ID, §4 expose) → 권한 → (lazy 면 모듈 import) → Zod safeParse 1회 → 가드 (authorize, §4) → 승인 (needsApproval · requiresConfirmation, §4) → execute.
13
+ * 실패는 MextError (UNKNOWN_COMMAND · PERMISSION_DENIED · INVALID_ARGUMENT · APPROVAL_REQUIRED · INPUT_UNAVAILABLE · INPUT_DECLINED).
10
14
  * 핸들러 예외는 그대로 전파 (instrumentation 있으면 onCommandError 보고 후).
11
15
  * instrumentation.otel 있으면 findCommand 뒤 전체를 `mext.command <id>` span 으로 감싼다.
16
+ * options.audit 있으면 호출 1건 = 감사 이벤트 1건 (§11.1. UNKNOWN_COMMAND · 입력 검증 실패 · 입력 대기 라운드 제외).
12
17
  */
13
18
  export async function invoke(registry, id, rawInput, options) {
14
- const entry = findCommand(registry, id);
19
+ // expose (§4): 주체의 표면에서 보이는 명령어만. 숨긴 명령어 = UNKNOWN_COMMAND (없는 ID 와 같은 본문)
20
+ const view = exposedRegistry(registry, surfaceOf(options.principal, options.transport ?? "local"));
21
+ let entry;
22
+ try {
23
+ entry = findCommand(view, id);
24
+ }
25
+ catch (error) {
26
+ // 숨긴 명령어의 호출 시도 기록 (audit.includeHidden, §11.1). 응답 = 이 오류 그대로. 꺼져 있으면 찾지 않는다
27
+ if (options.audit?.includeHidden === true && view !== registry) {
28
+ const hidden = resolveCommand(registry, id);
29
+ const work = hidden && auditHidden(hidden, options);
30
+ if (work) {
31
+ if (options.background)
32
+ options.background(work);
33
+ else
34
+ await work;
35
+ }
36
+ }
37
+ throw error;
38
+ }
15
39
  // span 의 취소 판정 signal. 분리 실행 후 = task signal
16
40
  let signal = options.signal;
17
41
  let handoff;
18
42
  const handedOff = options.detach ? new Promise((resolve) => (handoff = resolve)) : undefined;
19
- const run = observeCommand(entry.id, options, () => signal, async () => {
43
+ // 감사 (§11.1). sink 없음 · 대상 아님 = undefined
44
+ const trail = startAudit(entry, options);
45
+ const body = async () => {
20
46
  authorize(entry, options.principal, { readOnly: options.readOnly });
21
47
  // lazy Registry (mext start) = 여기서 명령어 모듈 import. 권한 · ID 오류는 import 없이
22
48
  const command = await loadCommand(entry);
23
- const input = await parseInput(entry, rawInput);
49
+ let input;
50
+ try {
51
+ input = await parseInput(entry, rawInput);
52
+ }
53
+ catch (error) {
54
+ // 입력 검증 실패 = 감사 이벤트 없음
55
+ trail?.skip();
56
+ throw error;
57
+ }
58
+ trail?.validated(command, input);
24
59
  const ctx = createContext(entry, options);
25
60
  ctx.signal.throwIfAborted();
26
- if (entry.command.requiresConfirmation) {
27
- // 확인은 ctx.ask 경유 (CLI = 프롬프트 · --yes, MCP = MRTR). ask 미주입 = INPUT_UNAVAILABLE
28
- const confirmed = await ctx.ask({ kind: "confirm", message: confirmationMessage(entry, input) });
29
- if (!confirmed)
30
- throw inputDeclined(entry.id, "confirm");
31
- ctx.signal.throwIfAborted();
32
- }
61
+ // 가드 = 로드한 명령어의 authorize (lazy Registry 의 메타데이터 명령어에는 함수가 없다)
62
+ await guard(entry, command, input, ctx, options);
63
+ await approve(entry, command, input, ctx, options, trail);
33
64
  const detached = await options.detach?.(entry);
34
65
  if (detached) {
35
66
  signal = detached.signal;
36
67
  handoff({ command: entry.id, value: undefined, detached: detached.handle });
37
68
  const taskCtx = createContext(entry, { ...options, signal: detached.signal, ask: detached.ask, progress: detached.progress });
69
+ trail?.task(detached.taskId);
70
+ // 감사 = 분리 실행의 실제 종료 시점, task 결과 기록 (settle) 전
38
71
  try {
39
72
  const value = await parseOutput(entry.id, command, await command.execute(input, taskCtx));
73
+ await trail?.finish({ value }, false);
40
74
  await detached.settle({ value });
41
75
  return { command: entry.id, value };
42
76
  }
43
77
  catch (error) {
44
78
  await reportCommandError(error, entry.id, options, taskCtx.signal);
79
+ await trail?.finish({ error }, taskCtx.signal.aborted);
45
80
  await detached.settle({ error });
46
81
  throw error;
47
82
  }
@@ -54,7 +89,25 @@ export async function invoke(registry, id, rawInput, options) {
54
89
  await reportCommandError(error, entry.id, options, ctx.signal);
55
90
  throw error;
56
91
  }
57
- });
92
+ };
93
+ const run = observeCommand(entry.id, options, () => signal, !trail
94
+ ? body
95
+ : async (trace) => {
96
+ trail.trace(trace);
97
+ try {
98
+ const result = await body();
99
+ if (options.pendingInput?.())
100
+ trail.skip();
101
+ await trail.finish({ value: result.value }, false);
102
+ return result;
103
+ }
104
+ catch (error) {
105
+ if (options.pendingInput?.())
106
+ trail.skip();
107
+ await trail.finish({ error }, signal?.aborted === true);
108
+ throw error;
109
+ }
110
+ });
58
111
  // 분리 실행 = handoff 로 먼저 resolve. 이후 run 의 거부는 race 가 받는다 (미처리 거부 없음)
59
112
  return handedOff ? Promise.race([handedOff, run]) : run;
60
113
  }
@@ -81,6 +134,86 @@ export function authorize(entry, principal, options = {}) {
81
134
  if (missing.length > 0)
82
135
  deny("scope", `${entry.id} requires scopes: ${missing.join(", ")}.`);
83
136
  }
137
+ /**
138
+ * 실행 가드 (defineCommand authorize, §4). true 만 통과. 그 외 반환값 (undefined 포함) · 예외 = PERMISSION_DENIED (reason "authorize").
139
+ * CommandError = 그 message 로 거부. 그 외 예외 = 거부 + onCommandError 보고 (message 는 응답에 싣지 않는다).
140
+ * 취소 · mext 오류 (ctx.ask 의 INPUT_UNAVAILABLE 등) · 입력 대기 중의 예외는 바꾸지 않는다
141
+ */
142
+ async function guard(entry, command, input, ctx, options) {
143
+ if (!command.authorize)
144
+ return;
145
+ const denied = (message, cause) => {
146
+ const error = new MextError("PERMISSION_DENIED", message, {
147
+ command: entry.id,
148
+ reason: "authorize",
149
+ required_scopes: [...entry.command.scopes],
150
+ held_scopes: [...options.principal.scopes],
151
+ });
152
+ // 원인은 서버 쪽 디버깅용 (응답 본문 = toJSON 에는 없다)
153
+ if (cause !== undefined)
154
+ error.cause = cause;
155
+ return error;
156
+ };
157
+ let verdict;
158
+ try {
159
+ verdict = await command.authorize(input, ctx);
160
+ }
161
+ catch (error) {
162
+ if (ctx.signal.aborted || isMextError(error) || options.pendingInput?.())
163
+ throw error;
164
+ await reportCommandError(error, entry.id, options, ctx.signal);
165
+ throw denied(isCommandError(error) && error.message !== "" ? error.message : GUARD_DENIED(entry.id), error);
166
+ }
167
+ if (verdict !== true)
168
+ throw denied(GUARD_DENIED(entry.id));
169
+ }
170
+ /**
171
+ * 승인 (defineCommand needsApproval · requiresConfirmation, §4 승인). 승인이 필요한 호출을 표면의 확인 방식 한 곳에서 확인한다.
172
+ * 행위자 agent = 승인 불가 (APPROVAL_REQUIRED human_required). 묻지 않는다
173
+ * client 방식 표면 = 요청의 확인 표시 + 행위자 human 일 때만 통과. 묻지 않는다
174
+ * ask 방식 표면 (기본) = ctx.ask confirm (CLI = 프롬프트 · --yes, MCP = MRTR). ask 미주입 = INPUT_UNAVAILABLE. 확인 표시는 보지 않는다
175
+ * 승인 대상이 아닌 명령어 = 아무것도 하지 않는다
176
+ */
177
+ async function approve(entry, command, input, ctx, options, trail) {
178
+ if (!command.requiresConfirmation) {
179
+ if (!command.needsApproval)
180
+ return;
181
+ if (!(await approvalNeeded(entry, command, input, ctx, options))) {
182
+ trail?.approval({ required: false });
183
+ return;
184
+ }
185
+ }
186
+ const method = approvalModeOf(options.approval, ctx.caller.surface);
187
+ const actor = options.principal.actor?.kind;
188
+ trail?.approval({ required: true, method, confirmed: false });
189
+ if (actor === "agent" || (method === "client" && actor !== "human")) {
190
+ throw approvalRequired(entry.id, "human_required", { agent: actor === "agent" });
191
+ }
192
+ if (method === "client") {
193
+ if (options.confirmed !== true)
194
+ throw approvalRequired(entry.id, "unconfirmed");
195
+ }
196
+ else {
197
+ const confirmed = await ctx.ask({ kind: "confirm", message: confirmationMessage(entry, input) });
198
+ if (!confirmed)
199
+ throw inputDeclined(entry.id, "confirm");
200
+ ctx.signal.throwIfAborted();
201
+ }
202
+ trail?.approval({ required: true, method, confirmed: true });
203
+ }
204
+ /** needsApproval 조건식. false 만 승인 불필요. 그 외 반환값 · 예외 = 필요 (예외는 onCommandError 보고). 취소 · 입력 대기 중의 예외는 전파 */
205
+ async function approvalNeeded(entry, command, input, ctx, options) {
206
+ try {
207
+ return (await command.needsApproval(input, ctx)) !== false;
208
+ }
209
+ catch (error) {
210
+ if (ctx.signal.aborted || options.pendingInput?.())
211
+ throw error;
212
+ await reportCommandError(error, entry.id, options, ctx.signal);
213
+ return true;
214
+ }
215
+ }
216
+ const GUARD_DENIED = (id) => `${id} is not permitted for this caller.`;
84
217
  /** Zod safeParse 1회. 실패 = INVALID_ARGUMENT (missing_fields · issues · expected_schema · examples) */
85
218
  export async function parseInput(entry, rawInput) {
86
219
  const raw = rawInput === undefined ? {} : rawInput;
@@ -145,6 +278,7 @@ export function createContext(entry, options) {
145
278
  };
146
279
  return {
147
280
  principal: options.principal,
281
+ caller: callerOf(options.principal, options.transport ?? "local", options.client),
148
282
  signal: options.signal ?? new AbortController().signal,
149
283
  progress: options.progress ?? (() => { }),
150
284
  ask: ask,
@@ -168,7 +302,7 @@ function assertAskUrl(url) {
168
302
  throw new TypeError(`ctx.ask url must be an absolute http(s) URL: ${JSON.stringify(url)}`);
169
303
  }
170
304
  }
171
- /** requiresConfirmation 확인 문구. 검증된 입력을 포함 (무엇을 승인하는지) */
305
+ /** 승인 확인 문구 (ask 방식). 검증된 입력을 포함 (무엇을 승인하는지) */
172
306
  export function confirmationMessage(entry, input) {
173
307
  let args;
174
308
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"invoke.js","sourceRoot":"","sources":["../src/invoke.ts"],"names":[],"mappings":"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","sourcesContent":["import * as z from \"zod\"\nimport type { Ask, AskRequest, Command, CommandContext, InputSchema, MextApp, ProgressUpdate } from \"./command.ts\"\nimport { inputDeclined, MextError, type ArgumentIssue } from \"./errors.ts\"\nimport { observeCommand, reportCommandError, type Instrumentation, type Transport } from \"./instrumentation.ts\"\nimport { findCommand } from \"./lookup.ts\"\nimport { hasScope, type Principal } from \"./principal.ts\"\nimport { loadCommand, type JsonSchema, type RegisteredCommand, type Registry } from \"./registry.ts\"\n\n/** 어댑터가 주입하는 ctx.ask 구현. command = 정식 ID */\nexport type AskHandler = (request: AskHandlerRequest) => Promise<unknown>\n\nexport type AskHandlerRequest =\n | { command: string; kind: \"confirm\"; message: string }\n | { command: string; kind: \"input\"; message: string; schema: InputSchema; requestedSchema: JsonSchema }\n | { command: string; kind: \"url\"; message: string; url: string }\n\nexport interface InvokeOptions {\n principal: Principal\n /** 기본 = abort 되지 않는 signal */\n signal?: AbortSignal\n /** 기본 = 무시 */\n progress?: (update: ProgressUpdate) => void\n /** 기본 = ctx.ask 호출 시 INPUT_UNAVAILABLE */\n ask?: AskHandler\n app?: MextApp\n /** readOnly 명령어만 허용 (split 의 query 도구). 그 외 = PERMISSION_DENIED */\n readOnly?: boolean\n /** loadInstrumentation 결과. onCommandError · mext.command span. 기본 = 없음 */\n instrumentation?: Instrumentation\n /** 실행 어댑터 (onCommandError · span 속성). 기본 \"local\" */\n transport?: Transport\n /** W3C trace context carrier (MCP params._meta 의 traceparent · tracestate). span 의 부모 */\n traceContext?: Record<string, unknown>\n /** ctx.resourceUpdated (§12.5). 기본 = no-op */\n resourceUpdated?: (uri: string) => Promise<void>\n /**\n * tasks 확장 (§12.6). 입력 검증 · 권한 · requiresConfirmation 통과 후 execute 직전에 호출.\n * 반환 = 분리 실행: invoke 는 handle 로 바로 resolve, execute 는 반환된 signal · ask · progress 로 계속 실행 후 settle.\n * undefined = 동기 실행 (지금과 같음). span · onCommandError 는 분리 실행 전체를 덮는다\n */\n detach?: (entry: RegisteredCommand) => Promise<DetachedExecution | undefined>\n}\n\n/** detach 의 반환. execute 의 ctx 를 요청과 분리한다 (R2: 응답 종료 ≠ 취소) */\nexport interface DetachedExecution {\n /** invoke 결과의 detached (MCP = CreateTaskResult) */\n handle: unknown\n signal: AbortSignal\n ask: AskHandler\n progress: (update: ProgressUpdate) => void\n /** execute 종료. 값 = output 검증 후, 예외 = onCommandError 보고 후. 거부하지 않는다 */\n settle(outcome: { value: unknown } | { error: unknown }): Promise<void>\n}\n\nexport interface InvokeResult {\n /** 정식 ID (별칭으로 호출해도) */\n command: string\n value: unknown\n /** detach 로 분리 실행됨: DetachedExecution.handle (value 는 undefined) */\n detached?: unknown\n}\n\n/**\n * 어댑터 공통 실행기: ID 해석 (별칭 포함) → 권한 → (lazy 면 모듈 import) → Zod safeParse 1회 → 확인 (requiresConfirmation) → execute.\n * 실패는 MextError (UNKNOWN_COMMAND · PERMISSION_DENIED · INVALID_ARGUMENT · INPUT_UNAVAILABLE · INPUT_DECLINED).\n * 핸들러 예외는 그대로 전파 (instrumentation 있으면 onCommandError 보고 후).\n * instrumentation.otel 있으면 findCommand 뒤 전체를 `mext.command <id>` span 으로 감싼다.\n */\nexport async function invoke(\n registry: Registry,\n id: string,\n rawInput: unknown,\n options: InvokeOptions,\n): Promise<InvokeResult> {\n const entry = findCommand(registry, id)\n // span 의 취소 판정 signal. 분리 실행 후 = task signal\n let signal = options.signal\n let handoff: ((result: InvokeResult) => void) | undefined\n const handedOff = options.detach ? new Promise<InvokeResult>((resolve) => (handoff = resolve)) : undefined\n const run = observeCommand(entry.id, options, () => signal, async () => {\n authorize(entry, options.principal, { readOnly: options.readOnly })\n // lazy Registry (mext start) = 여기서 명령어 모듈 import. 권한 · ID 오류는 import 없이\n const command = await loadCommand(entry)\n const input = await parseInput(entry, rawInput)\n const ctx = createContext(entry, options)\n ctx.signal.throwIfAborted()\n if (entry.command.requiresConfirmation) {\n // 확인은 ctx.ask 경유 (CLI = 프롬프트 · --yes, MCP = MRTR). ask 미주입 = INPUT_UNAVAILABLE\n const confirmed = await ctx.ask({ kind: \"confirm\", message: confirmationMessage(entry, input) })\n if (!confirmed) throw inputDeclined(entry.id, \"confirm\")\n ctx.signal.throwIfAborted()\n }\n const detached = await options.detach?.(entry)\n if (detached) {\n signal = detached.signal\n handoff!({ command: entry.id, value: undefined, detached: detached.handle })\n const taskCtx = createContext(entry, { ...options, signal: detached.signal, ask: detached.ask, progress: detached.progress })\n try {\n const value = await parseOutput(entry.id, command, await command.execute(input, taskCtx))\n await detached.settle({ value })\n return { command: entry.id, value }\n } catch (error) {\n await reportCommandError(error, entry.id, options, taskCtx.signal)\n await detached.settle({ error })\n throw error\n }\n }\n try {\n const value = await parseOutput(entry.id, command, await command.execute(input, ctx))\n return { command: entry.id, value }\n } catch (error) {\n await reportCommandError(error, entry.id, options, ctx.signal)\n throw error\n }\n })\n // 분리 실행 = handoff 로 먼저 resolve. 이후 run 의 거부는 race 가 받는다 (미처리 거부 없음)\n return handedOff ? Promise.race([handedOff, run]) : run\n}\n\n/** ID · 별칭 → 명령어. 없으면 UNKNOWN_COMMAND (suggested · usage). 구현 = lookup.ts (help · 고객 CLI 공용) */\nexport { findCommand }\n\n/**\n * 안전성 메타데이터를 주체에 대해 강제.\n * readOnly 전용 호출 = readOnly 명령어만 · anonymous = readOnly 명령어만 · command.scopes 전부 보유 (\"*\" = 전체).\n */\nexport function authorize(entry: RegisteredCommand, principal: Principal, options: { readOnly?: boolean } = {}): void {\n const c = entry.command\n const deny = (reason: \"anonymous\" | \"read_only\" | \"scope\", message: string): never =>\n throwError(\n new MextError(\"PERMISSION_DENIED\", message, {\n command: entry.id,\n reason,\n required_scopes: [...c.scopes],\n held_scopes: [...principal.scopes],\n }),\n )\n if (options.readOnly && !c.readOnly) deny(\"read_only\", `${entry.id} is not read-only and cannot run here.`)\n if (principal.kind === \"anonymous\" && !c.readOnly) {\n deny(\"anonymous\", `${entry.id} is not read-only and requires an authenticated principal.`)\n }\n const missing = c.scopes.filter((s) => !hasScope(principal, s))\n if (missing.length > 0) deny(\"scope\", `${entry.id} requires scopes: ${missing.join(\", \")}.`)\n}\n\n/** Zod safeParse 1회. 실패 = INVALID_ARGUMENT (missing_fields · issues · expected_schema · examples) */\nexport async function parseInput(entry: RegisteredCommand, rawInput: unknown): Promise<z.output<InputSchema>> {\n const raw = rawInput === undefined ? {} : rawInput\n const result = await (await loadCommand(entry)).input.safeParseAsync(raw)\n if (result.success) return result.data\n throw invalidArgument(entry.id, raw, result.error.issues, entry.inputSchema, [...entry.command.examples])\n}\n\n/**\n * output 이 있으면 반환값 safeParse (모든 어댑터 · 노출 방식, §12.2). 결과 = 파싱된 값 (outputSchema 와 같은 모양).\n * 실패 = OutputValidationError (핸들러 예외와 같이 EXECUTION_ERROR · onCommandError 보고). 던진 오류는 검증하지 않는다\n */\nasync function parseOutput(id: string, command: Command, value: unknown): Promise<unknown> {\n if (!command.output) return value\n const result = await command.output.safeParseAsync(value)\n if (result.success) return result.data\n const summary = result.error.issues\n .map((i) => (i.path.length > 0 ? `${i.path.map(String).join(\".\")}: ${i.message}` : i.message))\n .join(\"; \")\n throw new OutputValidationError(`${id} returned a value that does not match its output schema: ${summary}`)\n}\n\n/** output 검증 실패. MextError 가 아님 = 응답 EXECUTION_ERROR (message 만) · onCommandError 보고 */\nexport class OutputValidationError extends Error {\n constructor(message: string) {\n super(message)\n this.name = \"OutputValidationError\"\n }\n}\n\n/** ctx 생성. ask · progress · signal 은 어댑터 주입 */\nexport function createContext(entry: RegisteredCommand, options: InvokeOptions): CommandContext {\n const handler = options.ask\n const ask = async (request: AskRequest): Promise<unknown> => {\n // url 형식 오류 = 핸들러 버그 (TypeError → EXECUTION_ERROR). 실행 환경과 무관하게 먼저 검사\n if (request.kind === \"url\") assertAskUrl(request.url)\n if (!handler) {\n throw new MextError(\"INPUT_UNAVAILABLE\", `${entry.id} requested input, but this environment cannot ask.`, {\n command: entry.id,\n ...(request.kind === \"url\" ? { url: request.url } : {}),\n })\n }\n if (request.kind === \"confirm\") {\n return (await handler({ command: entry.id, kind: \"confirm\", message: request.message })) === true\n }\n if (request.kind === \"url\") {\n return (await handler({ command: entry.id, kind: \"url\", message: request.message, url: request.url })) === true\n }\n const requestedSchema = z.toJSONSchema(request.schema, { target: \"draft-2020-12\", io: \"input\" }) as JsonSchema\n const response = await handler({\n command: entry.id,\n kind: \"input\",\n message: request.message,\n schema: request.schema,\n requestedSchema,\n })\n const parsed = await request.schema.safeParseAsync(response)\n if (parsed.success) return parsed.data\n throw invalidArgument(entry.id, response, parsed.error.issues, requestedSchema, [])\n }\n return {\n principal: options.principal,\n signal: options.signal ?? new AbortController().signal,\n progress: options.progress ?? (() => {}),\n ask: ask as Ask,\n app: options.app ?? ({} as MextApp),\n resourceUpdated: options.resourceUpdated ?? noResourceUpdates,\n }\n}\n\n/** state 없는 실행 (로컬 CLI · stateless 서버). uri 형식 오류만 TypeError */\nasync function noResourceUpdates(uri: string): Promise<void> {\n assertResourceUri(uri)\n}\n\n/** ctx.resourceUpdated uri: 비어 있지 않은 문자열. 아니면 TypeError (핸들러 버그) */\nexport function assertResourceUri(uri: unknown): asserts uri is string {\n if (typeof uri !== \"string\" || uri === \"\") throw new TypeError(`resourceUpdated uri must be a non-empty string: ${JSON.stringify(uri)}`)\n}\n\n/** ctx.ask url: http(s) 절대 URL. 아니면 TypeError */\nfunction assertAskUrl(url: unknown): asserts url is string {\n const parsed = typeof url === \"string\" && URL.canParse(url) ? new URL(url) : undefined\n if (parsed?.protocol !== \"http:\" && parsed?.protocol !== \"https:\") {\n throw new TypeError(`ctx.ask url must be an absolute http(s) URL: ${JSON.stringify(url)}`)\n }\n}\n\n/** requiresConfirmation 확인 문구. 검증된 입력을 포함 (무엇을 승인하는지) */\nexport function confirmationMessage(entry: RegisteredCommand, input: unknown): string {\n let args: string\n try {\n args = JSON.stringify(input) ?? \"{}\"\n } catch {\n args = \"{}\"\n }\n return `Run ${entry.id} with ${args}?${entry.command.destructive ? \" This command is destructive.\" : \"\"}`\n}\n\n/** INVALID_ARGUMENT (missing_fields · issues · expected_schema · examples). 프롬프트 인자 (§12.3) 도 사용 */\nexport function invalidArgument(\n command: string,\n raw: unknown,\n zodIssues: readonly z.core.$ZodIssue[],\n expectedSchema: JsonSchema,\n examples: unknown[],\n): MextError<\"INVALID_ARGUMENT\"> {\n const issues: ArgumentIssue[] = zodIssues.map((i) => ({\n path: i.path.map(String).join(\".\"),\n code: i.code,\n message: i.message,\n }))\n const missing = new Set<string>()\n for (const i of zodIssues) {\n if (i.code === \"invalid_type\" && i.path.length > 0 && isAbsent(raw, i.path)) missing.add(i.path.map(String).join(\".\"))\n }\n const missing_fields = [...missing]\n const summary =\n missing_fields.length > 0\n ? `missing required: ${missing_fields.join(\", \")}`\n : issues.map((i) => (i.path ? `${i.path}: ${i.message}` : i.message)).join(\"; \")\n return new MextError(\"INVALID_ARGUMENT\", `Invalid arguments for ${command}: ${summary}`, {\n command,\n missing_fields,\n issues,\n expected_schema: expectedSchema,\n examples,\n })\n}\n\n/** 원본 입력에 경로가 없는지 (값 undefined 포함) */\nfunction isAbsent(raw: unknown, path: readonly PropertyKey[]): boolean {\n let cur: unknown = raw\n for (const key of path) {\n if (cur === null || typeof cur !== \"object\") return true\n cur = (cur as Record<PropertyKey, unknown>)[key]\n if (cur === undefined) return true\n }\n return false\n}\n\nfunction throwError(error: MextError): never {\n throw error\n}\n"]}
1
+ {"version":3,"file":"invoke.js","sourceRoot":"","sources":["../src/invoke.ts"],"names":[],"mappings":"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","sourcesContent":["import * as z from \"zod\"\nimport { approvalModeOf, type ApprovalConfig } from \"./approval.ts\"\nimport { auditHidden, startAudit, type AuditConfig, type AuditTrail } from \"./audit.ts\"\nimport { callerOf, surfaceOf, type ReportedClient } from \"./caller.ts\"\nimport type { Ask, AskRequest, Command, CommandContext, InputSchema, MextApp, ProgressUpdate } from \"./command.ts\"\nimport { approvalRequired, inputDeclined, isCommandError, isMextError, MextError, type ArgumentIssue } from \"./errors.ts\"\nimport { exposedRegistry } from \"./expose.ts\"\nimport { observeCommand, reportCommandError, type Instrumentation, type Transport } from \"./instrumentation.ts\"\nimport { findCommand } from \"./lookup.ts\"\nimport { hasScope, type Principal } from \"./principal.ts\"\nimport { loadCommand, resolveCommand, type JsonSchema, type RegisteredCommand, type Registry } from \"./registry.ts\"\n\n/** 어댑터가 주입하는 ctx.ask 구현. command = 정식 ID */\nexport type AskHandler = (request: AskHandlerRequest) => Promise<unknown>\n\nexport type AskHandlerRequest =\n | { command: string; kind: \"confirm\"; message: string }\n | { command: string; kind: \"input\"; message: string; schema: InputSchema; requestedSchema: JsonSchema }\n | { command: string; kind: \"url\"; message: string; url: string }\n\nexport interface InvokeOptions {\n principal: Principal\n /** 기본 = abort 되지 않는 signal */\n signal?: AbortSignal\n /** 기본 = 무시 */\n progress?: (update: ProgressUpdate) => void\n /** 기본 = ctx.ask 호출 시 INPUT_UNAVAILABLE */\n ask?: AskHandler\n app?: MextApp\n /** readOnly 명령어만 허용 (split 의 query 도구). 그 외 = PERMISSION_DENIED */\n readOnly?: boolean\n /**\n * 응답을 기다리게 하지 않을 작업 (숨긴 명령어 호출 시도의 감사 전달, §11.1) 을 넘겨받는다. MCP 어댑터 = waitUntil 또는 그대로 둠.\n * 없음 = invoke 가 끝까지 기다린다 (로컬 실행: 프로세스가 곧 끝난다)\n */\n background?: (work: Promise<void>) => void\n /** loadInstrumentation 결과. onCommandError · mext.command span. 기본 = 없음 */\n instrumentation?: Instrumentation\n /** 실행 어댑터 (onCommandError · span 속성 · ctx.caller.transport · 기본 표면). 기본 \"local\" */\n transport?: Transport\n /** 클라이언트가 신고한 clientInfo (ctx.caller.client). 자가 신고 값. 기본 = 없음 */\n client?: ReportedClient\n /** W3C trace context carrier (MCP params._meta 의 traceparent · tracestate). span 의 부모 */\n traceContext?: Record<string, unknown>\n /** ctx.resourceUpdated (§12.5). 기본 = no-op */\n resourceUpdated?: (uri: string) => Promise<void>\n /**\n * tasks 확장 (§12.6). 입력 검증 · 권한 · 승인 (§4) 통과 후 execute 직전에 호출.\n * 반환 = 분리 실행: invoke 는 handle 로 바로 resolve, execute 는 반환된 signal · ask · progress 로 계속 실행 후 settle.\n * undefined = 동기 실행 (지금과 같음). span · onCommandError 는 분리 실행 전체를 덮는다\n */\n detach?: (entry: RegisteredCommand) => Promise<DetachedExecution | undefined>\n /** 감사 (config.audit, §11.1). 없음 = 이벤트 없음 */\n audit?: AuditConfig\n /** 승인의 표면별 확인 방식 (config.approval, §4 승인). 없음 = 모든 표면 ask */\n approval?: ApprovalConfig\n /**\n * 요청에 확인 표시가 실려 있음 (MCP params._meta[\"dev.mext/approval\"] = { confirmed: true }). 클라이언트가 실은 값이다:\n * client 방식 표면 + 서버가 정한 행위자 human 일 때만 인정한다. 기본 false\n */\n confirmed?: boolean\n /**\n * 이 호출이 입력 대기로 끝났는지 (MRTR 라운드: 답 없는 ctx.ask 가 있어 결과를 버리고 InputRequiredResult 를 돌려준다).\n * true = 감사 이벤트 없음 (답을 받아 끝난 라운드가 1건)\n */\n pendingInput?: () => boolean\n}\n\n/** detach 의 반환. execute 의 ctx 를 요청과 분리한다 (R2: 응답 종료 ≠ 취소) */\nexport interface DetachedExecution {\n /** invoke 결과의 detached (MCP = CreateTaskResult) */\n handle: unknown\n /** 감사 이벤트의 taskId (§11.1) */\n taskId?: string\n signal: AbortSignal\n ask: AskHandler\n progress: (update: ProgressUpdate) => void\n /** execute 종료. 값 = output 검증 후, 예외 = onCommandError 보고 후. 거부하지 않는다 */\n settle(outcome: { value: unknown } | { error: unknown }): Promise<void>\n}\n\nexport interface InvokeResult {\n /** 정식 ID (별칭으로 호출해도) */\n command: string\n value: unknown\n /** detach 로 분리 실행됨: DetachedExecution.handle (value 는 undefined) */\n detached?: unknown\n}\n\n/**\n * 어댑터 공통 실행기: ID 해석 (별칭 포함. 주체의 표면에서 숨긴 명령어 = 없는 ID, §4 expose) → 권한 → (lazy 면 모듈 import) → Zod safeParse 1회 → 가드 (authorize, §4) → 승인 (needsApproval · requiresConfirmation, §4) → execute.\n * 실패는 MextError (UNKNOWN_COMMAND · PERMISSION_DENIED · INVALID_ARGUMENT · APPROVAL_REQUIRED · INPUT_UNAVAILABLE · INPUT_DECLINED).\n * 핸들러 예외는 그대로 전파 (instrumentation 있으면 onCommandError 보고 후).\n * instrumentation.otel 있으면 findCommand 뒤 전체를 `mext.command <id>` span 으로 감싼다.\n * options.audit 있으면 호출 1건 = 감사 이벤트 1건 (§11.1. UNKNOWN_COMMAND · 입력 검증 실패 · 입력 대기 라운드 제외).\n */\nexport async function invoke(\n registry: Registry,\n id: string,\n rawInput: unknown,\n options: InvokeOptions,\n): Promise<InvokeResult> {\n // expose (§4): 주체의 표면에서 보이는 명령어만. 숨긴 명령어 = UNKNOWN_COMMAND (없는 ID 와 같은 본문)\n const view = exposedRegistry(registry, surfaceOf(options.principal, options.transport ?? \"local\"))\n let entry: RegisteredCommand\n try {\n entry = findCommand(view, id)\n } catch (error) {\n // 숨긴 명령어의 호출 시도 기록 (audit.includeHidden, §11.1). 응답 = 이 오류 그대로. 꺼져 있으면 찾지 않는다\n if (options.audit?.includeHidden === true && view !== registry) {\n const hidden = resolveCommand(registry, id)\n const work = hidden && auditHidden(hidden, options)\n if (work) {\n if (options.background) options.background(work)\n else await work\n }\n }\n throw error\n }\n // span 의 취소 판정 signal. 분리 실행 후 = task signal\n let signal = options.signal\n let handoff: ((result: InvokeResult) => void) | undefined\n const handedOff = options.detach ? new Promise<InvokeResult>((resolve) => (handoff = resolve)) : undefined\n // 감사 (§11.1). sink 없음 · 대상 아님 = undefined\n const trail = startAudit(entry, options)\n const body = async (): Promise<InvokeResult> => {\n authorize(entry, options.principal, { readOnly: options.readOnly })\n // lazy Registry (mext start) = 여기서 명령어 모듈 import. 권한 · ID 오류는 import 없이\n const command = await loadCommand(entry)\n let input: z.output<InputSchema>\n try {\n input = await parseInput(entry, rawInput)\n } catch (error) {\n // 입력 검증 실패 = 감사 이벤트 없음\n trail?.skip()\n throw error\n }\n trail?.validated(command, input)\n const ctx = createContext(entry, options)\n ctx.signal.throwIfAborted()\n // 가드 = 로드한 명령어의 authorize (lazy Registry 의 메타데이터 명령어에는 함수가 없다)\n await guard(entry, command, input, ctx, options)\n await approve(entry, command, input, ctx, options, trail)\n const detached = await options.detach?.(entry)\n if (detached) {\n signal = detached.signal\n handoff!({ command: entry.id, value: undefined, detached: detached.handle })\n const taskCtx = createContext(entry, { ...options, signal: detached.signal, ask: detached.ask, progress: detached.progress })\n trail?.task(detached.taskId)\n // 감사 = 분리 실행의 실제 종료 시점, task 결과 기록 (settle) 전\n try {\n const value = await parseOutput(entry.id, command, await command.execute(input, taskCtx))\n await trail?.finish({ value }, false)\n await detached.settle({ value })\n return { command: entry.id, value }\n } catch (error) {\n await reportCommandError(error, entry.id, options, taskCtx.signal)\n await trail?.finish({ error }, taskCtx.signal.aborted)\n await detached.settle({ error })\n throw error\n }\n }\n try {\n const value = await parseOutput(entry.id, command, await command.execute(input, ctx))\n return { command: entry.id, value }\n } catch (error) {\n await reportCommandError(error, entry.id, options, ctx.signal)\n throw error\n }\n }\n const run = observeCommand(\n entry.id,\n options,\n () => signal,\n !trail\n ? body\n : async (trace) => {\n trail.trace(trace)\n try {\n const result = await body()\n if (options.pendingInput?.()) trail.skip()\n await trail.finish({ value: result.value }, false)\n return result\n } catch (error) {\n if (options.pendingInput?.()) trail.skip()\n await trail.finish({ error }, signal?.aborted === true)\n throw error\n }\n },\n )\n // 분리 실행 = handoff 로 먼저 resolve. 이후 run 의 거부는 race 가 받는다 (미처리 거부 없음)\n return handedOff ? Promise.race([handedOff, run]) : run\n}\n\n/** ID · 별칭 → 명령어. 없으면 UNKNOWN_COMMAND (suggested · usage). 구현 = lookup.ts (help · 고객 CLI 공용) */\nexport { findCommand }\n\n/**\n * 안전성 메타데이터를 주체에 대해 강제.\n * readOnly 전용 호출 = readOnly 명령어만 · anonymous = readOnly 명령어만 · command.scopes 전부 보유 (\"*\" = 전체).\n */\nexport function authorize(entry: RegisteredCommand, principal: Principal, options: { readOnly?: boolean } = {}): void {\n const c = entry.command\n const deny = (reason: \"anonymous\" | \"read_only\" | \"scope\", message: string): never =>\n throwError(\n new MextError(\"PERMISSION_DENIED\", message, {\n command: entry.id,\n reason,\n required_scopes: [...c.scopes],\n held_scopes: [...principal.scopes],\n }),\n )\n if (options.readOnly && !c.readOnly) deny(\"read_only\", `${entry.id} is not read-only and cannot run here.`)\n if (principal.kind === \"anonymous\" && !c.readOnly) {\n deny(\"anonymous\", `${entry.id} is not read-only and requires an authenticated principal.`)\n }\n const missing = c.scopes.filter((s) => !hasScope(principal, s))\n if (missing.length > 0) deny(\"scope\", `${entry.id} requires scopes: ${missing.join(\", \")}.`)\n}\n\n/**\n * 실행 가드 (defineCommand authorize, §4). true 만 통과. 그 외 반환값 (undefined 포함) · 예외 = PERMISSION_DENIED (reason \"authorize\").\n * CommandError = 그 message 로 거부. 그 외 예외 = 거부 + onCommandError 보고 (message 는 응답에 싣지 않는다).\n * 취소 · mext 오류 (ctx.ask 의 INPUT_UNAVAILABLE 등) · 입력 대기 중의 예외는 바꾸지 않는다\n */\nasync function guard(\n entry: RegisteredCommand,\n command: Command,\n input: z.output<InputSchema>,\n ctx: CommandContext,\n options: InvokeOptions,\n): Promise<void> {\n if (!command.authorize) return\n const denied = (message: string, cause?: unknown): MextError<\"PERMISSION_DENIED\"> => {\n const error = new MextError(\"PERMISSION_DENIED\", message, {\n command: entry.id,\n reason: \"authorize\",\n required_scopes: [...entry.command.scopes],\n held_scopes: [...options.principal.scopes],\n })\n // 원인은 서버 쪽 디버깅용 (응답 본문 = toJSON 에는 없다)\n if (cause !== undefined) error.cause = cause\n return error\n }\n let verdict: unknown\n try {\n verdict = await command.authorize(input, ctx)\n } catch (error) {\n if (ctx.signal.aborted || isMextError(error) || options.pendingInput?.()) throw error\n await reportCommandError(error, entry.id, options, ctx.signal)\n throw denied(isCommandError(error) && error.message !== \"\" ? error.message : GUARD_DENIED(entry.id), error)\n }\n if (verdict !== true) throw denied(GUARD_DENIED(entry.id))\n}\n\n/**\n * 승인 (defineCommand needsApproval · requiresConfirmation, §4 승인). 승인이 필요한 호출을 표면의 확인 방식 한 곳에서 확인한다.\n * 행위자 agent = 승인 불가 (APPROVAL_REQUIRED human_required). 묻지 않는다\n * client 방식 표면 = 요청의 확인 표시 + 행위자 human 일 때만 통과. 묻지 않는다\n * ask 방식 표면 (기본) = ctx.ask confirm (CLI = 프롬프트 · --yes, MCP = MRTR). ask 미주입 = INPUT_UNAVAILABLE. 확인 표시는 보지 않는다\n * 승인 대상이 아닌 명령어 = 아무것도 하지 않는다\n */\nasync function approve(\n entry: RegisteredCommand,\n command: Command,\n input: z.output<InputSchema>,\n ctx: CommandContext,\n options: InvokeOptions,\n trail: AuditTrail | undefined,\n): Promise<void> {\n if (!command.requiresConfirmation) {\n if (!command.needsApproval) return\n if (!(await approvalNeeded(entry, command, input, ctx, options))) {\n trail?.approval({ required: false })\n return\n }\n }\n const method = approvalModeOf(options.approval, ctx.caller.surface)\n const actor = options.principal.actor?.kind\n trail?.approval({ required: true, method, confirmed: false })\n if (actor === \"agent\" || (method === \"client\" && actor !== \"human\")) {\n throw approvalRequired(entry.id, \"human_required\", { agent: actor === \"agent\" })\n }\n if (method === \"client\") {\n if (options.confirmed !== true) throw approvalRequired(entry.id, \"unconfirmed\")\n } else {\n const confirmed = await ctx.ask({ kind: \"confirm\", message: confirmationMessage(entry, input) })\n if (!confirmed) throw inputDeclined(entry.id, \"confirm\")\n ctx.signal.throwIfAborted()\n }\n trail?.approval({ required: true, method, confirmed: true })\n}\n\n/** needsApproval 조건식. false 만 승인 불필요. 그 외 반환값 · 예외 = 필요 (예외는 onCommandError 보고). 취소 · 입력 대기 중의 예외는 전파 */\nasync function approvalNeeded(\n entry: RegisteredCommand,\n command: Command,\n input: z.output<InputSchema>,\n ctx: CommandContext,\n options: InvokeOptions,\n): Promise<boolean> {\n try {\n return ((await command.needsApproval!(input, ctx)) as unknown) !== false\n } catch (error) {\n if (ctx.signal.aborted || options.pendingInput?.()) throw error\n await reportCommandError(error, entry.id, options, ctx.signal)\n return true\n }\n}\n\nconst GUARD_DENIED = (id: string): string => `${id} is not permitted for this caller.`\n\n/** Zod safeParse 1회. 실패 = INVALID_ARGUMENT (missing_fields · issues · expected_schema · examples) */\nexport async function parseInput(entry: RegisteredCommand, rawInput: unknown): Promise<z.output<InputSchema>> {\n const raw = rawInput === undefined ? {} : rawInput\n const result = await (await loadCommand(entry)).input.safeParseAsync(raw)\n if (result.success) return result.data\n throw invalidArgument(entry.id, raw, result.error.issues, entry.inputSchema, [...entry.command.examples])\n}\n\n/**\n * output 이 있으면 반환값 safeParse (모든 어댑터 · 노출 방식, §12.2). 결과 = 파싱된 값 (outputSchema 와 같은 모양).\n * 실패 = OutputValidationError (핸들러 예외와 같이 EXECUTION_ERROR · onCommandError 보고). 던진 오류는 검증하지 않는다\n */\nasync function parseOutput(id: string, command: Command, value: unknown): Promise<unknown> {\n if (!command.output) return value\n const result = await command.output.safeParseAsync(value)\n if (result.success) return result.data\n const summary = result.error.issues\n .map((i) => (i.path.length > 0 ? `${i.path.map(String).join(\".\")}: ${i.message}` : i.message))\n .join(\"; \")\n throw new OutputValidationError(`${id} returned a value that does not match its output schema: ${summary}`)\n}\n\n/** output 검증 실패. MextError 가 아님 = 응답 EXECUTION_ERROR (message 만) · onCommandError 보고 */\nexport class OutputValidationError extends Error {\n constructor(message: string) {\n super(message)\n this.name = \"OutputValidationError\"\n }\n}\n\n/** ctx 생성. ask · progress · signal 은 어댑터 주입 */\nexport function createContext(entry: RegisteredCommand, options: InvokeOptions): CommandContext {\n const handler = options.ask\n const ask = async (request: AskRequest): Promise<unknown> => {\n // url 형식 오류 = 핸들러 버그 (TypeError → EXECUTION_ERROR). 실행 환경과 무관하게 먼저 검사\n if (request.kind === \"url\") assertAskUrl(request.url)\n if (!handler) {\n throw new MextError(\"INPUT_UNAVAILABLE\", `${entry.id} requested input, but this environment cannot ask.`, {\n command: entry.id,\n ...(request.kind === \"url\" ? { url: request.url } : {}),\n })\n }\n if (request.kind === \"confirm\") {\n return (await handler({ command: entry.id, kind: \"confirm\", message: request.message })) === true\n }\n if (request.kind === \"url\") {\n return (await handler({ command: entry.id, kind: \"url\", message: request.message, url: request.url })) === true\n }\n const requestedSchema = z.toJSONSchema(request.schema, { target: \"draft-2020-12\", io: \"input\" }) as JsonSchema\n const response = await handler({\n command: entry.id,\n kind: \"input\",\n message: request.message,\n schema: request.schema,\n requestedSchema,\n })\n const parsed = await request.schema.safeParseAsync(response)\n if (parsed.success) return parsed.data\n throw invalidArgument(entry.id, response, parsed.error.issues, requestedSchema, [])\n }\n return {\n principal: options.principal,\n caller: callerOf(options.principal, options.transport ?? \"local\", options.client),\n signal: options.signal ?? new AbortController().signal,\n progress: options.progress ?? (() => {}),\n ask: ask as Ask,\n app: options.app ?? ({} as MextApp),\n resourceUpdated: options.resourceUpdated ?? noResourceUpdates,\n }\n}\n\n/** state 없는 실행 (로컬 CLI · stateless 서버). uri 형식 오류만 TypeError */\nasync function noResourceUpdates(uri: string): Promise<void> {\n assertResourceUri(uri)\n}\n\n/** ctx.resourceUpdated uri: 비어 있지 않은 문자열. 아니면 TypeError (핸들러 버그) */\nexport function assertResourceUri(uri: unknown): asserts uri is string {\n if (typeof uri !== \"string\" || uri === \"\") throw new TypeError(`resourceUpdated uri must be a non-empty string: ${JSON.stringify(uri)}`)\n}\n\n/** ctx.ask url: http(s) 절대 URL. 아니면 TypeError */\nfunction assertAskUrl(url: unknown): asserts url is string {\n const parsed = typeof url === \"string\" && URL.canParse(url) ? new URL(url) : undefined\n if (parsed?.protocol !== \"http:\" && parsed?.protocol !== \"https:\") {\n throw new TypeError(`ctx.ask url must be an absolute http(s) URL: ${JSON.stringify(url)}`)\n }\n}\n\n/** 승인 확인 문구 (ask 방식). 검증된 입력을 포함 (무엇을 승인하는지) */\nexport function confirmationMessage(entry: RegisteredCommand, input: unknown): string {\n let args: string\n try {\n args = JSON.stringify(input) ?? \"{}\"\n } catch {\n args = \"{}\"\n }\n return `Run ${entry.id} with ${args}?${entry.command.destructive ? \" This command is destructive.\" : \"\"}`\n}\n\n/** INVALID_ARGUMENT (missing_fields · issues · expected_schema · examples). 프롬프트 인자 (§12.3) 도 사용 */\nexport function invalidArgument(\n command: string,\n raw: unknown,\n zodIssues: readonly z.core.$ZodIssue[],\n expectedSchema: JsonSchema,\n examples: unknown[],\n): MextError<\"INVALID_ARGUMENT\"> {\n const issues: ArgumentIssue[] = zodIssues.map((i) => ({\n path: i.path.map(String).join(\".\"),\n code: i.code,\n message: i.message,\n }))\n const missing = new Set<string>()\n for (const i of zodIssues) {\n if (i.code === \"invalid_type\" && i.path.length > 0 && isAbsent(raw, i.path)) missing.add(i.path.map(String).join(\".\"))\n }\n const missing_fields = [...missing]\n const summary =\n missing_fields.length > 0\n ? `missing required: ${missing_fields.join(\", \")}`\n : issues.map((i) => (i.path ? `${i.path}: ${i.message}` : i.message)).join(\"; \")\n return new MextError(\"INVALID_ARGUMENT\", `Invalid arguments for ${command}: ${summary}`, {\n command,\n missing_fields,\n issues,\n expected_schema: expectedSchema,\n examples,\n })\n}\n\n/** 원본 입력에 경로가 없는지 (값 undefined 포함) */\nfunction isAbsent(raw: unknown, path: readonly PropertyKey[]): boolean {\n let cur: unknown = raw\n for (const key of path) {\n if (cur === null || typeof cur !== \"object\") return true\n cur = (cur as Record<PropertyKey, unknown>)[key]\n if (cur === undefined) return true\n }\n return false\n}\n\nfunction throwError(error: MextError): never {\n throw error\n}\n"]}