@obov/mext 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/dist/build-cli.d.ts +39 -0
  2. package/dist/build-cli.js +160 -0
  3. package/dist/build-cli.js.map +1 -0
  4. package/dist/build.d.ts +65 -0
  5. package/dist/build.js +252 -0
  6. package/dist/build.js.map +1 -0
  7. package/dist/cli/args.d.ts +107 -0
  8. package/dist/cli/args.js +621 -0
  9. package/dist/cli/args.js.map +1 -0
  10. package/dist/cli/bin.d.ts +2 -0
  11. package/dist/cli/bin.js +13 -0
  12. package/dist/cli/bin.js.map +1 -0
  13. package/dist/cli/build.d.ts +11 -0
  14. package/dist/cli/build.js +87 -0
  15. package/dist/cli/build.js.map +1 -0
  16. package/dist/cli/dev-lock.d.ts +23 -0
  17. package/dist/cli/dev-lock.js +68 -0
  18. package/dist/cli/dev-lock.js.map +1 -0
  19. package/dist/cli/dev-server.d.ts +20 -0
  20. package/dist/cli/dev-server.js +74 -0
  21. package/dist/cli/dev-server.js.map +1 -0
  22. package/dist/cli/dev.d.ts +21 -0
  23. package/dist/cli/dev.js +564 -0
  24. package/dist/cli/dev.js.map +1 -0
  25. package/dist/cli/help.d.ts +31 -0
  26. package/dist/cli/help.js +238 -0
  27. package/dist/cli/help.js.map +1 -0
  28. package/dist/cli/io.d.ts +26 -0
  29. package/dist/cli/io.js +74 -0
  30. package/dist/cli/io.js.map +1 -0
  31. package/dist/cli/login.d.ts +32 -0
  32. package/dist/cli/login.js +284 -0
  33. package/dist/cli/login.js.map +1 -0
  34. package/dist/cli/logout.d.ts +9 -0
  35. package/dist/cli/logout.js +105 -0
  36. package/dist/cli/logout.js.map +1 -0
  37. package/dist/cli/main.d.ts +19 -0
  38. package/dist/cli/main.js +77 -0
  39. package/dist/cli/main.js.map +1 -0
  40. package/dist/cli/mcp.d.ts +16 -0
  41. package/dist/cli/mcp.js +92 -0
  42. package/dist/cli/mcp.js.map +1 -0
  43. package/dist/cli/output.d.ts +34 -0
  44. package/dist/cli/output.js +172 -0
  45. package/dist/cli/output.js.map +1 -0
  46. package/dist/cli/remote.d.ts +17 -0
  47. package/dist/cli/remote.js +35 -0
  48. package/dist/cli/remote.js.map +1 -0
  49. package/dist/cli/run.d.ts +14 -0
  50. package/dist/cli/run.js +218 -0
  51. package/dist/cli/run.js.map +1 -0
  52. package/dist/cli/start.d.ts +8 -0
  53. package/dist/cli/start.js +37 -0
  54. package/dist/cli/start.js.map +1 -0
  55. package/dist/client/cache.d.ts +104 -0
  56. package/dist/client/cache.js +208 -0
  57. package/dist/client/cache.js.map +1 -0
  58. package/dist/client/main.d.ts +25 -0
  59. package/dist/client/main.js +100 -0
  60. package/dist/client/main.js.map +1 -0
  61. package/dist/client/manifest.d.ts +19 -0
  62. package/dist/client/manifest.js +68 -0
  63. package/dist/client/manifest.js.map +1 -0
  64. package/dist/client/runner.d.ts +49 -0
  65. package/dist/client/runner.js +562 -0
  66. package/dist/client/runner.js.map +1 -0
  67. package/dist/command.d.ts +75 -0
  68. package/dist/command.js +44 -0
  69. package/dist/command.js.map +1 -0
  70. package/dist/config.d.ts +53 -0
  71. package/dist/config.js +122 -0
  72. package/dist/config.js.map +1 -0
  73. package/dist/errors.d.ts +74 -0
  74. package/dist/errors.js +38 -0
  75. package/dist/errors.js.map +1 -0
  76. package/dist/ids.d.ts +6 -0
  77. package/dist/ids.js +12 -0
  78. package/dist/ids.js.map +1 -0
  79. package/dist/index.d.ts +45 -0
  80. package/dist/index.js +27 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/instrumentation.d.ts +97 -0
  83. package/dist/instrumentation.js +165 -0
  84. package/dist/instrumentation.js.map +1 -0
  85. package/dist/invoke.d.ts +64 -0
  86. package/dist/invoke.js +152 -0
  87. package/dist/invoke.js.map +1 -0
  88. package/dist/lookup.d.ts +9 -0
  89. package/dist/lookup.js +27 -0
  90. package/dist/lookup.js.map +1 -0
  91. package/dist/manifest.d.ts +68 -0
  92. package/dist/manifest.js +77 -0
  93. package/dist/manifest.js.map +1 -0
  94. package/dist/mcp/constants.d.ts +9 -0
  95. package/dist/mcp/constants.js +10 -0
  96. package/dist/mcp/constants.js.map +1 -0
  97. package/dist/mcp/dispatch.d.ts +66 -0
  98. package/dist/mcp/dispatch.js +249 -0
  99. package/dist/mcp/dispatch.js.map +1 -0
  100. package/dist/mcp/help.d.ts +57 -0
  101. package/dist/mcp/help.js +136 -0
  102. package/dist/mcp/help.js.map +1 -0
  103. package/dist/mcp/http.d.ts +92 -0
  104. package/dist/mcp/http.js +366 -0
  105. package/dist/mcp/http.js.map +1 -0
  106. package/dist/mcp/index.d.ts +15 -0
  107. package/dist/mcp/index.js +9 -0
  108. package/dist/mcp/index.js.map +1 -0
  109. package/dist/mcp/install.d.ts +17 -0
  110. package/dist/mcp/install.js +36 -0
  111. package/dist/mcp/install.js.map +1 -0
  112. package/dist/mcp/mrtr.d.ts +82 -0
  113. package/dist/mcp/mrtr.js +130 -0
  114. package/dist/mcp/mrtr.js.map +1 -0
  115. package/dist/mcp/server.d.ts +58 -0
  116. package/dist/mcp/server.js +204 -0
  117. package/dist/mcp/server.js.map +1 -0
  118. package/dist/mcp/stdio.d.ts +57 -0
  119. package/dist/mcp/stdio.js +79 -0
  120. package/dist/mcp/stdio.js.map +1 -0
  121. package/dist/principal.d.ts +16 -0
  122. package/dist/principal.js +24 -0
  123. package/dist/principal.js.map +1 -0
  124. package/dist/registry.d.ts +90 -0
  125. package/dist/registry.js +169 -0
  126. package/dist/registry.js.map +1 -0
  127. package/dist/remote/browser.d.ts +15 -0
  128. package/dist/remote/browser.js +47 -0
  129. package/dist/remote/browser.js.map +1 -0
  130. package/dist/remote/client.d.ts +113 -0
  131. package/dist/remote/client.js +312 -0
  132. package/dist/remote/client.js.map +1 -0
  133. package/dist/remote/credentials.d.ts +48 -0
  134. package/dist/remote/credentials.js +196 -0
  135. package/dist/remote/credentials.js.map +1 -0
  136. package/dist/remote/index.d.ts +8 -0
  137. package/dist/remote/index.js +5 -0
  138. package/dist/remote/index.js.map +1 -0
  139. package/dist/remote/oauth.d.ts +186 -0
  140. package/dist/remote/oauth.js +507 -0
  141. package/dist/remote/oauth.js.map +1 -0
  142. package/dist/scan.d.ts +34 -0
  143. package/dist/scan.js +155 -0
  144. package/dist/scan.js.map +1 -0
  145. package/dist/start.d.ts +63 -0
  146. package/dist/start.js +267 -0
  147. package/dist/start.js.map +1 -0
  148. package/dist/suggest.d.ts +7 -0
  149. package/dist/suggest.js +45 -0
  150. package/dist/suggest.js.map +1 -0
  151. package/dist/version.d.ts +4 -0
  152. package/dist/version.js +13 -0
  153. package/dist/version.js.map +1 -0
  154. package/package.json +49 -4
  155. package/README.md +0 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ids.js","sourceRoot":"","sources":["../src/ids.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,MAAM,CAAC,MAAM,eAAe,GAAG,iCAAiC,CAAA;AAEhE,gDAAgD;AAChD,MAAM,CAAC,MAAM,sBAAsB,GAAsB,CAAC,MAAM,CAAC,CAAA;AAEjE,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,OAAO,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AACpC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,EAAU;IACxC,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;IAC7B,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AACvC,CAAC","sourcesContent":["/** 경로 세그먼트 · 별칭 규칙: kebab-case 만 */\nexport const SEGMENT_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/\n\n/** 루트에 둘 수 없는 세그먼트 (help 탐색 · CLI help 와 충돌) */\nexport const RESERVED_ROOT_SEGMENTS: readonly string[] = [\"help\"]\n\nexport function isSegment(value: string): boolean {\n return SEGMENT_PATTERN.test(value)\n}\n\nexport function parentNamespace(id: string): string {\n const i = id.lastIndexOf(\".\")\n return i === -1 ? \"\" : id.slice(0, i)\n}\n"]}
