@akon-labs/nexus-cli 0.1.9 → 0.1.10

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 (320) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE +1 -0
  3. package/README.md +3 -2
  4. package/dist/app-bridge.bundle.js +67 -0
  5. package/dist/cli.js +20263 -2158
  6. package/dist/core/agent-session.d.ts.map +1 -1
  7. package/dist/core/agent-session.js +1 -1
  8. package/dist/core/agent-session.js.map +1 -1
  9. package/dist/core/auto-model.d.ts +1 -1
  10. package/dist/core/auto-model.d.ts.map +1 -1
  11. package/dist/core/auto-model.js +1 -1
  12. package/dist/core/auto-model.js.map +1 -1
  13. package/dist/core/model-resolver.d.ts +2 -2
  14. package/dist/core/model-resolver.d.ts.map +1 -1
  15. package/dist/core/model-resolver.js +3 -3
  16. package/dist/core/model-resolver.js.map +1 -1
  17. package/dist/core/package-manager.d.ts +15 -0
  18. package/dist/core/package-manager.d.ts.map +1 -1
  19. package/dist/core/package-manager.js +50 -0
  20. package/dist/core/package-manager.js.map +1 -1
  21. package/dist/core/sdk.d.ts.map +1 -1
  22. package/dist/core/sdk.js +1 -1
  23. package/dist/core/sdk.js.map +1 -1
  24. package/dist/core/slash-commands.d.ts.map +1 -1
  25. package/dist/core/slash-commands.js +3 -3
  26. package/dist/core/slash-commands.js.map +1 -1
  27. package/dist/core/system-prompt.d.ts.map +1 -1
  28. package/dist/core/system-prompt.js +1 -1
  29. package/dist/core/system-prompt.js.map +1 -1
  30. package/dist/core/tools/index.d.ts +1 -1
  31. package/dist/core/tools/index.d.ts.map +1 -1
  32. package/dist/core/tools/index.js +5 -5
  33. package/dist/core/tools/index.js.map +1 -1
  34. package/dist/core/tools/websearch.d.ts.map +1 -1
  35. package/dist/core/tools/websearch.js +3 -3
  36. package/dist/core/tools/websearch.js.map +1 -1
  37. package/dist/extensions/gitnexus/gateway.d.ts +6 -6
  38. package/dist/extensions/gitnexus/gateway.d.ts.map +1 -1
  39. package/dist/extensions/gitnexus/gateway.js +4 -4
  40. package/dist/extensions/gitnexus/gateway.js.map +1 -1
  41. package/dist/extensions/gitnexus/index.d.ts.map +1 -1
  42. package/dist/extensions/gitnexus/index.js +4 -2
  43. package/dist/extensions/gitnexus/index.js.map +1 -1
  44. package/dist/extensions/mcp/abort.d.ts +3 -0
  45. package/dist/extensions/mcp/abort.d.ts.map +1 -0
  46. package/dist/extensions/mcp/abort.js +41 -0
  47. package/dist/extensions/mcp/abort.js.map +1 -0
  48. package/dist/extensions/mcp/agent-dir.d.ts +6 -0
  49. package/dist/extensions/mcp/agent-dir.d.ts.map +1 -0
  50. package/dist/extensions/mcp/agent-dir.js +18 -0
  51. package/dist/extensions/mcp/agent-dir.js.map +1 -0
  52. package/dist/extensions/mcp/agent-plugin-loader.d.ts +9 -0
  53. package/dist/extensions/mcp/agent-plugin-loader.d.ts.map +1 -0
  54. package/dist/extensions/mcp/agent-plugin-loader.js +384 -0
  55. package/dist/extensions/mcp/agent-plugin-loader.js.map +1 -0
  56. package/dist/extensions/mcp/app-bridge.bundle.js +67 -0
  57. package/dist/extensions/mcp/commands.d.ts +27 -0
  58. package/dist/extensions/mcp/commands.d.ts.map +1 -0
  59. package/dist/extensions/mcp/commands.js +629 -0
  60. package/dist/extensions/mcp/commands.js.map +1 -0
  61. package/dist/extensions/mcp/config.d.ts +121 -38
  62. package/dist/extensions/mcp/config.d.ts.map +1 -1
  63. package/dist/extensions/mcp/config.js +1030 -70
  64. package/dist/extensions/mcp/config.js.map +1 -1
  65. package/dist/extensions/mcp/consent-manager.d.ts +14 -0
  66. package/dist/extensions/mcp/consent-manager.d.ts.map +1 -0
  67. package/dist/extensions/mcp/consent-manager.js +60 -0
  68. package/dist/extensions/mcp/consent-manager.js.map +1 -0
  69. package/dist/extensions/mcp/direct-tools.d.ts +11 -0
  70. package/dist/extensions/mcp/direct-tools.d.ts.map +1 -0
  71. package/dist/extensions/mcp/direct-tools.js +562 -0
  72. package/dist/extensions/mcp/direct-tools.js.map +1 -0
  73. package/dist/extensions/mcp/elicitation-handler.d.ts +18 -0
  74. package/dist/extensions/mcp/elicitation-handler.d.ts.map +1 -0
  75. package/dist/extensions/mcp/elicitation-handler.js +320 -0
  76. package/dist/extensions/mcp/elicitation-handler.js.map +1 -0
  77. package/dist/extensions/mcp/error-signal.d.ts +16 -0
  78. package/dist/extensions/mcp/error-signal.d.ts.map +1 -0
  79. package/dist/extensions/mcp/error-signal.js +22 -0
  80. package/dist/extensions/mcp/error-signal.js.map +1 -0
  81. package/dist/extensions/mcp/errors.d.ts +104 -0
  82. package/dist/extensions/mcp/errors.d.ts.map +1 -0
  83. package/dist/extensions/mcp/errors.js +171 -0
  84. package/dist/extensions/mcp/errors.js.map +1 -0
  85. package/dist/extensions/mcp/glimpse-ui.d.ts +10 -0
  86. package/dist/extensions/mcp/glimpse-ui.d.ts.map +1 -0
  87. package/dist/extensions/mcp/glimpse-ui.js +67 -0
  88. package/dist/extensions/mcp/glimpse-ui.js.map +1 -0
  89. package/dist/extensions/mcp/host-html-template.d.ts +17 -0
  90. package/dist/extensions/mcp/host-html-template.d.ts.map +1 -0
  91. package/dist/extensions/mcp/host-html-template.js +442 -0
  92. package/dist/extensions/mcp/host-html-template.js.map +1 -0
  93. package/dist/extensions/mcp/index.d.ts +20 -15
  94. package/dist/extensions/mcp/index.d.ts.map +1 -1
  95. package/dist/extensions/mcp/index.js +1064 -82
  96. package/dist/extensions/mcp/index.js.map +1 -1
  97. package/dist/extensions/mcp/init.d.ts +28 -0
  98. package/dist/extensions/mcp/init.d.ts.map +1 -0
  99. package/dist/extensions/mcp/init.js +631 -0
  100. package/dist/extensions/mcp/init.js.map +1 -0
  101. package/dist/extensions/mcp/json-schema-validator.d.ts +3 -0
  102. package/dist/extensions/mcp/json-schema-validator.d.ts.map +1 -0
  103. package/dist/extensions/mcp/json-schema-validator.js +53 -0
  104. package/dist/extensions/mcp/json-schema-validator.js.map +1 -0
  105. package/dist/extensions/mcp/lifecycle.d.ts +56 -0
  106. package/dist/extensions/mcp/lifecycle.d.ts.map +1 -0
  107. package/dist/extensions/mcp/lifecycle.js +395 -0
  108. package/dist/extensions/mcp/lifecycle.js.map +1 -0
  109. package/dist/extensions/mcp/logger.d.ts +52 -0
  110. package/dist/extensions/mcp/logger.d.ts.map +1 -0
  111. package/dist/extensions/mcp/logger.js +134 -0
  112. package/dist/extensions/mcp/logger.js.map +1 -0
  113. package/dist/extensions/mcp/mcp-auth-flow.d.ts +117 -0
  114. package/dist/extensions/mcp/mcp-auth-flow.d.ts.map +1 -0
  115. package/dist/extensions/mcp/mcp-auth-flow.js +869 -0
  116. package/dist/extensions/mcp/mcp-auth-flow.js.map +1 -0
  117. package/dist/extensions/mcp/mcp-auth.d.ts +162 -0
  118. package/dist/extensions/mcp/mcp-auth.d.ts.map +1 -0
  119. package/dist/extensions/mcp/mcp-auth.js +897 -0
  120. package/dist/extensions/mcp/mcp-auth.js.map +1 -0
  121. package/dist/extensions/mcp/mcp-bearer-store.d.ts +25 -0
  122. package/dist/extensions/mcp/mcp-bearer-store.d.ts.map +1 -0
  123. package/dist/extensions/mcp/mcp-bearer-store.js +350 -0
  124. package/dist/extensions/mcp/mcp-bearer-store.js.map +1 -0
  125. package/dist/extensions/mcp/mcp-callback-server.d.ts +54 -0
  126. package/dist/extensions/mcp/mcp-callback-server.d.ts.map +1 -0
  127. package/dist/extensions/mcp/mcp-callback-server.js +454 -0
  128. package/dist/extensions/mcp/mcp-callback-server.js.map +1 -0
  129. package/dist/extensions/mcp/mcp-code.d.ts +48 -0
  130. package/dist/extensions/mcp/mcp-code.d.ts.map +1 -0
  131. package/dist/extensions/mcp/mcp-code.js +358 -0
  132. package/dist/extensions/mcp/mcp-code.js.map +1 -0
  133. package/dist/extensions/mcp/mcp-keyring-helper.cjs +89 -0
  134. package/dist/extensions/mcp/mcp-oauth-provider.d.ts +135 -0
  135. package/dist/extensions/mcp/mcp-oauth-provider.d.ts.map +1 -0
  136. package/dist/extensions/mcp/mcp-oauth-provider.js +491 -0
  137. package/dist/extensions/mcp/mcp-oauth-provider.js.map +1 -0
  138. package/dist/extensions/mcp/mcp-output-guard.d.ts +59 -0
  139. package/dist/extensions/mcp/mcp-output-guard.d.ts.map +1 -0
  140. package/dist/extensions/mcp/mcp-output-guard.js +343 -0
  141. package/dist/extensions/mcp/mcp-output-guard.js.map +1 -0
  142. package/dist/extensions/mcp/mcp-panel.d.ts +71 -0
  143. package/dist/extensions/mcp/mcp-panel.d.ts.map +1 -0
  144. package/dist/extensions/mcp/mcp-panel.js +973 -0
  145. package/dist/extensions/mcp/mcp-panel.js.map +1 -0
  146. package/dist/extensions/mcp/mcp-probe.d.ts +7 -0
  147. package/dist/extensions/mcp/mcp-probe.d.ts.map +1 -0
  148. package/dist/extensions/mcp/mcp-probe.js +155 -0
  149. package/dist/extensions/mcp/mcp-probe.js.map +1 -0
  150. package/dist/extensions/mcp/mcp-script-worker.mjs +130 -0
  151. package/dist/extensions/mcp/mcp-setup-panel.d.ts +85 -0
  152. package/dist/extensions/mcp/mcp-setup-panel.d.ts.map +1 -0
  153. package/dist/extensions/mcp/mcp-setup-panel.js +618 -0
  154. package/dist/extensions/mcp/mcp-setup-panel.js.map +1 -0
  155. package/dist/extensions/mcp/mcp-status.d.ts +12 -0
  156. package/dist/extensions/mcp/mcp-status.d.ts.map +1 -0
  157. package/dist/extensions/mcp/mcp-status.js +98 -0
  158. package/dist/extensions/mcp/mcp-status.js.map +1 -0
  159. package/dist/extensions/mcp/mcp-trace.d.ts +95 -0
  160. package/dist/extensions/mcp/mcp-trace.d.ts.map +1 -0
  161. package/dist/extensions/mcp/mcp-trace.js +252 -0
  162. package/dist/extensions/mcp/mcp-trace.js.map +1 -0
  163. package/dist/extensions/mcp/metadata-cache.d.ts +20 -0
  164. package/dist/extensions/mcp/metadata-cache.d.ts.map +1 -0
  165. package/dist/extensions/mcp/metadata-cache.js +318 -0
  166. package/dist/extensions/mcp/metadata-cache.js.map +1 -0
  167. package/dist/extensions/mcp/npx-resolver.d.ts +7 -0
  168. package/dist/extensions/mcp/npx-resolver.d.ts.map +1 -0
  169. package/dist/extensions/mcp/npx-resolver.js +505 -0
  170. package/dist/extensions/mcp/npx-resolver.js.map +1 -0
  171. package/dist/extensions/mcp/oauth.d.ts +21 -0
  172. package/dist/extensions/mcp/oauth.d.ts.map +1 -0
  173. package/dist/extensions/mcp/oauth.js +15 -0
  174. package/dist/extensions/mcp/oauth.js.map +1 -0
  175. package/dist/extensions/mcp/onboarding-state.d.ts +13 -0
  176. package/dist/extensions/mcp/onboarding-state.d.ts.map +1 -0
  177. package/dist/extensions/mcp/onboarding-state.js +65 -0
  178. package/dist/extensions/mcp/onboarding-state.js.map +1 -0
  179. package/dist/extensions/mcp/package-mcp-loader.d.ts +3 -0
  180. package/dist/extensions/mcp/package-mcp-loader.d.ts.map +1 -0
  181. package/dist/extensions/mcp/package-mcp-loader.js +170 -0
  182. package/dist/extensions/mcp/package-mcp-loader.js.map +1 -0
  183. package/dist/extensions/mcp/panel-keys.d.ts +21 -0
  184. package/dist/extensions/mcp/panel-keys.d.ts.map +1 -0
  185. package/dist/extensions/mcp/panel-keys.js +29 -0
  186. package/dist/extensions/mcp/panel-keys.js.map +1 -0
  187. package/dist/extensions/mcp/prompts.d.ts +63 -0
  188. package/dist/extensions/mcp/prompts.d.ts.map +1 -0
  189. package/dist/extensions/mcp/prompts.js +297 -0
  190. package/dist/extensions/mcp/prompts.js.map +1 -0
  191. package/dist/extensions/mcp/proxy-modes.d.ts +15 -0
  192. package/dist/extensions/mcp/proxy-modes.d.ts.map +1 -0
  193. package/dist/extensions/mcp/proxy-modes.js +1421 -0
  194. package/dist/extensions/mcp/proxy-modes.js.map +1 -0
  195. package/dist/extensions/mcp/request-headers-command.d.ts +11 -0
  196. package/dist/extensions/mcp/request-headers-command.d.ts.map +1 -0
  197. package/dist/extensions/mcp/request-headers-command.js +334 -0
  198. package/dist/extensions/mcp/request-headers-command.js.map +1 -0
  199. package/dist/extensions/mcp/resource-tools.d.ts +2 -0
  200. package/dist/extensions/mcp/resource-tools.d.ts.map +1 -0
  201. package/dist/extensions/mcp/resource-tools.js +15 -0
  202. package/dist/extensions/mcp/resource-tools.js.map +1 -0
  203. package/dist/extensions/mcp/runtime-owner.d.ts +14 -0
  204. package/dist/extensions/mcp/runtime-owner.d.ts.map +1 -0
  205. package/dist/extensions/mcp/runtime-owner.js +84 -0
  206. package/dist/extensions/mcp/runtime-owner.js.map +1 -0
  207. package/dist/extensions/mcp/sampling-handler.d.ts +18 -0
  208. package/dist/extensions/mcp/sampling-handler.d.ts.map +1 -0
  209. package/dist/extensions/mcp/sampling-handler.js +229 -0
  210. package/dist/extensions/mcp/sampling-handler.js.map +1 -0
  211. package/dist/extensions/mcp/search-ranking.d.ts +25 -0
  212. package/dist/extensions/mcp/search-ranking.d.ts.map +1 -0
  213. package/dist/extensions/mcp/search-ranking.js +234 -0
  214. package/dist/extensions/mcp/search-ranking.js.map +1 -0
  215. package/dist/extensions/mcp/server-manager.d.ts +116 -0
  216. package/dist/extensions/mcp/server-manager.d.ts.map +1 -0
  217. package/dist/extensions/mcp/server-manager.js +1052 -0
  218. package/dist/extensions/mcp/server-manager.js.map +1 -0
  219. package/dist/extensions/mcp/session-recovery.d.ts +27 -0
  220. package/dist/extensions/mcp/session-recovery.d.ts.map +1 -0
  221. package/dist/extensions/mcp/session-recovery.js +140 -0
  222. package/dist/extensions/mcp/session-recovery.js.map +1 -0
  223. package/dist/extensions/mcp/skills/mcp-scripting/SKILL.md +38 -0
  224. package/dist/extensions/mcp/state.d.ts +62 -0
  225. package/dist/extensions/mcp/state.d.ts.map +1 -0
  226. package/dist/extensions/mcp/state.js +2 -0
  227. package/dist/extensions/mcp/state.js.map +1 -0
  228. package/dist/extensions/mcp/tool-approval.d.ts +11 -0
  229. package/dist/extensions/mcp/tool-approval.d.ts.map +1 -0
  230. package/dist/extensions/mcp/tool-approval.js +156 -0
  231. package/dist/extensions/mcp/tool-approval.js.map +1 -0
  232. package/dist/extensions/mcp/tool-metadata.d.ts +11 -0
  233. package/dist/extensions/mcp/tool-metadata.d.ts.map +1 -0
  234. package/dist/extensions/mcp/tool-metadata.js +264 -0
  235. package/dist/extensions/mcp/tool-metadata.js.map +1 -0
  236. package/dist/extensions/mcp/tool-registrar.d.ts +21 -0
  237. package/dist/extensions/mcp/tool-registrar.d.ts.map +1 -0
  238. package/dist/extensions/mcp/tool-registrar.js +229 -0
  239. package/dist/extensions/mcp/tool-registrar.js.map +1 -0
  240. package/dist/extensions/mcp/tool-result-renderer.d.ts +83 -0
  241. package/dist/extensions/mcp/tool-result-renderer.d.ts.map +1 -0
  242. package/dist/extensions/mcp/tool-result-renderer.js +345 -0
  243. package/dist/extensions/mcp/tool-result-renderer.js.map +1 -0
  244. package/dist/extensions/mcp/ts-shape.d.ts +3 -0
  245. package/dist/extensions/mcp/ts-shape.d.ts.map +1 -0
  246. package/dist/extensions/mcp/ts-shape.js +160 -0
  247. package/dist/extensions/mcp/ts-shape.js.map +1 -0
  248. package/dist/extensions/mcp/types.d.ts +521 -0
  249. package/dist/extensions/mcp/types.d.ts.map +1 -0
  250. package/dist/extensions/mcp/types.js +294 -0
  251. package/dist/extensions/mcp/types.js.map +1 -0
  252. package/dist/extensions/mcp/ui-app-bridge-helpers.d.ts +7 -0
  253. package/dist/extensions/mcp/ui-app-bridge-helpers.d.ts.map +1 -0
  254. package/dist/extensions/mcp/ui-app-bridge-helpers.js +37 -0
  255. package/dist/extensions/mcp/ui-app-bridge-helpers.js.map +1 -0
  256. package/dist/extensions/mcp/ui-resource-handler.d.ts +18 -0
  257. package/dist/extensions/mcp/ui-resource-handler.d.ts.map +1 -0
  258. package/dist/extensions/mcp/ui-resource-handler.js +210 -0
  259. package/dist/extensions/mcp/ui-resource-handler.js.map +1 -0
  260. package/dist/extensions/mcp/ui-server.d.ts +52 -0
  261. package/dist/extensions/mcp/ui-server.d.ts.map +1 -0
  262. package/dist/extensions/mcp/ui-server.js +740 -0
  263. package/dist/extensions/mcp/ui-server.js.map +1 -0
  264. package/dist/extensions/mcp/ui-session.d.ts +40 -0
  265. package/dist/extensions/mcp/ui-session.d.ts.map +1 -0
  266. package/dist/extensions/mcp/ui-session.js +477 -0
  267. package/dist/extensions/mcp/ui-session.js.map +1 -0
  268. package/dist/extensions/mcp/ui-stream-types.d.ts +105 -0
  269. package/dist/extensions/mcp/ui-stream-types.d.ts.map +1 -0
  270. package/dist/extensions/mcp/ui-stream-types.js +61 -0
  271. package/dist/extensions/mcp/ui-stream-types.js.map +1 -0
  272. package/dist/extensions/mcp/ui-tool-visibility.d.ts +5 -0
  273. package/dist/extensions/mcp/ui-tool-visibility.d.ts.map +1 -0
  274. package/dist/extensions/mcp/ui-tool-visibility.js +27 -0
  275. package/dist/extensions/mcp/ui-tool-visibility.js.map +1 -0
  276. package/dist/extensions/mcp/unix-socket-transport.d.ts +15 -0
  277. package/dist/extensions/mcp/unix-socket-transport.d.ts.map +1 -0
  278. package/dist/extensions/mcp/unix-socket-transport.js +85 -0
  279. package/dist/extensions/mcp/unix-socket-transport.js.map +1 -0
  280. package/dist/extensions/mcp/utils.d.ts +32 -0
  281. package/dist/extensions/mcp/utils.d.ts.map +1 -0
  282. package/dist/extensions/mcp/utils.js +336 -0
  283. package/dist/extensions/mcp/utils.js.map +1 -0
  284. package/dist/extensions/subagent/index.d.ts +61 -1
  285. package/dist/extensions/subagent/index.d.ts.map +1 -1
  286. package/dist/extensions/subagent/index.js +177 -4
  287. package/dist/extensions/subagent/index.js.map +1 -1
  288. package/dist/extensions/web-access.d.ts.map +1 -1
  289. package/dist/extensions/web-access.js +1 -1
  290. package/dist/extensions/web-access.js.map +1 -1
  291. package/dist/index.d.ts +2 -0
  292. package/dist/index.d.ts.map +1 -1
  293. package/dist/index.js +20057 -1947
  294. package/dist/index.js.map +1 -1
  295. package/dist/mcp-keyring-helper.cjs +89 -0
  296. package/dist/mcp-script-worker.mjs +130 -0
  297. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  298. package/dist/modes/interactive/components/model-selector.js +1 -1
  299. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  300. package/dist/modes/interactive/components/response-separator.d.ts +1 -1
  301. package/dist/modes/interactive/components/response-separator.d.ts.map +1 -1
  302. package/dist/modes/interactive/components/response-separator.js +1 -1
  303. package/dist/modes/interactive/components/response-separator.js.map +1 -1
  304. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  305. package/dist/modes/interactive/interactive-mode.js +7 -5
  306. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  307. package/dist/rpc-entry.js +20263 -2158
  308. package/dist/skills/mcp-scripting/SKILL.md +38 -0
  309. package/dist/vendor/ai.js +280 -205
  310. package/docs/mcp.md +178 -0
  311. package/docs/pi-subagents.md +75 -0
  312. package/docs/quickstart.md +1 -1
  313. package/docs/usage.md +2 -1
  314. package/examples/extensions/pi-subagents-worker-policy.ts +86 -0
  315. package/npm-shrinkwrap.json +763 -6
  316. package/package.json +15 -4
  317. package/dist/extensions/mcp/client.d.ts +0 -86
  318. package/dist/extensions/mcp/client.d.ts.map +0 -1
  319. package/dist/extensions/mcp/client.js +0 -275
  320. package/dist/extensions/mcp/client.js.map +0 -1
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { createRequire } = require('node:module');
5
+ const { dirname, join } = require('node:path');
6
+
7
+ const requireFromHere = createRequire(__filename);
8
+
9
+ function loadKeyringEntryClass() {
10
+ try {
11
+ return requireFromHere('@napi-rs/keyring').Entry;
12
+ } catch (loaderError) {
13
+ const suffixes = getNativeBindingSuffixes(process.platform, process.arch);
14
+ let lastError;
15
+ for (const suffix of suffixes) {
16
+ try {
17
+ const packageJsonPath = requireFromHere.resolve(`@napi-rs/keyring-${suffix}/package.json`);
18
+ return requireFromHere(join(dirname(packageJsonPath), `keyring.${suffix}.node`)).Entry;
19
+ } catch (error) {
20
+ lastError = error;
21
+ }
22
+ }
23
+ const error = new Error(`Failed to load @napi-rs/keyring in recovery helper: ${lastError?.message ?? loaderError.message}`);
24
+ error.cause = loaderError;
25
+ throw error;
26
+ }
27
+ }
28
+
29
+ function getNativeBindingSuffixes(platform, arch) {
30
+ if (platform === 'linux') {
31
+ if (arch === 'arm64') return ['linux-arm64-gnu', 'linux-arm64-musl'];
32
+ if (arch === 'arm') return ['linux-arm-gnueabihf'];
33
+ if (arch === 'riscv64') return ['linux-riscv64-gnu'];
34
+ if (arch === 'x64') return ['linux-x64-gnu', 'linux-x64-musl'];
35
+ }
36
+ return [];
37
+ }
38
+
39
+ function readStdin() {
40
+ return new Promise((resolve, reject) => {
41
+ let input = '';
42
+ process.stdin.setEncoding('utf8');
43
+ process.stdin.on('data', chunk => {
44
+ input += chunk;
45
+ if (input.length > 1024 * 1024) {
46
+ reject(new Error('request too large'));
47
+ process.stdin.destroy();
48
+ }
49
+ });
50
+ process.stdin.on('error', reject);
51
+ process.stdin.on('end', () => resolve(input));
52
+ });
53
+ }
54
+
55
+ function writeResponse(response) {
56
+ process.stdout.write(`${JSON.stringify(response)}\n`);
57
+ }
58
+
59
+ (async () => {
60
+ try {
61
+ const request = JSON.parse(await readStdin());
62
+ if (!request || typeof request !== 'object') throw new Error('invalid request');
63
+ const { operation, service, account, payload } = request;
64
+ if (!['read', 'write', 'remove'].includes(operation)) throw new Error('invalid operation');
65
+ if (typeof service !== 'string' || !service) throw new Error('invalid service');
66
+ if (typeof account !== 'string' || !account) throw new Error('invalid account');
67
+
68
+ const Entry = loadKeyringEntryClass();
69
+ const entry = new Entry(service, account);
70
+
71
+ if (operation === 'read') {
72
+ const value = entry.getPassword();
73
+ writeResponse(value === null ? { ok: true, found: false } : { ok: true, found: true, value });
74
+ return;
75
+ }
76
+ if (operation === 'write') {
77
+ if (typeof payload !== 'string') throw new Error('invalid payload');
78
+ entry.setPassword(payload);
79
+ writeResponse({ ok: true });
80
+ return;
81
+ }
82
+
83
+ entry.deleteCredential();
84
+ writeResponse({ ok: true });
85
+ } catch (error) {
86
+ writeResponse({ ok: false, error: error instanceof Error ? error.message : String(error) });
87
+ process.exitCode = 1;
88
+ }
89
+ })();
@@ -0,0 +1,135 @@
1
+ /**
2
+ * MCP OAuth Provider
3
+ *
4
+ * Implementation of the MCP SDK's OAuthClientProvider interface.
5
+ * Handles OAuth client registration, token storage, and authorization redirection.
6
+ */
7
+ import type { OAuthClientInformationMixed, OAuthClientMetadata, OAuthTokens } from "@modelcontextprotocol/client";
8
+ import { type AddClientAuthentication, type OAuthClientProvider, type OAuthDiscoveryState } from "@modelcontextprotocol/client";
9
+ import { type AuthStorageOptions } from "./mcp-auth.ts";
10
+ declare const DEFAULT_OAUTH_CALLBACK_PORT = 19876;
11
+ declare const DEFAULT_OAUTH_CALLBACK_PATH = "/callback";
12
+ export declare function getConfiguredOAuthCallbackPort(): number;
13
+ export declare function getOAuthCallbackPort(): number;
14
+ export declare function setOAuthCallbackPort(port: number): void;
15
+ export declare function getOAuthCallbackPath(): string;
16
+ export declare function setOAuthCallbackPath(path: string): void;
17
+ /** Configuration options for OAuth */
18
+ export interface McpOAuthConfig {
19
+ grantType?: "authorization_code" | "client_credentials";
20
+ clientId?: string;
21
+ clientSecret?: string;
22
+ scope?: string;
23
+ authorizationParams?: Record<string, string>;
24
+ redirectUri?: string;
25
+ clientName?: string;
26
+ clientUri?: string;
27
+ logoUri?: string;
28
+ skipIssuerMetadataValidation?: boolean;
29
+ }
30
+ /** Callbacks for OAuth flow interactions */
31
+ export interface McpOAuthCallbacks {
32
+ onRedirect: (url: URL) => void | Promise<void>;
33
+ }
34
+ /**
35
+ * OAuth provider implementation for MCP servers.
36
+ * Implements the OAuthClientProvider interface from the MCP SDK.
37
+ */
38
+ export declare class McpOAuthProvider implements OAuthClientProvider {
39
+ private readonly redirectUrlSnapshot;
40
+ private active;
41
+ private flowClientInfo;
42
+ private flowCodeVerifier;
43
+ private flowDiscoveryState;
44
+ private flowIssuerMismatch;
45
+ private flowState;
46
+ private serverName;
47
+ private serverUrl;
48
+ private config;
49
+ private callbacks;
50
+ private storageOptions;
51
+ private runtimeSignal;
52
+ constructor(serverName: string, serverUrl: string, config: McpOAuthConfig, callbacks: McpOAuthCallbacks, storageOptions?: AuthStorageOptions, runtimeSignal?: AbortSignal, initialState?: string);
53
+ private get usesClientCredentials();
54
+ private get discoveredIssuer();
55
+ deactivate(): void;
56
+ private assertStoredIssuerBindings;
57
+ private throwIfInactive;
58
+ /**
59
+ * The redirect URL for OAuth callbacks.
60
+ * This must match the redirect_uri in client metadata.
61
+ */
62
+ get redirectUrl(): string | undefined;
63
+ /** Configured homepage, otherwise the Nexus repository. */
64
+ private get clientUri();
65
+ /**
66
+ * Client metadata for dynamic registration.
67
+ * Describes this client to the OAuth authorization server.
68
+ */
69
+ get clientMetadata(): OAuthClientMetadata;
70
+ /**
71
+ * Get client information (for pre-registered or dynamically registered clients).
72
+ * Returns undefined if no client info exists or if the server URL has changed.
73
+ */
74
+ clientInformation(): Promise<OAuthClientInformationMixed | undefined>;
75
+ /**
76
+ * Save client information from dynamic registration.
77
+ */
78
+ saveClientInformation(info: OAuthClientInformationMixed): Promise<void>;
79
+ /**
80
+ * Get stored OAuth tokens.
81
+ * Returns undefined if no tokens exist or if the server URL has changed.
82
+ */
83
+ tokens(): Promise<OAuthTokens | undefined>;
84
+ /**
85
+ * Save OAuth tokens.
86
+ */
87
+ saveTokens(tokens: OAuthTokens): Promise<void>;
88
+ /**
89
+ * Redirect the user to the authorization URL.
90
+ * This opens the browser for the user to authenticate.
91
+ *
92
+ * Throws UnauthorizedError when called outside of a user-initiated flow
93
+ * (no oauthState saved by startAuth). That path is reached when the SDK
94
+ * falls through from a failed refresh into a fresh authorization_code
95
+ * flow, which library hosts cannot complete in-process.
96
+ */
97
+ redirectToAuthorization(authorizationUrl: URL): Promise<void>;
98
+ /**
99
+ * Save the PKCE code verifier.
100
+ */
101
+ saveCodeVerifier(codeVerifier: string): Promise<void>;
102
+ /**
103
+ * Get the stored PKCE code verifier.
104
+ * @throws Error if no code verifier is stored
105
+ */
106
+ codeVerifier(): Promise<string>;
107
+ /**
108
+ * Keep discovery with the in-flight PKCE verifier. The callback leg uses it
109
+ * to validate the authorization response issuer before token exchange.
110
+ */
111
+ saveDiscoveryState(state: OAuthDiscoveryState): Promise<void>;
112
+ discoveryState(): Promise<OAuthDiscoveryState | undefined>;
113
+ /**
114
+ * Save the OAuth state parameter for CSRF protection.
115
+ */
116
+ saveState(state: string): Promise<void>;
117
+ /**
118
+ * Get the stored OAuth state parameter.
119
+ * @throws UnauthorizedError if no flow is in progress (see redirectToAuthorization)
120
+ */
121
+ state(): Promise<string>;
122
+ /**
123
+ * Invalidate credentials when authentication fails.
124
+ * Clears tokens, client info, or all credentials based on the type.
125
+ */
126
+ invalidateCredentials(type: "all" | "client" | "tokens" | "verifier" | "discovery"): Promise<void>;
127
+ /**
128
+ * Adds configured authorization-code scope without replacing the SDK's
129
+ * default token endpoint authentication behavior.
130
+ */
131
+ addClientAuthentication: AddClientAuthentication;
132
+ prepareTokenRequest(scope?: string): URLSearchParams | undefined;
133
+ }
134
+ export { DEFAULT_OAUTH_CALLBACK_PORT, DEFAULT_OAUTH_CALLBACK_PATH };
135
+ //# sourceMappingURL=mcp-oauth-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-oauth-provider.d.ts","sourceRoot":"","sources":["../../../src/extensions/mcp/mcp-oauth-provider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAClH,OAAO,EACN,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EAExB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAEN,KAAK,kBAAkB,EAUvB,MAAM,eAAe,CAAC;AAmCvB,QAAA,MAAM,2BAA2B,QAAQ,CAAC;AAC1C,QAAA,MAAM,2BAA2B,cAAc,CAAC;AAchD,wBAAgB,8BAA8B,IAAI,MAAM,CAEvD;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEvD;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEvD;AAED,sCAAsC;AACtC,MAAM,WAAW,cAAc;IAC9B,SAAS,CAAC,EAAE,oBAAoB,GAAG,oBAAoB,CAAC;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4BAA4B,CAAC,EAAE,OAAO,CAAC;CACvC;AAyBD,4CAA4C;AAC5C,MAAM,WAAW,iBAAiB;IACjC,UAAU,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAED;;;GAGG;AACH,qBAAa,gBAAiB,YAAW,mBAAmB;IAC3D,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAqB;IACzD,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,kBAAkB,CAAkC;IAC5D,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,cAAc,CAAqB;IAC3C,OAAO,CAAC,aAAa,CAA0B;IAE/C,YACC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,iBAAiB,EAC5B,cAAc,GAAE,kBAAuB,EACvC,aAAa,CAAC,EAAE,WAAW,EAC3B,YAAY,CAAC,EAAE,MAAM,EAarB;IAED,OAAO,KAAK,qBAAqB,GAEhC;IAED,OAAO,KAAK,gBAAgB,GAI3B;IAED,UAAU,IAAI,IAAI,CAEjB;IAED,OAAO,CAAC,0BAA0B;IAmBlC,OAAO,CAAC,eAAe;IAKvB;;;OAGG;IACH,IAAI,WAAW,IAAI,MAAM,GAAG,SAAS,CAEpC;IAED,2DAA2D;IAC3D,OAAO,KAAK,SAAS,GAEpB;IAED;;;OAGG;IACH,IAAI,cAAc,IAAI,mBAAmB,CA2BxC;IAED;;;OAGG;IACG,iBAAiB,IAAI,OAAO,CAAC,2BAA2B,GAAG,SAAS,CAAC,CAsE1E;IAED;;OAEG;IACG,qBAAqB,CAAC,IAAI,EAAE,2BAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC5E;IAED;;;OAGG;IACG,MAAM,IAAI,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAsB/C;IAED;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBnD;IAED;;;;;;;;OAQG;IACG,uBAAuB,CAAC,gBAAgB,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAWlE;IAED;;OAEG;IACG,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG1D;IAED;;;OAGG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CASpC;IAED;;;OAGG;IACG,kBAAkB,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAGlE;IAEK,cAAc,IAAI,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC,CAG/D;IAED;;OAEG;IACG,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG5C;IAED;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAS7B;IAED;;;OAGG;IACG,qBAAqB,CAAC,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBvG;IAED;;;OAGG;IACH,uBAAuB,EAAE,uBAAuB,CA6C9C;IAEF,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAW/D;CACD;AAED,OAAO,EAAE,2BAA2B,EAAE,2BAA2B,EAAE,CAAC","sourcesContent":["/**\n * MCP OAuth Provider\n *\n * Implementation of the MCP SDK's OAuthClientProvider interface.\n * Handles OAuth client registration, token storage, and authorization redirection.\n */\n\nimport type { OAuthClientInformationMixed, OAuthClientMetadata, OAuthTokens } from \"@modelcontextprotocol/client\";\nimport {\n\ttype AddClientAuthentication,\n\ttype OAuthClientProvider,\n\ttype OAuthDiscoveryState,\n\tUnauthorizedError,\n} from \"@modelcontextprotocol/client\";\nimport { getAppClientUri, getAppName } from \"./agent-dir.ts\";\nimport {\n\ttype AuthEntry,\n\ttype AuthStorageOptions,\n\tclearAllCredentials,\n\tclearClientInfo,\n\tclearCodeVerifier,\n\tclearTokens,\n\tgetAuthForUrl,\n\ttype StoredClientInfo,\n\ttype StoredTokens,\n\tupdateClientInfo,\n\tupdateTokens,\n} from \"./mcp-auth.ts\";\nimport { resolveCommandSecret } from \"./utils.ts\";\n\n/**\n * Client name advertised during Dynamic Client Registration.\n *\n * OAuth consent screens must identify the application users are running.\n */\nfunction defaultClientName(): string {\n\treturn getAppName();\n}\n\n/**\n * Client homepage advertised during Dynamic Client Registration.\n *\n * RFC 7591 defines client_uri as the home page of the client.\n */\nfunction defaultClientUri(): string | undefined {\n\tconst declared = getAppClientUri();\n\tif (declared) return declared;\n\treturn getAppName() === \"Nexus\" ? \"https://github.com/Akon-Labs/nexus-cli\" : undefined;\n}\n\ntype IssuerBoundClientInformation = OAuthClientInformationMixed & { issuer?: string };\ntype IssuerBoundTokens = OAuthTokens & { issuer?: string };\n\nfunction issuersMatch(first: string, second: string): boolean {\n\treturn (\n\t\tfirst === second ||\n\t\t(first.endsWith(\"/\") && first.slice(0, -1) === second) ||\n\t\t(second.endsWith(\"/\") && second.slice(0, -1) === first)\n\t);\n}\n\n// Callback server configuration\nconst DEFAULT_OAUTH_CALLBACK_PORT = 19876;\nconst DEFAULT_OAUTH_CALLBACK_PATH = \"/callback\";\n\nlet configuredOAuthCallbackPort = DEFAULT_OAUTH_CALLBACK_PORT;\n\nif (process.env.MCP_OAUTH_CALLBACK_PORT) {\n\tconst parsedPort = Number.parseInt(process.env.MCP_OAUTH_CALLBACK_PORT, 10);\n\tif (Number.isInteger(parsedPort) && parsedPort > 0 && parsedPort <= 65535) {\n\t\tconfiguredOAuthCallbackPort = parsedPort;\n\t}\n}\n\nlet oauthCallbackPort = configuredOAuthCallbackPort;\nlet oauthCallbackPath = DEFAULT_OAUTH_CALLBACK_PATH;\n\nexport function getConfiguredOAuthCallbackPort(): number {\n\treturn configuredOAuthCallbackPort;\n}\n\nexport function getOAuthCallbackPort(): number {\n\treturn oauthCallbackPort;\n}\n\nexport function setOAuthCallbackPort(port: number): void {\n\toauthCallbackPort = port;\n}\n\nexport function getOAuthCallbackPath(): string {\n\treturn oauthCallbackPath;\n}\n\nexport function setOAuthCallbackPath(path: string): void {\n\toauthCallbackPath = path.startsWith(\"/\") ? path : `/${path}`;\n}\n\n/** Configuration options for OAuth */\nexport interface McpOAuthConfig {\n\tgrantType?: \"authorization_code\" | \"client_credentials\";\n\tclientId?: string;\n\tclientSecret?: string;\n\tscope?: string;\n\tauthorizationParams?: Record<string, string>;\n\tredirectUri?: string;\n\tclientName?: string;\n\tclientUri?: string;\n\tlogoUri?: string;\n\tskipIssuerMetadataValidation?: boolean;\n}\n\nconst reservedAuthorizationParams = new Set([\n\t\"client_id\",\n\t\"code_challenge\",\n\t\"code_challenge_method\",\n\t\"redirect_uri\",\n\t\"resource\",\n\t\"response_type\",\n\t\"scope\",\n\t\"state\",\n]);\n\nfunction addAuthorizationParams(authorizationUrl: URL, params: Record<string, string> | undefined): URL {\n\tif (!params) return authorizationUrl;\n\tconst nextUrl = new URL(authorizationUrl.toString());\n\tfor (const [key, value] of Object.entries(params)) {\n\t\tif (reservedAuthorizationParams.has(key) || nextUrl.searchParams.has(key)) {\n\t\t\tthrow new Error(`OAuth authorizationParams.${key} cannot override an authorization flow parameter`);\n\t\t}\n\t\tnextUrl.searchParams.set(key, value);\n\t}\n\treturn nextUrl;\n}\n\n/** Callbacks for OAuth flow interactions */\nexport interface McpOAuthCallbacks {\n\tonRedirect: (url: URL) => void | Promise<void>;\n}\n\n/**\n * OAuth provider implementation for MCP servers.\n * Implements the OAuthClientProvider interface from the MCP SDK.\n */\nexport class McpOAuthProvider implements OAuthClientProvider {\n\tprivate readonly redirectUrlSnapshot: string | undefined;\n\tprivate active = true;\n\tprivate flowClientInfo: StoredClientInfo | undefined;\n\tprivate flowCodeVerifier: string | undefined;\n\tprivate flowDiscoveryState: OAuthDiscoveryState | undefined;\n\tprivate flowIssuerMismatch = false;\n\tprivate flowState: string | undefined;\n\tprivate serverName: string;\n\tprivate serverUrl: string;\n\tprivate config: McpOAuthConfig;\n\tprivate callbacks: McpOAuthCallbacks;\n\tprivate storageOptions: AuthStorageOptions;\n\tprivate runtimeSignal: AbortSignal | undefined;\n\n\tconstructor(\n\t\tserverName: string,\n\t\tserverUrl: string,\n\t\tconfig: McpOAuthConfig,\n\t\tcallbacks: McpOAuthCallbacks,\n\t\tstorageOptions: AuthStorageOptions = {},\n\t\truntimeSignal?: AbortSignal,\n\t\tinitialState?: string,\n\t) {\n\t\tthis.serverName = serverName;\n\t\tthis.serverUrl = serverUrl;\n\t\tthis.config = config;\n\t\tthis.callbacks = callbacks;\n\t\tthis.storageOptions = storageOptions;\n\t\tthis.runtimeSignal = runtimeSignal;\n\t\tthis.flowState = initialState;\n\t\tthis.redirectUrlSnapshot =\n\t\t\tconfig.grantType === \"client_credentials\"\n\t\t\t\t? undefined\n\t\t\t\t: (config.redirectUri ?? `http://localhost:${getOAuthCallbackPort()}${getOAuthCallbackPath()}`);\n\t}\n\n\tprivate get usesClientCredentials(): boolean {\n\t\treturn this.config.grantType === \"client_credentials\";\n\t}\n\n\tprivate get discoveredIssuer(): string | undefined {\n\t\treturn (\n\t\t\tthis.flowDiscoveryState?.authorizationServerMetadata?.issuer ?? this.flowDiscoveryState?.authorizationServerUrl\n\t\t);\n\t}\n\n\tdeactivate(): void {\n\t\tthis.active = false;\n\t}\n\n\tprivate assertStoredIssuerBindings(entry: AuthEntry | undefined, issuer: string | undefined): void {\n\t\tif (this.flowIssuerMismatch) {\n\t\t\tthrow new Error(\n\t\t\t\t`OAuth authorization server issuer changed for ${this.serverName}; clear credentials before authenticating again`,\n\t\t\t);\n\t\t}\n\t\tif (!entry || !issuer) return;\n\n\t\tconst storedIssuers = [entry.clientInfo?.issuer, entry.tokens?.issuer].filter(\n\t\t\t(storedIssuer): storedIssuer is string => storedIssuer !== undefined,\n\t\t);\n\t\tif (storedIssuers.some((storedIssuer) => !issuersMatch(storedIssuer, issuer))) {\n\t\t\tthis.flowIssuerMismatch = true;\n\t\t\tthrow new Error(\n\t\t\t\t`OAuth authorization server issuer changed for ${this.serverName}; clear credentials before authenticating again`,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate throwIfInactive(): void {\n\t\tif (!this.active) throw new Error(\"OAuth flow is no longer active\");\n\t\tthis.runtimeSignal?.throwIfAborted();\n\t}\n\n\t/**\n\t * The redirect URL for OAuth callbacks.\n\t * This must match the redirect_uri in client metadata.\n\t */\n\tget redirectUrl(): string | undefined {\n\t\treturn this.redirectUrlSnapshot;\n\t}\n\n\t/** Configured homepage, otherwise the Nexus repository. */\n\tprivate get clientUri(): string | undefined {\n\t\treturn this.config.clientUri ?? defaultClientUri();\n\t}\n\n\t/**\n\t * Client metadata for dynamic registration.\n\t * Describes this client to the OAuth authorization server.\n\t */\n\tget clientMetadata(): OAuthClientMetadata {\n\t\tif (this.usesClientCredentials) {\n\t\t\treturn {\n\t\t\t\tclient_name: this.config.clientName ?? defaultClientName(),\n\t\t\t\t...(this.clientUri !== undefined ? { client_uri: this.clientUri } : {}),\n\t\t\t\t...(this.config.logoUri !== undefined ? { logo_uri: this.config.logoUri } : {}),\n\t\t\t\tredirect_uris: [],\n\t\t\t\tgrant_types: [\"client_credentials\"],\n\t\t\t\ttoken_endpoint_auth_method: this.config.clientSecret ? \"client_secret_post\" : \"none\",\n\t\t\t};\n\t\t}\n\n\t\tconst redirectUrl = this.redirectUrl;\n\t\tif (!redirectUrl) {\n\t\t\tthrow new Error(\"redirectUrl is required for authorization_code flow\");\n\t\t}\n\n\t\treturn {\n\t\t\tredirect_uris: [redirectUrl],\n\t\t\tclient_name: this.config.clientName ?? defaultClientName(),\n\t\t\t...(this.clientUri !== undefined ? { client_uri: this.clientUri } : {}),\n\t\t\t...(this.config.logoUri !== undefined ? { logo_uri: this.config.logoUri } : {}),\n\t\t\tgrant_types: [\"authorization_code\", \"refresh_token\"],\n\t\t\tresponse_types: [\"code\"],\n\t\t\ttoken_endpoint_auth_method: this.config.clientSecret ? \"client_secret_post\" : \"none\",\n\t\t\t...(this.config.scope !== undefined ? { scope: this.config.scope } : {}),\n\t\t};\n\t}\n\n\t/**\n\t * Get client information (for pre-registered or dynamically registered clients).\n\t * Returns undefined if no client info exists or if the server URL has changed.\n\t */\n\tasync clientInformation(): Promise<OAuthClientInformationMixed | undefined> {\n\t\tconst issuer = this.discoveredIssuer;\n\t\tconst stored = await getAuthForUrl(this.serverName, this.serverUrl, this.storageOptions);\n\t\tthis.assertStoredIssuerBindings(stored, issuer);\n\n\t\t// Check config first (pre-registered client). Store only its issuer binding.\n\t\t// The configured secret stays in config and never enters the credential store.\n\t\tif (this.config.clientId) {\n\t\t\tconst storedClient = stored?.clientInfo?.clientId === this.config.clientId ? stored.clientInfo : undefined;\n\t\t\tif (issuer && (storedClient?.issuer !== issuer || storedClient.configPreRegistered !== true)) {\n\t\t\t\tupdateClientInfo(\n\t\t\t\t\tthis.serverName,\n\t\t\t\t\t{ clientId: this.config.clientId, issuer, configPreRegistered: true },\n\t\t\t\t\tthis.serverUrl,\n\t\t\t\t\tthis.storageOptions,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst clientSecret = this.config.clientSecret?.startsWith(\"!\")\n\t\t\t\t? resolveCommandSecret(this.config.clientSecret, `MCP server \"${this.serverName}\" OAuth clientSecret`)\n\t\t\t\t: this.config.clientSecret;\n\t\t\treturn {\n\t\t\t\tclient_id: this.config.clientId,\n\t\t\t\tclient_secret: clientSecret,\n\t\t\t\t...(issuer !== undefined ? { issuer } : {}),\n\t\t\t} as IssuerBoundClientInformation;\n\t\t}\n\n\t\t// Keep client registration associated with this in-flight flow even if\n\t\t// another runtime writes the shared persistent entry for the same name.\n\t\tconst clientInfo = this.flowClientInfo ?? stored?.clientInfo;\n\t\tif (clientInfo) {\n\t\t\t// A stored SEP-2352 issuer stub for a config-pre-registered client\n\t\t\t// (identified by its explicit marker) is only meaningful\n\t\t\t// when the config supplies the matching client secret. Since we reach\n\t\t\t// this branch only when config.clientId is absent, serving the stub\n\t\t\t// would let a token refresh go out with a client_id but no secret,\n\t\t\t// causing invalid_client and credential invalidation. Return undefined\n\t\t\t// so callers treat this as \"no client info\".\n\t\t\tconst isConfigStub = clientInfo.configPreRegistered === true;\n\t\t\tif (isConfigStub) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\t// Check if client secret has expired\n\t\t\tif (clientInfo.clientSecretExpiresAt && clientInfo.clientSecretExpiresAt < Date.now() / 1000) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tif (issuer && clientInfo.issuer && !issuersMatch(clientInfo.issuer, issuer)) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tif (issuer && clientInfo.issuer === undefined) {\n\t\t\t\tclientInfo.issuer = issuer;\n\t\t\t\tthis.flowClientInfo = clientInfo;\n\t\t\t\tupdateClientInfo(this.serverName, clientInfo, this.serverUrl, this.storageOptions);\n\t\t\t}\n\t\t\t// Return all registration metadata and the local issuer extension.\n\t\t\t// This keeps the SDK OAuth view and the stored issuer binding consistent.\n\t\t\treturn {\n\t\t\t\tclient_id: clientInfo.clientId,\n\t\t\t\tclient_secret: clientInfo.clientSecret,\n\t\t\t\t...(clientInfo.clientIdIssuedAt !== undefined ? { client_id_issued_at: clientInfo.clientIdIssuedAt } : {}),\n\t\t\t\t...(clientInfo.clientSecretExpiresAt !== undefined\n\t\t\t\t\t? { client_secret_expires_at: clientInfo.clientSecretExpiresAt }\n\t\t\t\t\t: {}),\n\t\t\t\t...(clientInfo.redirectUris !== undefined ? { redirect_uris: clientInfo.redirectUris } : {}),\n\t\t\t\t...(clientInfo.issuer !== undefined ? { issuer: clientInfo.issuer } : {}),\n\t\t\t} as IssuerBoundClientInformation;\n\t\t}\n\n\t\t// No client info or URL changed - will trigger dynamic registration\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Save client information from dynamic registration.\n\t */\n\tasync saveClientInformation(info: OAuthClientInformationMixed): Promise<void> {\n\t\tthis.throwIfInactive();\n\t\tconst issuer = this.discoveredIssuer ?? (info as IssuerBoundClientInformation).issuer;\n\t\tif (this.config.clientId && info.client_id === this.config.clientId) {\n\t\t\tupdateClientInfo(\n\t\t\t\tthis.serverName,\n\t\t\t\t{\n\t\t\t\t\tclientId: info.client_id,\n\t\t\t\t\t...(issuer !== undefined ? { issuer } : {}),\n\t\t\t\t\tconfigPreRegistered: true,\n\t\t\t\t},\n\t\t\t\tthis.serverUrl,\n\t\t\t\tthis.storageOptions,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst redirectUris =\n\t\t\t(\"redirect_uris\" in info ? info.redirect_uris : undefined) ??\n\t\t\t(this.redirectUrl ? [this.redirectUrl] : undefined);\n\t\tconst clientInfo: StoredClientInfo = {\n\t\t\tclientId: info.client_id,\n\t\t\t...(info.client_secret !== undefined ? { clientSecret: info.client_secret } : {}),\n\t\t\t...(info.client_id_issued_at !== undefined ? { clientIdIssuedAt: info.client_id_issued_at } : {}),\n\t\t\t...(info.client_secret_expires_at !== undefined\n\t\t\t\t? { clientSecretExpiresAt: info.client_secret_expires_at }\n\t\t\t\t: {}),\n\t\t\t...(redirectUris !== undefined ? { redirectUris } : {}),\n\t\t\t...(issuer !== undefined ? { issuer } : {}),\n\t\t};\n\t\tthis.flowClientInfo = clientInfo;\n\t\tupdateClientInfo(this.serverName, clientInfo, this.serverUrl, this.storageOptions);\n\t}\n\n\t/**\n\t * Get stored OAuth tokens.\n\t * Returns undefined if no tokens exist or if the server URL has changed.\n\t */\n\tasync tokens(): Promise<OAuthTokens | undefined> {\n\t\t// Use getAuthForUrl to validate tokens are for the current server URL.\n\t\tconst entry = await getAuthForUrl(this.serverName, this.serverUrl, this.storageOptions);\n\t\tif (!entry?.tokens) return undefined;\n\t\tconst issuer = this.discoveredIssuer;\n\t\tthis.assertStoredIssuerBindings(entry, issuer);\n\t\tif (issuer && entry.tokens.issuer === undefined) {\n\t\t\tentry.tokens.issuer = issuer;\n\t\t\tupdateTokens(this.serverName, entry.tokens, this.serverUrl, this.storageOptions);\n\t\t}\n\n\t\treturn {\n\t\t\taccess_token: entry.tokens.accessToken,\n\t\t\ttoken_type: \"Bearer\",\n\t\t\trefresh_token: entry.tokens.refreshToken,\n\t\t\texpires_in:\n\t\t\t\tentry.tokens.expiresAt !== undefined\n\t\t\t\t\t? Math.max(0, Math.floor(entry.tokens.expiresAt - Date.now() / 1000))\n\t\t\t\t\t: undefined,\n\t\t\tscope: entry.tokens.scope,\n\t\t\t...(entry.tokens.issuer !== undefined ? { issuer: entry.tokens.issuer } : {}),\n\t\t} as IssuerBoundTokens;\n\t}\n\n\t/**\n\t * Save OAuth tokens.\n\t */\n\tasync saveTokens(tokens: OAuthTokens): Promise<void> {\n\t\tconst issuer = this.discoveredIssuer ?? (tokens as IssuerBoundTokens).issuer;\n\t\tconst storedTokens: StoredTokens = {\n\t\t\taccessToken: tokens.access_token,\n\t\t\t...(tokens.refresh_token !== undefined ? { refreshToken: tokens.refresh_token } : {}),\n\t\t\t// Preserve expiry even when expires_in is 0 (e.g. the SDK re-saving an\n\t\t\t// already-expired token) so expired tokens stay expired instead of\n\t\t\t// being persisted as never-expiring.\n\t\t\t...(tokens.expires_in !== undefined ? { expiresAt: Date.now() / 1000 + tokens.expires_in } : {}),\n\t\t\t...(tokens.scope !== undefined ? { scope: tokens.scope } : {}),\n\t\t\t...(issuer !== undefined ? { issuer } : {}),\n\t\t};\n\t\tthis.throwIfInactive();\n\t\tupdateTokens(this.serverName, storedTokens, this.serverUrl, this.storageOptions);\n\t\t// Discovery must survive the browser redirect so the callback can verify\n\t\t// the authorization server that minted the code. Once token issuance\n\t\t// succeeds, clear it so a later 401 re-reads PRM and can observe an\n\t\t// authorization-server migration.\n\t\tthis.flowDiscoveryState = undefined;\n\t}\n\n\t/**\n\t * Redirect the user to the authorization URL.\n\t * This opens the browser for the user to authenticate.\n\t *\n\t * Throws UnauthorizedError when called outside of a user-initiated flow\n\t * (no oauthState saved by startAuth). That path is reached when the SDK\n\t * falls through from a failed refresh into a fresh authorization_code\n\t * flow, which library hosts cannot complete in-process.\n\t */\n\tasync redirectToAuthorization(authorizationUrl: URL): Promise<void> {\n\t\tif (this.usesClientCredentials) {\n\t\t\tthrow new Error(\"redirectToAuthorization is not used for client_credentials flow\");\n\t\t}\n\t\t// No flow-local state means we're on the post-refresh authorize fallback.\n\t\tthis.throwIfInactive();\n\t\tif (!this.flowState) {\n\t\t\tthrow new UnauthorizedError(`Re-authentication required for MCP server: ${this.serverName}`);\n\t\t}\n\t\t// URL is passed to callback, not logged (may contain sensitive params)\n\t\tawait this.callbacks.onRedirect(addAuthorizationParams(authorizationUrl, this.config.authorizationParams));\n\t}\n\n\t/**\n\t * Save the PKCE code verifier.\n\t */\n\tasync saveCodeVerifier(codeVerifier: string): Promise<void> {\n\t\tthis.throwIfInactive();\n\t\tthis.flowCodeVerifier = codeVerifier;\n\t}\n\n\t/**\n\t * Get the stored PKCE code verifier.\n\t * @throws Error if no code verifier is stored\n\t */\n\tasync codeVerifier(): Promise<string> {\n\t\tif (this.usesClientCredentials) {\n\t\t\tthrow new Error(\"codeVerifier is not used for client_credentials flow\");\n\t\t}\n\t\tthis.throwIfInactive();\n\t\tif (!this.flowCodeVerifier) {\n\t\t\tthrow new Error(`No code verifier saved for MCP server: ${this.serverName}`);\n\t\t}\n\t\treturn this.flowCodeVerifier;\n\t}\n\n\t/**\n\t * Keep discovery with the in-flight PKCE verifier. The callback leg uses it\n\t * to validate the authorization response issuer before token exchange.\n\t */\n\tasync saveDiscoveryState(state: OAuthDiscoveryState): Promise<void> {\n\t\tthis.throwIfInactive();\n\t\tthis.flowDiscoveryState = structuredClone(state);\n\t}\n\n\tasync discoveryState(): Promise<OAuthDiscoveryState | undefined> {\n\t\tthis.throwIfInactive();\n\t\treturn this.flowDiscoveryState ? structuredClone(this.flowDiscoveryState) : undefined;\n\t}\n\n\t/**\n\t * Save the OAuth state parameter for CSRF protection.\n\t */\n\tasync saveState(state: string): Promise<void> {\n\t\tthis.throwIfInactive();\n\t\tthis.flowState = state;\n\t}\n\n\t/**\n\t * Get the stored OAuth state parameter.\n\t * @throws UnauthorizedError if no flow is in progress (see redirectToAuthorization)\n\t */\n\tasync state(): Promise<string> {\n\t\tif (this.usesClientCredentials) {\n\t\t\tthrow new Error(\"state is not used for client_credentials flow\");\n\t\t}\n\t\tthis.throwIfInactive();\n\t\tif (!this.flowState) {\n\t\t\tthrow new UnauthorizedError(`Re-authentication required for MCP server: ${this.serverName}`);\n\t\t}\n\t\treturn this.flowState;\n\t}\n\n\t/**\n\t * Invalidate credentials when authentication fails.\n\t * Clears tokens, client info, or all credentials based on the type.\n\t */\n\tasync invalidateCredentials(type: \"all\" | \"client\" | \"tokens\" | \"verifier\" | \"discovery\"): Promise<void> {\n\t\tthis.throwIfInactive();\n\t\tswitch (type) {\n\t\t\tcase \"all\":\n\t\t\t\tthis.flowClientInfo = undefined;\n\t\t\t\tthis.flowCodeVerifier = undefined;\n\t\t\t\tthis.flowDiscoveryState = undefined;\n\t\t\t\tthis.flowIssuerMismatch = false;\n\t\t\t\tthis.flowState = undefined;\n\t\t\t\tclearAllCredentials(this.serverName, this.storageOptions);\n\t\t\t\tbreak;\n\t\t\tcase \"client\":\n\t\t\t\tthis.flowClientInfo = undefined;\n\t\t\t\tclearClientInfo(this.serverName, this.storageOptions);\n\t\t\t\tbreak;\n\t\t\tcase \"tokens\":\n\t\t\t\tclearTokens(this.serverName, this.storageOptions);\n\t\t\t\tbreak;\n\t\t\tcase \"verifier\":\n\t\t\t\tclearCodeVerifier(this.serverName, this.storageOptions);\n\t\t\t\tbreak;\n\t\t\tcase \"discovery\":\n\t\t\t\tthis.flowDiscoveryState = undefined;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/**\n\t * Adds configured authorization-code scope without replacing the SDK's\n\t * default token endpoint authentication behavior.\n\t */\n\taddClientAuthentication: AddClientAuthentication = async (headers, params, _url, metadata) => {\n\t\tthis.throwIfInactive();\n\t\tif (params.get(\"grant_type\") === \"authorization_code\" && !params.has(\"scope\") && this.config.scope) {\n\t\t\tparams.set(\"scope\", this.config.scope);\n\t\t}\n\n\t\tconst clientInfo = await this.clientInformation();\n\t\tthis.throwIfInactive();\n\t\tif (!clientInfo) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst supportedMethods = metadata?.token_endpoint_auth_methods_supported ?? [];\n\t\tconst hasClientSecret = clientInfo.client_secret !== undefined;\n\t\tlet authMethod: \"client_secret_basic\" | \"client_secret_post\" | \"none\";\n\n\t\tif (supportedMethods.length === 0) {\n\t\t\tauthMethod = hasClientSecret ? \"client_secret_post\" : \"none\";\n\t\t} else if (hasClientSecret && supportedMethods.includes(\"client_secret_basic\")) {\n\t\t\tauthMethod = \"client_secret_basic\";\n\t\t} else if (hasClientSecret && supportedMethods.includes(\"client_secret_post\")) {\n\t\t\tauthMethod = \"client_secret_post\";\n\t\t} else if (supportedMethods.includes(\"none\")) {\n\t\t\tauthMethod = \"none\";\n\t\t} else {\n\t\t\tauthMethod = hasClientSecret ? \"client_secret_post\" : \"none\";\n\t\t}\n\n\t\tif (authMethod === \"client_secret_basic\") {\n\t\t\tif (!clientInfo.client_secret) {\n\t\t\t\tthrow new Error(\"client_secret_basic authentication requires a client_secret\");\n\t\t\t}\n\t\t\theaders.set(\n\t\t\t\t\"Authorization\",\n\t\t\t\t`Basic ${Buffer.from(`${clientInfo.client_id}:${clientInfo.client_secret}`).toString(\"base64\")}`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!params.has(\"client_id\")) {\n\t\t\tparams.set(\"client_id\", clientInfo.client_id);\n\t\t}\n\t\tif (authMethod === \"client_secret_post\" && clientInfo.client_secret && !params.has(\"client_secret\")) {\n\t\t\tparams.set(\"client_secret\", clientInfo.client_secret);\n\t\t}\n\t};\n\n\tprepareTokenRequest(scope?: string): URLSearchParams | undefined {\n\t\tif (!this.usesClientCredentials) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst params = new URLSearchParams({ grant_type: \"client_credentials\" });\n\t\tconst requestedScope = scope ?? this.config.scope;\n\t\tif (requestedScope) {\n\t\t\tparams.set(\"scope\", requestedScope);\n\t\t}\n\t\treturn params;\n\t}\n}\n\nexport { DEFAULT_OAUTH_CALLBACK_PORT, DEFAULT_OAUTH_CALLBACK_PATH };\n"]}