@@ -0,0 +1,45 @@
1
+ export { VERSION } from "./version.ts";
2
+ export { defineCommand, isCommand } from "./command.ts";
3
+ export type { Ask, AskRequest, Command, CommandContext, CommandDefinition, ConfirmRequest, InputRequest, InputSchema, MextApp, ProgressUpdate, } from "./command.ts";
4
+ export { ANONYMOUS, hasScope, localPrincipal } from "./principal.ts";
5
+ export type { Principal } from "./principal.ts";
6
+ export { inputDeclined, isMextError, MextBuildError, MextError, unauthenticated } from "./errors.ts";
7
+ export type { ArgumentIssue, BuildIssue, BuildIssueCode, MextErrorCode, MextErrorDetails } from "./errors.ts";
8
+ export { authorize, confirmationMessage, createContext, findCommand, invoke, parseInput } from "./invoke.ts";
9
+ export type { AskHandler, AskHandlerRequest, InvokeOptions, InvokeResult } from "./invoke.ts";
10
+ export { findInstrumentation, INSTRUMENTATION_FILE, loadInstrumentation, loadProjectInstrumentation, } from "./instrumentation.ts";
11
+ export type { CommandErrorInfo, Instrumentation, InstrumentationModule, LoadInstrumentationOptions, OtelApi, Transport, } from "./instrumentation.ts";
12
+ export { collectRegistry, createLazyRegistry, createRegistry, loadCommand, resolveCommand } from "./registry.ts";
13
+ export type { JsonSchema, LazyCommandInput, NamespaceInfo, RegisteredCommand, Registry, RegistryCommandInput, RegistryInput, RegistryNamespaceInput, } from "./registry.ts";
14
+ export { collectCommands, loadRegistry, scanCommands, walkCommands } from "./scan.ts";
15
+ export type { ScannedFile, ScanResult } from "./scan.ts";
16
+ export { buildManifest, describeCommand, generateManifest, MANIFEST_SCHEMA_VERSION, manifestHash } from "./manifest.ts";
17
+ export type { BuildManifest, BuildManifestCommand, Manifest, ManifestCommand, ManifestNamespace } from "./manifest.ts";
18
+ export { BUILD_DIR, BUILD_MANIFEST_FILE, buildProject, HANDLER_JS, RolldownUnavailableError, SERVER_JS, START_ENTRY } from "./build.ts";
19
+ export type { BuildOptions, BuildResult, BuildWarning, RolldownModule, RolldownOutputItem } from "./build.ts";
20
+ export { formatBuildSummary, runBuild } from "./cli/build.ts";
21
+ export { mextVersion } from "./version.ts";
22
+ export * from "./mcp/index.ts";
23
+ export { CLI_BUILTIN_COMMANDS, CONFIG_FILE, createApp, defineConfig, loadConfig, resolveCommandsDir, resolveLocalPrincipal } from "./config.ts";
24
+ export type { CliConfig, MextConfig } from "./config.ts";
25
+ export { buildCustomerCli, CLI_BIN_FILE, CLI_DIR, customerCliIssues } from "./build-cli.ts";
26
+ export type { BuildCustomerCliOptions, CustomerCliBuild } from "./build-cli.ts";
27
+ export { runCustomerCli } from "./client/main.ts";
28
+ export type { CustomerCliConfig } from "./client/main.ts";
29
+ export { clientManifest, manifestHelp } from "./client/manifest.ts";
30
+ export type { ClientManifest, ClientManifestCommand } from "./client/manifest.ts";
31
+ export { runRemote } from "./client/runner.ts";
32
+ export type { HelpSource, RemoteRunOptions } from "./client/runner.ts";
33
+ export { runCli, SUBCOMMANDS } from "./cli/main.ts";
34
+ export type { CliSubcommand } from "./cli/main.ts";
35
+ export type { CliIo, CliWriter } from "./cli/io.ts";
36
+ export { analyzeInput, assertCliConvertible, cliBuildIssues, cliSpec, parseArgs, RESERVED_FLAGS, toKebab } from "./cli/args.ts";
37
+ export type { CliField, CliSpec, FieldKind, ParseArgsOptions, ParsedArgs, Primitive, ScalarKind } from "./cli/args.ts";
38
+ export { cliPath, formatInvocation, renderCommandHelp, renderHelp, renderNamespaceHelp, resolveHelpTarget, } from "./cli/help.ts";
39
+ export type { HelpOptions, HelpTarget } from "./cli/help.ts";
40
+ export { errorJson, exitCodeOf, formatError, formatJson, formatResult } from "./cli/output.ts";
41
+ export { loginCommand, resolveServerUrl } from "./cli/login.ts";
42
+ export type { AuthCommandOptions } from "./cli/login.ts";
43
+ export { logoutCommand } from "./cli/logout.ts";
44
+ export * from "./remote/index.ts";
45
+ export { cliSpecFromJsonSchema, defineCliSpec } from "./cli/args.ts";
package/dist/index.js ADDED
@@ -0,0 +1,27 @@
1
+ export { VERSION } from "./version.js";
2
+ export { defineCommand, isCommand } from "./command.js";
3
+ export { ANONYMOUS, hasScope, localPrincipal } from "./principal.js";
4
+ export { inputDeclined, isMextError, MextBuildError, MextError, unauthenticated } from "./errors.js";
5
+ export { authorize, confirmationMessage, createContext, findCommand, invoke, parseInput } from "./invoke.js";
6
+ export { findInstrumentation, INSTRUMENTATION_FILE, loadInstrumentation, loadProjectInstrumentation, } from "./instrumentation.js";
7
+ export { collectRegistry, createLazyRegistry, createRegistry, loadCommand, resolveCommand } from "./registry.js";
8
+ export { collectCommands, loadRegistry, scanCommands, walkCommands } from "./scan.js";
9
+ export { buildManifest, describeCommand, generateManifest, MANIFEST_SCHEMA_VERSION, manifestHash } from "./manifest.js";
10
+ export { BUILD_DIR, BUILD_MANIFEST_FILE, buildProject, HANDLER_JS, RolldownUnavailableError, SERVER_JS, START_ENTRY } from "./build.js";
11
+ export { formatBuildSummary, runBuild } from "./cli/build.js";
12
+ export { mextVersion } from "./version.js";
13
+ export * from "./mcp/index.js";
14
+ export { CLI_BUILTIN_COMMANDS, CONFIG_FILE, createApp, defineConfig, loadConfig, resolveCommandsDir, resolveLocalPrincipal } from "./config.js";
15
+ export { buildCustomerCli, CLI_BIN_FILE, CLI_DIR, customerCliIssues } from "./build-cli.js";
16
+ export { runCustomerCli } from "./client/main.js";
17
+ export { clientManifest, manifestHelp } from "./client/manifest.js";
18
+ export { runRemote } from "./client/runner.js";
19
+ export { runCli, SUBCOMMANDS } from "./cli/main.js";
20
+ export { analyzeInput, assertCliConvertible, cliBuildIssues, cliSpec, parseArgs, RESERVED_FLAGS, toKebab } from "./cli/args.js";
21
+ export { cliPath, formatInvocation, renderCommandHelp, renderHelp, renderNamespaceHelp, resolveHelpTarget, } from "./cli/help.js";
22
+ export { errorJson, exitCodeOf, formatError, formatJson, formatResult } from "./cli/output.js";
23
+ export { loginCommand, resolveServerUrl } from "./cli/login.js";
24
+ export { logoutCommand } from "./cli/logout.js";
25
+ export * from "./remote/index.js";
26
+ export { cliSpecFromJsonSchema, defineCliSpec } from "./cli/args.js";
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAavD,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAEpE,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAEpG,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAE5G,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,0BAA0B,GAC3B,MAAM,sBAAsB,CAAA;AAS7B,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,cAAc,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAWhH,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAErF,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAEvH,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,YAAY,EAAE,UAAU,EAAE,wBAAwB,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAEvI,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,cAAc,gBAAgB,CAAA;AAC9B,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAE/I,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAE3F,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEjD,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAEnE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAE9C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAGnD,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAE/H,OAAO,EACL,OAAO,EACP,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,EACV,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,eAAe,CAAA;AAEtB,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9F,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAE/D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,cAAc,mBAAmB,CAAA;AACjC,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA","sourcesContent":["export { VERSION } from \"./version.ts\"\n\nexport { defineCommand, isCommand } from \"./command.ts\"\nexport type {\n Ask,\n AskRequest,\n Command,\n CommandContext,\n CommandDefinition,\n ConfirmRequest,\n InputRequest,\n InputSchema,\n MextApp,\n ProgressUpdate,\n} from \"./command.ts\"\nexport { ANONYMOUS, hasScope, localPrincipal } from \"./principal.ts\"\nexport type { Principal } from \"./principal.ts\"\nexport { inputDeclined, isMextError, MextBuildError, MextError, unauthenticated } from \"./errors.ts\"\nexport type { ArgumentIssue, BuildIssue, BuildIssueCode, MextErrorCode, MextErrorDetails } from \"./errors.ts\"\nexport { authorize, confirmationMessage, createContext, findCommand, invoke, parseInput } from \"./invoke.ts\"\nexport type { AskHandler, AskHandlerRequest, InvokeOptions, InvokeResult } from \"./invoke.ts\"\nexport {\n findInstrumentation,\n INSTRUMENTATION_FILE,\n loadInstrumentation,\n loadProjectInstrumentation,\n} from \"./instrumentation.ts\"\nexport type {\n CommandErrorInfo,\n Instrumentation,\n InstrumentationModule,\n LoadInstrumentationOptions,\n OtelApi,\n Transport,\n} from \"./instrumentation.ts\"\nexport { collectRegistry, createLazyRegistry, createRegistry, loadCommand, resolveCommand } from \"./registry.ts\"\nexport type {\n JsonSchema,\n LazyCommandInput,\n NamespaceInfo,\n RegisteredCommand,\n Registry,\n RegistryCommandInput,\n RegistryInput,\n RegistryNamespaceInput,\n} from \"./registry.ts\"\nexport { collectCommands, loadRegistry, scanCommands, walkCommands } from \"./scan.ts\"\nexport type { ScannedFile, ScanResult } from \"./scan.ts\"\nexport { buildManifest, describeCommand, generateManifest, MANIFEST_SCHEMA_VERSION, manifestHash } from \"./manifest.ts\"\nexport type { BuildManifest, BuildManifestCommand, Manifest, ManifestCommand, ManifestNamespace } from \"./manifest.ts\"\nexport { BUILD_DIR, BUILD_MANIFEST_FILE, buildProject, HANDLER_JS, RolldownUnavailableError, SERVER_JS, START_ENTRY } from \"./build.ts\"\nexport type { BuildOptions, BuildResult, BuildWarning, RolldownModule, RolldownOutputItem } from \"./build.ts\"\nexport { formatBuildSummary, runBuild } from \"./cli/build.ts\"\nexport { mextVersion } from \"./version.ts\"\nexport * from \"./mcp/index.ts\"\nexport { CLI_BUILTIN_COMMANDS, CONFIG_FILE, createApp, defineConfig, loadConfig, resolveCommandsDir, resolveLocalPrincipal } from \"./config.ts\"\nexport type { CliConfig, MextConfig } from \"./config.ts\"\nexport { buildCustomerCli, CLI_BIN_FILE, CLI_DIR, customerCliIssues } from \"./build-cli.ts\"\nexport type { BuildCustomerCliOptions, CustomerCliBuild } from \"./build-cli.ts\"\nexport { runCustomerCli } from \"./client/main.ts\"\nexport type { CustomerCliConfig } from \"./client/main.ts\"\nexport { clientManifest, manifestHelp } from \"./client/manifest.ts\"\nexport type { ClientManifest, ClientManifestCommand } from \"./client/manifest.ts\"\nexport { runRemote } from \"./client/runner.ts\"\nexport type { HelpSource, RemoteRunOptions } from \"./client/runner.ts\"\nexport { runCli, SUBCOMMANDS } from \"./cli/main.ts\"\nexport type { CliSubcommand } from \"./cli/main.ts\"\nexport type { CliIo, CliWriter } from \"./cli/io.ts\"\nexport { analyzeInput, assertCliConvertible, cliBuildIssues, cliSpec, parseArgs, RESERVED_FLAGS, toKebab } from \"./cli/args.ts\"\nexport type { CliField, CliSpec, FieldKind, ParseArgsOptions, ParsedArgs, Primitive, ScalarKind } from \"./cli/args.ts\"\nexport {\n cliPath,\n formatInvocation,\n renderCommandHelp,\n renderHelp,\n renderNamespaceHelp,\n resolveHelpTarget,\n} from \"./cli/help.ts\"\nexport type { HelpOptions, HelpTarget } from \"./cli/help.ts\"\nexport { errorJson, exitCodeOf, formatError, formatJson, formatResult } from \"./cli/output.ts\"\nexport { loginCommand, resolveServerUrl } from \"./cli/login.ts\"\nexport type { AuthCommandOptions } from \"./cli/login.ts\"\nexport { logoutCommand } from \"./cli/logout.ts\"\nexport * from \"./remote/index.ts\"\nexport { cliSpecFromJsonSchema, defineCliSpec } from \"./cli/args.ts\"\n"]}
@@ -0,0 +1,97 @@
1
+ import type { Principal } from "./principal.ts";
2
+ /**
3
+ * instrumentation.ts (프로젝트 루트, 선택) · OpenTelemetry span (§11).
4
+ * register() = 프로세스당 1회, 첫 명령어 실행 전. onCommandError = 핸들러 예외 보고.
5
+ * span = @opentelemetry/api (선택 peer) 가 있을 때만. 없으면 no-op (실패한 import 1회 캐시).
6
+ */
7
+ export declare const INSTRUMENTATION_FILE = "instrumentation.ts";
8
+ /** 핸들러를 실행한 어댑터. 원격 CLI 는 핸들러를 실행하지 않으므로 없다 */
9
+ export type Transport = "http" | "stdio" | "local";
10
+ export interface CommandErrorInfo {
11
+ /** 정식 명령어 ID */
12
+ command: string;
13
+ transport: Transport;
14
+ /** scopes · claims 는 넘기지 않는다 */
15
+ principal: {
16
+ id: string;
17
+ kind: Principal["kind"];
18
+ };
19
+ }
20
+ /** instrumentation.ts 의 export */
21
+ export interface InstrumentationModule {
22
+ register?: () => unknown;
23
+ onCommandError?: (error: unknown, info: CommandErrorInfo) => unknown;
24
+ }
25
+ /** 어댑터가 InvokeOptions.instrumentation 으로 넘기는 로드 결과 */
26
+ export interface Instrumentation {
27
+ /** 핸들러 예외 (MextError 외, 취소 · MRTR 대기 제외). 자체 예외는 stderr 로 보고하고 응답은 바꾸지 않는다 */
28
+ onCommandError?: (error: unknown, info: CommandErrorInfo) => unknown;
29
+ /** @opentelemetry/api. undefined = span 없음 */
30
+ otel?: OtelApi;
31
+ /** onCommandError 의 예외 보고. 기본 stderr */
32
+ onerror?: (error: unknown) => void;
33
+ }
34
+ export interface LoadInstrumentationOptions {
35
+ /** @opentelemetry/api 로더 (테스트 주입). 기본 = 동적 import, 결과는 프로세스당 캐시 */
36
+ importOtel?: () => Promise<unknown>;
37
+ onerror?: (error: unknown) => void;
38
+ }
39
+ /** mext 가 쓰는 @opentelemetry/api 의 부분 (타입 의존 없이) */
40
+ export interface OtelApi {
41
+ trace: {
42
+ getTracer(name: string, version?: string): OtelTracer;
43
+ };
44
+ context: {
45
+ active(): unknown;
46
+ };
47
+ propagation: {
48
+ extract(context: unknown, carrier: unknown): unknown;
49
+ };
50
+ SpanStatusCode: {
51
+ ERROR: number;
52
+ };
53
+ }
54
+ interface OtelTracer {
55
+ startActiveSpan<T>(name: string, options: {
56
+ attributes: Record<string, string>;
57
+ }, context: unknown, fn: (span: OtelSpan) => T): T;
58
+ }
59
+ interface OtelSpan {
60
+ setAttribute(key: string, value: string): unknown;
61
+ setStatus(status: {
62
+ code: number;
63
+ message?: string;
64
+ }): unknown;
65
+ recordException(exception: unknown): unknown;
66
+ end(): void;
67
+ }
68
+ /** cwd 의 instrumentation.ts 절대 경로. 없으면 undefined */
69
+ export declare function findInstrumentation(cwd?: string): string | undefined;
70
+ /** findInstrumentation(cwd) → loadInstrumentation. mext dev · mext run (로컬) · stdio 용 */
71
+ export declare function loadProjectInstrumentation(cwd?: string, options?: LoadInstrumentationOptions): Promise<Instrumentation>;
72
+ /**
73
+ * instrumentation 모듈 (파일 경로 · URL · import 된 모듈) 을 프로세스당 1회 import 하고 register() 를 await.
74
+ * 같은 모듈의 두 번째 호출 = register 재호출 없이 같은 hooks. register 실패 = reject (다음 호출에서 재시도).
75
+ * source 없음 = hooks 없이 span 만. 빌드 산출물 (.mext/server/instrumentation.js) 도 같은 함수.
76
+ */
77
+ export declare function loadInstrumentation(source?: string | URL | InstrumentationModule, options?: LoadInstrumentationOptions): Promise<Instrumentation>;
78
+ export interface ObserveOptions {
79
+ instrumentation?: Instrumentation;
80
+ transport?: Transport;
81
+ principal: Principal;
82
+ /** W3C trace context carrier (MCP params._meta 의 traceparent · tracestate) */
83
+ traceContext?: Record<string, unknown>;
84
+ }
85
+ /**
86
+ * 명령어 실행 1회를 `mext.command <id>` span 으로 감싼다 (otel 있을 때만, 없으면 fn 그대로).
87
+ * 속성 = mext.command.id · mext.transport · mext.principal.kind. 인자 · 결과 · 토큰은 기록하지 않는다.
88
+ * 실패: status ERROR + mext.error.code. 핸들러 예외만 recordException (MextError 메시지는 입력 일부를 담을 수 있어 제외).
89
+ * 취소 (signal abort · MRTR 대기) = status 없음.
90
+ */
91
+ export declare function observeCommand<T>(command: string, options: ObserveOptions, signal: () => AbortSignal | undefined, fn: () => Promise<T>): Promise<T>;
92
+ /**
93
+ * 핸들러 예외 → onCommandError (await). MextError · 취소 · MRTR 대기는 보고하지 않는다.
94
+ * onCommandError 자체의 예외 = onerror (기본 stderr), 호출자에게 전파하지 않는다.
95
+ */
96
+ export declare function reportCommandError(error: unknown, command: string, options: ObserveOptions, signal: AbortSignal | undefined): Promise<void>;
97
+ export {};
@@ -0,0 +1,165 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ import { existsSync } from "node:fs";
10
+ import { isAbsolute, join, resolve } from "node:path";
11
+ import { pathToFileURL } from "node:url";
12
+ import { isMextError } from "./errors.js";
13
+ /**
14
+ * instrumentation.ts (프로젝트 루트, 선택) · OpenTelemetry span (§11).
15
+ * register() = 프로세스당 1회, 첫 명령어 실행 전. onCommandError = 핸들러 예외 보고.
16
+ * span = @opentelemetry/api (선택 peer) 가 있을 때만. 없으면 no-op (실패한 import 1회 캐시).
17
+ */
18
+ export const INSTRUMENTATION_FILE = "instrumentation.ts";
19
+ /** cwd 의 instrumentation.ts 절대 경로. 없으면 undefined */
20
+ export function findInstrumentation(cwd = process.cwd()) {
21
+ const file = join(resolve(cwd), INSTRUMENTATION_FILE);
22
+ return existsSync(file) ? file : undefined;
23
+ }
24
+ /** findInstrumentation(cwd) → loadInstrumentation. mext dev · mext run (로컬) · stdio 용 */
25
+ export function loadProjectInstrumentation(cwd = process.cwd(), options = {}) {
26
+ return loadInstrumentation(findInstrumentation(cwd), options);
27
+ }
28
+ const loaded = new Map();
29
+ const loadedModules = new WeakMap();
30
+ /**
31
+ * instrumentation 모듈 (파일 경로 · URL · import 된 모듈) 을 프로세스당 1회 import 하고 register() 를 await.
32
+ * 같은 모듈의 두 번째 호출 = register 재호출 없이 같은 hooks. register 실패 = reject (다음 호출에서 재시도).
33
+ * source 없음 = hooks 없이 span 만. 빌드 산출물 (.mext/server/instrumentation.js) 도 같은 함수.
34
+ */
35
+ export async function loadInstrumentation(source, options = {}) {
36
+ const [mod, otel] = await Promise.all([
37
+ source === undefined ? Promise.resolve({}) : registerOnce(source),
38
+ options.importOtel ? resolveOtel(options.importOtel) : defaultOtel(),
39
+ ]);
40
+ return {
41
+ ...(mod.onCommandError ? { onCommandError: mod.onCommandError } : {}),
42
+ ...(otel ? { otel } : {}),
43
+ ...(options.onerror ? { onerror: options.onerror } : {}),
44
+ };
45
+ }
46
+ function registerOnce(source) {
47
+ if (typeof source === "string" || source instanceof URL) {
48
+ const isPath = typeof source === "string" && (isAbsolute(source) || !/^[a-z][a-z0-9+.-]+:/i.test(source));
49
+ const href = isPath ? pathToFileURL(resolve(source)).href : String(source);
50
+ return memo(loaded, href, () => import(__rewriteRelativeImportExtension(href)).then((m) => register(m, href)));
51
+ }
52
+ return memo(loadedModules, source, () => register(source, "instrumentation"));
53
+ }
54
+ function memo(cache, key, load) {
55
+ let pending = cache.get(key);
56
+ if (!pending) {
57
+ pending = load().catch((error) => {
58
+ cache.delete(key);
59
+ throw error;
60
+ });
61
+ cache.set(key, pending);
62
+ }
63
+ return pending;
64
+ }
65
+ async function register(value, label) {
66
+ const mod = (value ?? {});
67
+ for (const key of ["register", "onCommandError"]) {
68
+ if (mod[key] !== undefined && typeof mod[key] !== "function") {
69
+ throw new TypeError(`${label}: export ${key} must be a function`);
70
+ }
71
+ }
72
+ const hooks = mod;
73
+ await hooks.register?.();
74
+ return hooks;
75
+ }
76
+ /* @opentelemetry/api (선택 peer). 번들러가 해석 · 포함하지 않도록 specifier 는 변수 (R5) */
77
+ const OTEL_API = "@opentelemetry/api";
78
+ let otelDefault;
79
+ function defaultOtel() {
80
+ otelDefault ??= resolveOtel(() => import(__rewriteRelativeImportExtension(OTEL_API)));
81
+ return otelDefault;
82
+ }
83
+ async function resolveOtel(importer) {
84
+ try {
85
+ const mod = (await importer());
86
+ const api = mod.trace ? mod : mod.default;
87
+ return api?.trace && api.context && api.propagation && api.SpanStatusCode ? api : undefined;
88
+ }
89
+ catch {
90
+ return undefined;
91
+ }
92
+ }
93
+ /* invoke 에서 사용 */
94
+ const TRACER_NAME = "@obov/mext";
95
+ /**
96
+ * 명령어 실행 1회를 `mext.command <id>` span 으로 감싼다 (otel 있을 때만, 없으면 fn 그대로).
97
+ * 속성 = mext.command.id · mext.transport · mext.principal.kind. 인자 · 결과 · 토큰은 기록하지 않는다.
98
+ * 실패: status ERROR + mext.error.code. 핸들러 예외만 recordException (MextError 메시지는 입력 일부를 담을 수 있어 제외).
99
+ * 취소 (signal abort · MRTR 대기) = status 없음.
100
+ */
101
+ export function observeCommand(command, options, signal, fn) {
102
+ const otel = options.instrumentation?.otel;
103
+ if (!otel)
104
+ return fn();
105
+ const parent = options.traceContext ? otel.propagation.extract(otel.context.active(), options.traceContext) : otel.context.active();
106
+ const attributes = {
107
+ "mext.command.id": command,
108
+ "mext.transport": options.transport ?? "local",
109
+ "mext.principal.kind": options.principal.kind,
110
+ };
111
+ const tracer = otel.trace.getTracer(TRACER_NAME);
112
+ return tracer.startActiveSpan(`mext.command ${command}`, { attributes }, parent, async (span) => {
113
+ try {
114
+ return await fn();
115
+ }
116
+ catch (error) {
117
+ if (!signal()?.aborted) {
118
+ if (isMextError(error)) {
119
+ span.setAttribute("mext.error.code", error.code);
120
+ span.setStatus({ code: otel.SpanStatusCode.ERROR, message: error.code });
121
+ }
122
+ else {
123
+ span.setAttribute("mext.error.code", "EXECUTION_ERROR");
124
+ span.recordException(error);
125
+ span.setStatus({ code: otel.SpanStatusCode.ERROR, message: error instanceof Error ? error.message : String(error) });
126
+ }
127
+ }
128
+ throw error;
129
+ }
130
+ finally {
131
+ span.end();
132
+ }
133
+ });
134
+ }
135
+ /**
136
+ * 핸들러 예외 → onCommandError (await). MextError · 취소 · MRTR 대기는 보고하지 않는다.
137
+ * onCommandError 자체의 예외 = onerror (기본 stderr), 호출자에게 전파하지 않는다.
138
+ */
139
+ export async function reportCommandError(error, command, options, signal) {
140
+ const hook = options.instrumentation?.onCommandError;
141
+ if (!hook || isMextError(error) || signal?.aborted)
142
+ return;
143
+ const info = {
144
+ command,
145
+ transport: options.transport ?? "local",
146
+ principal: { id: options.principal.id, kind: options.principal.kind },
147
+ };
148
+ try {
149
+ await hook(error, info);
150
+ }
151
+ catch (hookError) {
152
+ const onerror = options.instrumentation?.onerror ?? defaultOnError;
153
+ try {
154
+ onerror(hookError);
155
+ }
156
+ catch {
157
+ // 보고는 응답을 바꾸지 않는다
158
+ }
159
+ }
160
+ }
161
+ function defaultOnError(error) {
162
+ const message = error instanceof Error ? (error.stack ?? error.message) : String(error);
163
+ process.stderr.write(`mext: onCommandError threw: ${message}\n`);
164
+ }
165
+ //# sourceMappingURL=instrumentation.js.map
@@ -0,0 +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 { isMextError } 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 */\n command: 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 메시지는 입력 일부를 담을 수 있어 제외).\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 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 attributes = {\n \"mext.command.id\": command,\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(`mext.command ${command}`, { attributes }, parent, async (span) => {\n try {\n return await fn()\n } catch (error) {\n if (!signal()?.aborted) {\n if (isMextError(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 · 취소 · MRTR 대기는 보고하지 않는다.\n * onCommandError 자체의 예외 = onerror (기본 stderr), 호출자에게 전파하지 않는다.\n */\nexport async function reportCommandError(\n error: unknown,\n command: string,\n options: ObserveOptions,\n signal: AbortSignal | undefined,\n): Promise<void> {\n const hook = options.instrumentation?.onCommandError\n if (!hook || isMextError(error) || signal?.aborted) return\n const info: CommandErrorInfo = {\n command,\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"]}
@@ -0,0 +1,64 @@
1
+ import * as z from "zod";
2
+ import type { CommandContext, InputSchema, MextApp, ProgressUpdate } from "./command.ts";
3
+ import { type Instrumentation, type Transport } from "./instrumentation.ts";
4
+ import { findCommand } from "./lookup.ts";
5
+ import { type Principal } from "./principal.ts";
6
+ import { type JsonSchema, type RegisteredCommand, type Registry } from "./registry.ts";
7
+ /** 어댑터가 주입하는 ctx.ask 구현. command = 정식 ID */
8
+ export type AskHandler = (request: AskHandlerRequest) => Promise<unknown>;
9
+ export type AskHandlerRequest = {
10
+ command: string;
11
+ kind: "confirm";
12
+ message: string;
13
+ } | {
14
+ command: string;
15
+ kind: "input";
16
+ message: string;
17
+ schema: InputSchema;
18
+ requestedSchema: JsonSchema;
19
+ };
20
+ export interface InvokeOptions {
21
+ principal: Principal;
22
+ /** 기본 = abort 되지 않는 signal */
23
+ signal?: AbortSignal;
24
+ /** 기본 = 무시 */
25
+ progress?: (update: ProgressUpdate) => void;
26
+ /** 기본 = ctx.ask 호출 시 INPUT_UNAVAILABLE */
27
+ ask?: AskHandler;
28
+ app?: MextApp;
29
+ /** readOnly 명령어만 허용 (split 의 query 도구). 그 외 = PERMISSION_DENIED */
30
+ readOnly?: boolean;
31
+ /** loadInstrumentation 결과. onCommandError · mext.command span. 기본 = 없음 */
32
+ instrumentation?: Instrumentation;
33
+ /** 실행 어댑터 (onCommandError · span 속성). 기본 "local" */
34
+ transport?: Transport;
35
+ /** W3C trace context carrier (MCP params._meta 의 traceparent · tracestate). span 의 부모 */
36
+ traceContext?: Record<string, unknown>;
37
+ }
38
+ export interface InvokeResult {
39
+ /** 정식 ID (별칭으로 호출해도) */
40
+ command: string;
41
+ value: unknown;
42
+ }
43
+ /**
44
+ * 어댑터 공통 실행기: ID 해석 (별칭 포함) → 권한 → (lazy 면 모듈 import) → Zod safeParse 1회 → 확인 (requiresConfirmation) → execute.
45
+ * 실패는 MextError (UNKNOWN_COMMAND · PERMISSION_DENIED · INVALID_ARGUMENT · INPUT_UNAVAILABLE · INPUT_DECLINED).
46
+ * 핸들러 예외는 그대로 전파 (instrumentation 있으면 onCommandError 보고 후).
47
+ * instrumentation.otel 있으면 findCommand 뒤 전체를 `mext.command <id>` span 으로 감싼다.
48
+ */
49
+ export declare function invoke(registry: Registry, id: string, rawInput: unknown, options: InvokeOptions): Promise<InvokeResult>;
50
+ /** ID · 별칭 → 명령어. 없으면 UNKNOWN_COMMAND (suggested · usage). 구현 = lookup.ts (help · 고객 CLI 공용) */
51
+ export { findCommand };
52
+ /**
53
+ * 안전성 메타데이터를 주체에 대해 강제.
54
+ * readOnly 전용 호출 = readOnly 명령어만 · anonymous = readOnly 명령어만 · command.scopes 전부 보유 ("*" = 전체).
55
+ */
56
+ export declare function authorize(entry: RegisteredCommand, principal: Principal, options?: {
57
+ readOnly?: boolean;
58
+ }): void;
59
+ /** Zod safeParse 1회. 실패 = INVALID_ARGUMENT (missing_fields · issues · expected_schema · examples) */
60
+ export declare function parseInput(entry: RegisteredCommand, rawInput: unknown): Promise<z.output<InputSchema>>;
61
+ /** ctx 생성. ask · progress · signal 은 어댑터 주입 */
62
+ export declare function createContext(entry: RegisteredCommand, options: InvokeOptions): CommandContext;
63
+ /** requiresConfirmation 확인 문구. 검증된 입력을 포함 (무엇을 승인하는지) */
64
+ export declare function confirmationMessage(entry: RegisteredCommand, input: unknown): string;
package/dist/invoke.js ADDED
@@ -0,0 +1,152 @@
1
+ import * as z from "zod";
2
+ import { inputDeclined, MextError } from "./errors.js";
3
+ import { observeCommand, reportCommandError } from "./instrumentation.js";
4
+ import { findCommand } from "./lookup.js";
5
+ import { hasScope } from "./principal.js";
6
+ import { loadCommand } from "./registry.js";
7
+ /**
8
+ * 어댑터 공통 실행기: ID 해석 (별칭 포함) → 권한 → (lazy 면 모듈 import) → Zod safeParse 1회 → 확인 (requiresConfirmation) → execute.
9
+ * 실패는 MextError (UNKNOWN_COMMAND · PERMISSION_DENIED · INVALID_ARGUMENT · INPUT_UNAVAILABLE · INPUT_DECLINED).
10
+ * 핸들러 예외는 그대로 전파 (instrumentation 있으면 onCommandError 보고 후).
11
+ * instrumentation.otel 있으면 findCommand 뒤 전체를 `mext.command <id>` span 으로 감싼다.
12
+ */
13
+ export async function invoke(registry, id, rawInput, options) {
14
+ const entry = findCommand(registry, id);
15
+ return observeCommand(entry.id, options, () => options.signal, async () => {
16
+ authorize(entry, options.principal, { readOnly: options.readOnly });
17
+ // lazy Registry (mext start) = 여기서 명령어 모듈 import. 권한 · ID 오류는 import 없이
18
+ const command = await loadCommand(entry);
19
+ const input = await parseInput(entry, rawInput);
20
+ const ctx = createContext(entry, options);
21
+ ctx.signal.throwIfAborted();
22
+ if (entry.command.requiresConfirmation) {
23
+ // 확인은 ctx.ask 경유 (CLI = 프롬프트 · --yes, MCP = MRTR). ask 미주입 = INPUT_UNAVAILABLE
24
+ const confirmed = await ctx.ask({ kind: "confirm", message: confirmationMessage(entry, input) });
25
+ if (!confirmed)
26
+ throw inputDeclined(entry.id, "confirm");
27
+ ctx.signal.throwIfAborted();
28
+ }
29
+ try {
30
+ const value = await command.execute(input, ctx);
31
+ return { command: entry.id, value };
32
+ }
33
+ catch (error) {
34
+ await reportCommandError(error, entry.id, options, ctx.signal);
35
+ throw error;
36
+ }
37
+ });
38
+ }
39
+ /** ID · 별칭 → 명령어. 없으면 UNKNOWN_COMMAND (suggested · usage). 구현 = lookup.ts (help · 고객 CLI 공용) */
40
+ export { findCommand };
41
+ /**
42
+ * 안전성 메타데이터를 주체에 대해 강제.
43
+ * readOnly 전용 호출 = readOnly 명령어만 · anonymous = readOnly 명령어만 · command.scopes 전부 보유 ("*" = 전체).
44
+ */
45
+ export function authorize(entry, principal, options = {}) {
46
+ const c = entry.command;
47
+ const deny = (reason, message) => throwError(new MextError("PERMISSION_DENIED", message, {
48
+ command: entry.id,
49
+ reason,
50
+ required_scopes: [...c.scopes],
51
+ held_scopes: [...principal.scopes],
52
+ }));
53
+ if (options.readOnly && !c.readOnly)
54
+ deny("read_only", `${entry.id} is not read-only and cannot run here.`);
55
+ if (principal.kind === "anonymous" && !c.readOnly) {
56
+ deny("anonymous", `${entry.id} is not read-only and requires an authenticated principal.`);
57
+ }
58
+ const missing = c.scopes.filter((s) => !hasScope(principal, s));
59
+ if (missing.length > 0)
60
+ deny("scope", `${entry.id} requires scopes: ${missing.join(", ")}.`);
61
+ }
62
+ /** Zod safeParse 1회. 실패 = INVALID_ARGUMENT (missing_fields · issues · expected_schema · examples) */
63
+ export async function parseInput(entry, rawInput) {
64
+ const raw = rawInput === undefined ? {} : rawInput;
65
+ const result = await (await loadCommand(entry)).input.safeParseAsync(raw);
66
+ if (result.success)
67
+ return result.data;
68
+ throw invalidArgument(entry.id, raw, result.error.issues, entry.inputSchema, [...entry.command.examples]);
69
+ }
70
+ /** ctx 생성. ask · progress · signal 은 어댑터 주입 */
71
+ export function createContext(entry, options) {
72
+ const handler = options.ask;
73
+ const ask = async (request) => {
74
+ if (!handler) {
75
+ throw new MextError("INPUT_UNAVAILABLE", `${entry.id} requested input, but this environment cannot ask.`, {
76
+ command: entry.id,
77
+ });
78
+ }
79
+ if (request.kind === "confirm") {
80
+ return (await handler({ command: entry.id, kind: "confirm", message: request.message })) === true;
81
+ }
82
+ const requestedSchema = z.toJSONSchema(request.schema, { target: "draft-2020-12", io: "input" });
83
+ const response = await handler({
84
+ command: entry.id,
85
+ kind: "input",
86
+ message: request.message,
87
+ schema: request.schema,
88
+ requestedSchema,
89
+ });
90
+ const parsed = await request.schema.safeParseAsync(response);
91
+ if (parsed.success)
92
+ return parsed.data;
93
+ throw invalidArgument(entry.id, response, parsed.error.issues, requestedSchema, []);
94
+ };
95
+ return {
96
+ principal: options.principal,
97
+ signal: options.signal ?? new AbortController().signal,
98
+ progress: options.progress ?? (() => { }),
99
+ ask: ask,
100
+ app: options.app ?? {},
101
+ };
102
+ }
103
+ /** requiresConfirmation 확인 문구. 검증된 입력을 포함 (무엇을 승인하는지) */
104
+ export function confirmationMessage(entry, input) {
105
+ let args;
106
+ try {
107
+ args = JSON.stringify(input) ?? "{}";
108
+ }
109
+ catch {
110
+ args = "{}";
111
+ }
112
+ return `Run ${entry.id} with ${args}?${entry.command.destructive ? " This command is destructive." : ""}`;
113
+ }
114
+ function invalidArgument(command, raw, zodIssues, expectedSchema, examples) {
115
+ const issues = zodIssues.map((i) => ({
116
+ path: i.path.map(String).join("."),
117
+ code: i.code,
118
+ message: i.message,
119
+ }));
120
+ const missing = new Set();
121
+ for (const i of zodIssues) {
122
+ if (i.code === "invalid_type" && i.path.length > 0 && isAbsent(raw, i.path))
123
+ missing.add(i.path.map(String).join("."));
124
+ }
125
+ const missing_fields = [...missing];
126
+ const summary = missing_fields.length > 0
127
+ ? `missing required: ${missing_fields.join(", ")}`
128
+ : issues.map((i) => (i.path ? `${i.path}: ${i.message}` : i.message)).join("; ");
129
+ return new MextError("INVALID_ARGUMENT", `Invalid arguments for ${command}: ${summary}`, {
130
+ command,
131
+ missing_fields,
132
+ issues,
133
+ expected_schema: expectedSchema,
134
+ examples,
135
+ });
136
+ }
137
+ /** 원본 입력에 경로가 없는지 (값 undefined 포함) */
138
+ function isAbsent(raw, path) {
139
+ let cur = raw;
140
+ for (const key of path) {
141
+ if (cur === null || typeof cur !== "object")
142
+ return true;
143
+ cur = cur[key];
144
+ if (cur === undefined)
145
+ return true;
146
+ }
147
+ return false;
148
+ }
149
+ function throwError(error) {
150
+ throw error;
151
+ }
152
+ //# sourceMappingURL=invoke.js.map