apex-code 0.0.1-alpha.8 → 0.0.4

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 (634) hide show
  1. package/CHANGELOG.md +231 -0
  2. package/README.md +9 -8
  3. package/dist/cli/args.d.ts +26 -1
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +72 -10
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/cli/file-processor.d.ts.map +1 -1
  8. package/dist/cli/file-processor.js +2 -1
  9. package/dist/cli/file-processor.js.map +1 -1
  10. package/dist/cli/mcp-command.d.ts +9 -0
  11. package/dist/cli/mcp-command.d.ts.map +1 -0
  12. package/dist/cli/mcp-command.js +53 -0
  13. package/dist/cli/mcp-command.js.map +1 -0
  14. package/dist/cli/project-trust.d.ts.map +1 -1
  15. package/dist/cli/project-trust.js +3 -1
  16. package/dist/cli/project-trust.js.map +1 -1
  17. package/dist/cli/startup-ui.d.ts.map +1 -1
  18. package/dist/cli/startup-ui.js +2 -1
  19. package/dist/cli/startup-ui.js.map +1 -1
  20. package/dist/cli.d.ts.map +1 -1
  21. package/dist/cli.js +94 -5
  22. package/dist/cli.js.map +1 -1
  23. package/dist/config.d.ts +3 -2
  24. package/dist/config.d.ts.map +1 -1
  25. package/dist/config.js +45 -18
  26. package/dist/config.js.map +1 -1
  27. package/dist/core/agent-session-services.d.ts +3 -0
  28. package/dist/core/agent-session-services.d.ts.map +1 -1
  29. package/dist/core/agent-session-services.js +1 -0
  30. package/dist/core/agent-session-services.js.map +1 -1
  31. package/dist/core/agent-session.d.ts +183 -15
  32. package/dist/core/agent-session.d.ts.map +1 -1
  33. package/dist/core/agent-session.js +728 -117
  34. package/dist/core/agent-session.js.map +1 -1
  35. package/dist/core/auth-storage.d.ts.map +1 -1
  36. package/dist/core/auth-storage.js +6 -7
  37. package/dist/core/auth-storage.js.map +1 -1
  38. package/dist/core/bash-executor.d.ts.map +1 -1
  39. package/dist/core/bash-executor.js +7 -0
  40. package/dist/core/bash-executor.js.map +1 -1
  41. package/dist/core/checkpoints/git-checkpoints.d.ts +39 -0
  42. package/dist/core/checkpoints/git-checkpoints.d.ts.map +1 -0
  43. package/dist/core/checkpoints/git-checkpoints.js +251 -0
  44. package/dist/core/checkpoints/git-checkpoints.js.map +1 -0
  45. package/dist/core/checkpoints/session-checkpoints.d.ts +23 -0
  46. package/dist/core/checkpoints/session-checkpoints.d.ts.map +1 -0
  47. package/dist/core/checkpoints/session-checkpoints.js +36 -0
  48. package/dist/core/checkpoints/session-checkpoints.js.map +1 -0
  49. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  50. package/dist/core/compaction/branch-summarization.js +7 -3
  51. package/dist/core/compaction/branch-summarization.js.map +1 -1
  52. package/dist/core/compaction/compaction.d.ts +9 -3
  53. package/dist/core/compaction/compaction.d.ts.map +1 -1
  54. package/dist/core/compaction/compaction.js +59 -36
  55. package/dist/core/compaction/compaction.js.map +1 -1
  56. package/dist/core/defaults.d.ts +1 -0
  57. package/dist/core/defaults.d.ts.map +1 -1
  58. package/dist/core/defaults.js +9 -0
  59. package/dist/core/defaults.js.map +1 -1
  60. package/dist/core/delegation/runtime.d.ts +6 -5
  61. package/dist/core/delegation/runtime.d.ts.map +1 -1
  62. package/dist/core/delegation/runtime.js +4 -3
  63. package/dist/core/delegation/runtime.js.map +1 -1
  64. package/dist/core/durable-state/sqlite.d.ts.map +1 -1
  65. package/dist/core/durable-state/sqlite.js +26 -2
  66. package/dist/core/durable-state/sqlite.js.map +1 -1
  67. package/dist/core/exec.d.ts.map +1 -1
  68. package/dist/core/exec.js +5 -2
  69. package/dist/core/exec.js.map +1 -1
  70. package/dist/core/extensions/index.d.ts +2 -2
  71. package/dist/core/extensions/index.d.ts.map +1 -1
  72. package/dist/core/extensions/index.js +1 -1
  73. package/dist/core/extensions/index.js.map +1 -1
  74. package/dist/core/extensions/loader.d.ts.map +1 -1
  75. package/dist/core/extensions/loader.js +123 -50
  76. package/dist/core/extensions/loader.js.map +1 -1
  77. package/dist/core/extensions/runner.d.ts +5 -0
  78. package/dist/core/extensions/runner.d.ts.map +1 -1
  79. package/dist/core/extensions/runner.js +45 -1
  80. package/dist/core/extensions/runner.js.map +1 -1
  81. package/dist/core/extensions/source-runtime.d.ts +14 -0
  82. package/dist/core/extensions/source-runtime.d.ts.map +1 -0
  83. package/dist/core/extensions/source-runtime.js +56 -0
  84. package/dist/core/extensions/source-runtime.js.map +1 -0
  85. package/dist/core/extensions/types.d.ts +60 -11
  86. package/dist/core/extensions/types.d.ts.map +1 -1
  87. package/dist/core/extensions/types.js +3 -0
  88. package/dist/core/extensions/types.js.map +1 -1
  89. package/dist/core/footer-data-provider.d.ts +1 -1
  90. package/dist/core/footer-data-provider.d.ts.map +1 -1
  91. package/dist/core/footer-data-provider.js +1 -1
  92. package/dist/core/footer-data-provider.js.map +1 -1
  93. package/dist/core/formatter-lifecycle.d.ts +69 -0
  94. package/dist/core/formatter-lifecycle.d.ts.map +1 -0
  95. package/dist/core/formatter-lifecycle.js +360 -0
  96. package/dist/core/formatter-lifecycle.js.map +1 -0
  97. package/dist/core/hooks/command-handler.d.ts +19 -0
  98. package/dist/core/hooks/command-handler.d.ts.map +1 -0
  99. package/dist/core/hooks/command-handler.js +112 -0
  100. package/dist/core/hooks/command-handler.js.map +1 -0
  101. package/dist/core/hooks/http-handler.d.ts +10 -0
  102. package/dist/core/hooks/http-handler.d.ts.map +1 -0
  103. package/dist/core/hooks/http-handler.js +36 -0
  104. package/dist/core/hooks/http-handler.js.map +1 -0
  105. package/dist/core/hooks/loader.d.ts +29 -0
  106. package/dist/core/hooks/loader.d.ts.map +1 -0
  107. package/dist/core/hooks/loader.js +139 -0
  108. package/dist/core/hooks/loader.js.map +1 -0
  109. package/dist/core/hooks/runtime.d.ts +13 -0
  110. package/dist/core/hooks/runtime.d.ts.map +1 -0
  111. package/dist/core/hooks/runtime.js +63 -0
  112. package/dist/core/hooks/runtime.js.map +1 -0
  113. package/dist/core/hooks/types.d.ts +83 -0
  114. package/dist/core/hooks/types.d.ts.map +1 -0
  115. package/dist/core/hooks/types.js +24 -0
  116. package/dist/core/hooks/types.js.map +1 -0
  117. package/dist/core/keybindings.d.ts +20 -19
  118. package/dist/core/keybindings.d.ts.map +1 -1
  119. package/dist/core/keybindings.js +26 -5
  120. package/dist/core/keybindings.js.map +1 -1
  121. package/dist/core/mcp/config.d.ts +16 -0
  122. package/dist/core/mcp/config.d.ts.map +1 -0
  123. package/dist/core/mcp/config.js +166 -0
  124. package/dist/core/mcp/config.js.map +1 -0
  125. package/dist/core/mcp/connector.d.ts +35 -0
  126. package/dist/core/mcp/connector.d.ts.map +1 -0
  127. package/dist/core/mcp/connector.js +105 -0
  128. package/dist/core/mcp/connector.js.map +1 -0
  129. package/dist/core/mcp/contract.d.ts +19 -0
  130. package/dist/core/mcp/contract.d.ts.map +1 -0
  131. package/dist/core/mcp/contract.js +89 -0
  132. package/dist/core/mcp/contract.js.map +1 -0
  133. package/dist/core/mcp/mcp-tool.d.ts +32 -0
  134. package/dist/core/mcp/mcp-tool.d.ts.map +1 -0
  135. package/dist/core/mcp/mcp-tool.js +171 -0
  136. package/dist/core/mcp/mcp-tool.js.map +1 -0
  137. package/dist/core/mcp/metadata-cache.d.ts +29 -0
  138. package/dist/core/mcp/metadata-cache.d.ts.map +1 -0
  139. package/dist/core/mcp/metadata-cache.js +99 -0
  140. package/dist/core/mcp/metadata-cache.js.map +1 -0
  141. package/dist/core/mcp/oauth/authorize.d.ts +21 -0
  142. package/dist/core/mcp/oauth/authorize.d.ts.map +1 -0
  143. package/dist/core/mcp/oauth/authorize.js +32 -0
  144. package/dist/core/mcp/oauth/authorize.js.map +1 -0
  145. package/dist/core/mcp/oauth/discover.d.ts +27 -0
  146. package/dist/core/mcp/oauth/discover.d.ts.map +1 -0
  147. package/dist/core/mcp/oauth/discover.js +116 -0
  148. package/dist/core/mcp/oauth/discover.js.map +1 -0
  149. package/dist/core/mcp/oauth/flow.d.ts +31 -0
  150. package/dist/core/mcp/oauth/flow.d.ts.map +1 -0
  151. package/dist/core/mcp/oauth/flow.js +175 -0
  152. package/dist/core/mcp/oauth/flow.js.map +1 -0
  153. package/dist/core/mcp/oauth/mcp-token.d.ts +51 -0
  154. package/dist/core/mcp/oauth/mcp-token.d.ts.map +1 -0
  155. package/dist/core/mcp/oauth/mcp-token.js +129 -0
  156. package/dist/core/mcp/oauth/mcp-token.js.map +1 -0
  157. package/dist/core/mcp/oauth/pkce.d.ts +12 -0
  158. package/dist/core/mcp/oauth/pkce.d.ts.map +1 -0
  159. package/dist/core/mcp/oauth/pkce.js +11 -0
  160. package/dist/core/mcp/oauth/pkce.js.map +1 -0
  161. package/dist/core/mcp/oauth/register.d.ts +16 -0
  162. package/dist/core/mcp/oauth/register.d.ts.map +1 -0
  163. package/dist/core/mcp/oauth/register.js +42 -0
  164. package/dist/core/mcp/oauth/register.js.map +1 -0
  165. package/dist/core/mcp/oauth/token-client.d.ts +33 -0
  166. package/dist/core/mcp/oauth/token-client.d.ts.map +1 -0
  167. package/dist/core/mcp/oauth/token-client.js +65 -0
  168. package/dist/core/mcp/oauth/token-client.js.map +1 -0
  169. package/dist/core/mcp/runtime.d.ts +20 -0
  170. package/dist/core/mcp/runtime.d.ts.map +1 -0
  171. package/dist/core/mcp/runtime.js +37 -0
  172. package/dist/core/mcp/runtime.js.map +1 -0
  173. package/dist/core/mcp/schema.d.ts +22 -0
  174. package/dist/core/mcp/schema.d.ts.map +1 -0
  175. package/dist/core/mcp/schema.js +20 -0
  176. package/dist/core/mcp/schema.js.map +1 -0
  177. package/dist/core/mcp/server-manager.d.ts +43 -0
  178. package/dist/core/mcp/server-manager.d.ts.map +1 -0
  179. package/dist/core/mcp/server-manager.js +142 -0
  180. package/dist/core/mcp/server-manager.js.map +1 -0
  181. package/dist/core/mcp/types.d.ts +100 -0
  182. package/dist/core/mcp/types.d.ts.map +1 -0
  183. package/dist/core/mcp/types.js +8 -0
  184. package/dist/core/mcp/types.js.map +1 -0
  185. package/dist/core/model-config.d.ts +5 -0
  186. package/dist/core/model-config.d.ts.map +1 -1
  187. package/dist/core/model-config.js +3 -1
  188. package/dist/core/model-config.js.map +1 -1
  189. package/dist/core/model-resolver.d.ts +1 -0
  190. package/dist/core/model-resolver.d.ts.map +1 -1
  191. package/dist/core/model-resolver.js +14 -8
  192. package/dist/core/model-resolver.js.map +1 -1
  193. package/dist/core/models-store.d.ts.map +1 -1
  194. package/dist/core/models-store.js +2 -1
  195. package/dist/core/models-store.js.map +1 -1
  196. package/dist/core/package-manager.d.ts.map +1 -1
  197. package/dist/core/package-manager.js +22 -14
  198. package/dist/core/package-manager.js.map +1 -1
  199. package/dist/core/permissions/gate.d.ts.map +1 -1
  200. package/dist/core/permissions/gate.js +45 -4
  201. package/dist/core/permissions/gate.js.map +1 -1
  202. package/dist/core/permissions/operations.d.ts +20 -0
  203. package/dist/core/permissions/operations.d.ts.map +1 -0
  204. package/dist/core/permissions/operations.js +9 -0
  205. package/dist/core/permissions/operations.js.map +1 -0
  206. package/dist/core/permissions/policy-command.d.ts +42 -0
  207. package/dist/core/permissions/policy-command.d.ts.map +1 -0
  208. package/dist/core/permissions/policy-command.js +44 -0
  209. package/dist/core/permissions/policy-command.js.map +1 -0
  210. package/dist/core/permissions/responder.d.ts +49 -2
  211. package/dist/core/permissions/responder.d.ts.map +1 -1
  212. package/dist/core/permissions/responder.js +20 -8
  213. package/dist/core/permissions/responder.js.map +1 -1
  214. package/dist/core/permissions/rules.d.ts.map +1 -1
  215. package/dist/core/permissions/rules.js +11 -1
  216. package/dist/core/permissions/rules.js.map +1 -1
  217. package/dist/core/permissions/store.d.ts +18 -0
  218. package/dist/core/permissions/store.d.ts.map +1 -1
  219. package/dist/core/permissions/store.js +89 -8
  220. package/dist/core/permissions/store.js.map +1 -1
  221. package/dist/core/pi-manifest.d.ts.map +1 -1
  222. package/dist/core/pi-manifest.js +2 -1
  223. package/dist/core/pi-manifest.js.map +1 -1
  224. package/dist/core/policy-executor.d.ts +47 -0
  225. package/dist/core/policy-executor.d.ts.map +1 -0
  226. package/dist/core/policy-executor.js +228 -0
  227. package/dist/core/policy-executor.js.map +1 -0
  228. package/dist/core/policy-loader.d.ts +72 -0
  229. package/dist/core/policy-loader.d.ts.map +1 -0
  230. package/dist/core/policy-loader.js +195 -0
  231. package/dist/core/policy-loader.js.map +1 -0
  232. package/dist/core/project-trust.d.ts +1 -1
  233. package/dist/core/project-trust.d.ts.map +1 -1
  234. package/dist/core/project-trust.js.map +1 -1
  235. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  236. package/dist/core/remote-catalog-provider.js +2 -1
  237. package/dist/core/remote-catalog-provider.js.map +1 -1
  238. package/dist/core/resource-loader.d.ts.map +1 -1
  239. package/dist/core/resource-loader.js +3 -2
  240. package/dist/core/resource-loader.js.map +1 -1
  241. package/dist/core/sandbox/bwrap-arguments.d.ts +41 -0
  242. package/dist/core/sandbox/bwrap-arguments.d.ts.map +1 -0
  243. package/dist/core/sandbox/bwrap-arguments.js +136 -0
  244. package/dist/core/sandbox/bwrap-arguments.js.map +1 -0
  245. package/dist/core/sandbox/child-entry.d.ts.map +1 -1
  246. package/dist/core/sandbox/child-entry.js +3 -1
  247. package/dist/core/sandbox/child-entry.js.map +1 -1
  248. package/dist/core/sandbox/cli-launch.d.ts +84 -4
  249. package/dist/core/sandbox/cli-launch.d.ts.map +1 -1
  250. package/dist/core/sandbox/cli-launch.js +115 -16
  251. package/dist/core/sandbox/cli-launch.js.map +1 -1
  252. package/dist/core/sandbox/cli-supervisor.d.ts +2 -0
  253. package/dist/core/sandbox/cli-supervisor.d.ts.map +1 -1
  254. package/dist/core/sandbox/cli-supervisor.js +50 -2
  255. package/dist/core/sandbox/cli-supervisor.js.map +1 -1
  256. package/dist/core/sandbox/full-access.d.ts +28 -0
  257. package/dist/core/sandbox/full-access.d.ts.map +1 -0
  258. package/dist/core/sandbox/full-access.js +63 -0
  259. package/dist/core/sandbox/full-access.js.map +1 -0
  260. package/dist/core/sandbox/git-identity.d.ts +57 -0
  261. package/dist/core/sandbox/git-identity.d.ts.map +1 -0
  262. package/dist/core/sandbox/git-identity.js +78 -0
  263. package/dist/core/sandbox/git-identity.js.map +1 -0
  264. package/dist/core/sandbox/host-approval.d.ts +42 -0
  265. package/dist/core/sandbox/host-approval.d.ts.map +1 -0
  266. package/dist/core/sandbox/host-approval.js +99 -0
  267. package/dist/core/sandbox/host-approval.js.map +1 -0
  268. package/dist/core/sandbox/linux-backend.d.ts +14 -0
  269. package/dist/core/sandbox/linux-backend.d.ts.map +1 -1
  270. package/dist/core/sandbox/linux-backend.js +158 -80
  271. package/dist/core/sandbox/linux-backend.js.map +1 -1
  272. package/dist/core/sandbox/macos-backend.d.ts +5 -0
  273. package/dist/core/sandbox/macos-backend.d.ts.map +1 -1
  274. package/dist/core/sandbox/macos-backend.js +164 -5
  275. package/dist/core/sandbox/macos-backend.js.map +1 -1
  276. package/dist/core/sandbox/network-proxy.d.ts +19 -0
  277. package/dist/core/sandbox/network-proxy.d.ts.map +1 -1
  278. package/dist/core/sandbox/network-proxy.js +93 -19
  279. package/dist/core/sandbox/network-proxy.js.map +1 -1
  280. package/dist/core/sandbox/policy.d.ts +8 -0
  281. package/dist/core/sandbox/policy.d.ts.map +1 -1
  282. package/dist/core/sandbox/policy.js +29 -12
  283. package/dist/core/sandbox/policy.js.map +1 -1
  284. package/dist/core/sandbox/profiles.d.ts +25 -0
  285. package/dist/core/sandbox/profiles.d.ts.map +1 -0
  286. package/dist/core/sandbox/profiles.js +23 -0
  287. package/dist/core/sandbox/profiles.js.map +1 -0
  288. package/dist/core/sandbox/rpc/command-client.d.ts +28 -0
  289. package/dist/core/sandbox/rpc/command-client.d.ts.map +1 -0
  290. package/dist/core/sandbox/rpc/command-client.js +86 -0
  291. package/dist/core/sandbox/rpc/command-client.js.map +1 -0
  292. package/dist/core/sandbox/rpc/command-proxy.d.ts +48 -0
  293. package/dist/core/sandbox/rpc/command-proxy.d.ts.map +1 -0
  294. package/dist/core/sandbox/rpc/command-proxy.js +120 -0
  295. package/dist/core/sandbox/rpc/command-proxy.js.map +1 -0
  296. package/dist/core/sandbox/rpc/credential-proxy.d.ts.map +1 -1
  297. package/dist/core/sandbox/rpc/credential-proxy.js +2 -96
  298. package/dist/core/sandbox/rpc/credential-proxy.js.map +1 -1
  299. package/dist/core/sandbox/rpc/framing.d.ts +35 -0
  300. package/dist/core/sandbox/rpc/framing.d.ts.map +1 -0
  301. package/dist/core/sandbox/rpc/framing.js +114 -0
  302. package/dist/core/sandbox/rpc/framing.js.map +1 -0
  303. package/dist/core/sandbox/rpc/git-credential-helper.d.ts +47 -0
  304. package/dist/core/sandbox/rpc/git-credential-helper.d.ts.map +1 -0
  305. package/dist/core/sandbox/rpc/git-credential-helper.js +222 -0
  306. package/dist/core/sandbox/rpc/git-credential-helper.js.map +1 -0
  307. package/dist/core/sandbox/rpc/git-credential-proxy.d.ts +66 -0
  308. package/dist/core/sandbox/rpc/git-credential-proxy.d.ts.map +1 -0
  309. package/dist/core/sandbox/rpc/git-credential-proxy.js +209 -0
  310. package/dist/core/sandbox/rpc/git-credential-proxy.js.map +1 -0
  311. package/dist/core/sandbox/supervisor-temp.d.ts +18 -0
  312. package/dist/core/sandbox/supervisor-temp.d.ts.map +1 -0
  313. package/dist/core/sandbox/supervisor-temp.js +21 -0
  314. package/dist/core/sandbox/supervisor-temp.js.map +1 -0
  315. package/dist/core/sandbox/supervisor.d.ts +12 -1
  316. package/dist/core/sandbox/supervisor.d.ts.map +1 -1
  317. package/dist/core/sandbox/supervisor.js +15 -1
  318. package/dist/core/sandbox/supervisor.js.map +1 -1
  319. package/dist/core/sandbox/terminal-handoff.d.ts +68 -0
  320. package/dist/core/sandbox/terminal-handoff.d.ts.map +1 -0
  321. package/dist/core/sandbox/terminal-handoff.js +221 -0
  322. package/dist/core/sandbox/terminal-handoff.js.map +1 -0
  323. package/dist/core/sandbox/terminal-size.d.ts +13 -0
  324. package/dist/core/sandbox/terminal-size.d.ts.map +1 -1
  325. package/dist/core/sandbox/terminal-size.js +23 -2
  326. package/dist/core/sandbox/terminal-size.js.map +1 -1
  327. package/dist/core/sdk.d.ts +24 -2
  328. package/dist/core/sdk.d.ts.map +1 -1
  329. package/dist/core/sdk.js +63 -4
  330. package/dist/core/sdk.js.map +1 -1
  331. package/dist/core/session-export.d.ts +4 -0
  332. package/dist/core/session-export.d.ts.map +1 -0
  333. package/dist/core/session-export.js +32 -0
  334. package/dist/core/session-export.js.map +1 -0
  335. package/dist/core/session-manager.d.ts +13 -1
  336. package/dist/core/session-manager.d.ts.map +1 -1
  337. package/dist/core/session-manager.js +34 -6
  338. package/dist/core/session-manager.js.map +1 -1
  339. package/dist/core/settings-diagnostics.d.ts +9 -0
  340. package/dist/core/settings-diagnostics.d.ts.map +1 -0
  341. package/dist/core/settings-diagnostics.js +21 -0
  342. package/dist/core/settings-diagnostics.js.map +1 -0
  343. package/dist/core/settings-manager.d.ts +172 -1
  344. package/dist/core/settings-manager.d.ts.map +1 -1
  345. package/dist/core/settings-manager.js +160 -11
  346. package/dist/core/settings-manager.js.map +1 -1
  347. package/dist/core/skills.d.ts.map +1 -1
  348. package/dist/core/skills.js +51 -33
  349. package/dist/core/skills.js.map +1 -1
  350. package/dist/core/slash-commands.d.ts.map +1 -1
  351. package/dist/core/slash-commands.js +4 -1
  352. package/dist/core/slash-commands.js.map +1 -1
  353. package/dist/core/system-prompt.d.ts.map +1 -1
  354. package/dist/core/system-prompt.js +8 -2
  355. package/dist/core/system-prompt.js.map +1 -1
  356. package/dist/core/tools/background-shell.d.ts +39 -0
  357. package/dist/core/tools/background-shell.d.ts.map +1 -0
  358. package/dist/core/tools/background-shell.js +81 -0
  359. package/dist/core/tools/background-shell.js.map +1 -0
  360. package/dist/core/tools/bash-command-segments.d.ts.map +1 -1
  361. package/dist/core/tools/bash-command-segments.js +2 -0
  362. package/dist/core/tools/bash-command-segments.js.map +1 -1
  363. package/dist/core/tools/bash.d.ts +44 -16
  364. package/dist/core/tools/bash.d.ts.map +1 -1
  365. package/dist/core/tools/bash.js +264 -32
  366. package/dist/core/tools/bash.js.map +1 -1
  367. package/dist/core/tools/contract-snapshot.d.ts +58 -0
  368. package/dist/core/tools/contract-snapshot.d.ts.map +1 -0
  369. package/dist/core/tools/contract-snapshot.js +51 -0
  370. package/dist/core/tools/contract-snapshot.js.map +1 -0
  371. package/dist/core/tools/contract.d.ts +53 -5
  372. package/dist/core/tools/contract.d.ts.map +1 -1
  373. package/dist/core/tools/contract.js +22 -2
  374. package/dist/core/tools/contract.js.map +1 -1
  375. package/dist/core/tools/delegate.d.ts +6 -4
  376. package/dist/core/tools/delegate.d.ts.map +1 -1
  377. package/dist/core/tools/delegate.js +21 -11
  378. package/dist/core/tools/delegate.js.map +1 -1
  379. package/dist/core/tools/edit-diff.d.ts +48 -5
  380. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  381. package/dist/core/tools/edit-diff.js +217 -8
  382. package/dist/core/tools/edit-diff.js.map +1 -1
  383. package/dist/core/tools/edit.d.ts +8 -0
  384. package/dist/core/tools/edit.d.ts.map +1 -1
  385. package/dist/core/tools/edit.js +72 -10
  386. package/dist/core/tools/edit.js.map +1 -1
  387. package/dist/core/tools/find.d.ts.map +1 -1
  388. package/dist/core/tools/find.js +5 -2
  389. package/dist/core/tools/find.js.map +1 -1
  390. package/dist/core/tools/grep.d.ts.map +1 -1
  391. package/dist/core/tools/grep.js +5 -2
  392. package/dist/core/tools/grep.js.map +1 -1
  393. package/dist/core/tools/index.d.ts +14 -2
  394. package/dist/core/tools/index.d.ts.map +1 -1
  395. package/dist/core/tools/index.js +12 -0
  396. package/dist/core/tools/index.js.map +1 -1
  397. package/dist/core/tools/ls.d.ts.map +1 -1
  398. package/dist/core/tools/ls.js +5 -2
  399. package/dist/core/tools/ls.js.map +1 -1
  400. package/dist/core/tools/lsp.d.ts +19 -1
  401. package/dist/core/tools/lsp.d.ts.map +1 -1
  402. package/dist/core/tools/lsp.js +163 -10
  403. package/dist/core/tools/lsp.js.map +1 -1
  404. package/dist/core/tools/path-permission.d.ts +3 -0
  405. package/dist/core/tools/path-permission.d.ts.map +1 -1
  406. package/dist/core/tools/path-permission.js +16 -4
  407. package/dist/core/tools/path-permission.js.map +1 -1
  408. package/dist/core/tools/path-utils.d.ts +27 -2
  409. package/dist/core/tools/path-utils.d.ts.map +1 -1
  410. package/dist/core/tools/path-utils.js +221 -4
  411. package/dist/core/tools/path-utils.js.map +1 -1
  412. package/dist/core/tools/powershell.d.ts +16 -0
  413. package/dist/core/tools/powershell.d.ts.map +1 -0
  414. package/dist/core/tools/powershell.js +39 -0
  415. package/dist/core/tools/powershell.js.map +1 -0
  416. package/dist/core/tools/read.d.ts.map +1 -1
  417. package/dist/core/tools/read.js +20 -11
  418. package/dist/core/tools/read.js.map +1 -1
  419. package/dist/core/tools/test.d.ts +54 -9
  420. package/dist/core/tools/test.d.ts.map +1 -1
  421. package/dist/core/tools/test.js +239 -19
  422. package/dist/core/tools/test.js.map +1 -1
  423. package/dist/core/tools/write.d.ts +7 -0
  424. package/dist/core/tools/write.d.ts.map +1 -1
  425. package/dist/core/tools/write.js +64 -9
  426. package/dist/core/tools/write.js.map +1 -1
  427. package/dist/core/trust-manager.d.ts.map +1 -1
  428. package/dist/core/trust-manager.js +2 -1
  429. package/dist/core/trust-manager.js.map +1 -1
  430. package/dist/core/verification-lifecycle.d.ts +77 -0
  431. package/dist/core/verification-lifecycle.d.ts.map +1 -0
  432. package/dist/core/verification-lifecycle.js +146 -0
  433. package/dist/core/verification-lifecycle.js.map +1 -0
  434. package/dist/core/workspace/artifacts.d.ts +45 -0
  435. package/dist/core/workspace/artifacts.d.ts.map +1 -0
  436. package/dist/core/workspace/artifacts.js +165 -0
  437. package/dist/core/workspace/artifacts.js.map +1 -0
  438. package/dist/core/workspace/comparison.d.ts +27 -0
  439. package/dist/core/workspace/comparison.d.ts.map +1 -0
  440. package/dist/core/workspace/comparison.js +94 -0
  441. package/dist/core/workspace/comparison.js.map +1 -0
  442. package/dist/core/workspace/git-observer.d.ts +48 -0
  443. package/dist/core/workspace/git-observer.d.ts.map +1 -0
  444. package/dist/core/workspace/git-observer.js +346 -0
  445. package/dist/core/workspace/git-observer.js.map +1 -0
  446. package/dist/core/workspace/projection.d.ts +3 -0
  447. package/dist/core/workspace/projection.d.ts.map +1 -0
  448. package/dist/core/workspace/projection.js +56 -0
  449. package/dist/core/workspace/projection.js.map +1 -0
  450. package/dist/core/workspace/state.d.ts +133 -0
  451. package/dist/core/workspace/state.d.ts.map +1 -0
  452. package/dist/core/workspace/state.js +96 -0
  453. package/dist/core/workspace/state.js.map +1 -0
  454. package/dist/extensions/llama/client.d.ts +6 -0
  455. package/dist/extensions/llama/client.d.ts.map +1 -1
  456. package/dist/extensions/llama/client.js +7 -0
  457. package/dist/extensions/llama/client.js.map +1 -1
  458. package/dist/extensions/llama/index.d.ts.map +1 -1
  459. package/dist/extensions/llama/index.js +2 -0
  460. package/dist/extensions/llama/index.js.map +1 -1
  461. package/dist/extensions/llama/provider.d.ts +3 -1
  462. package/dist/extensions/llama/provider.d.ts.map +1 -1
  463. package/dist/extensions/llama/provider.js +29 -4
  464. package/dist/extensions/llama/provider.js.map +1 -1
  465. package/dist/index.d.ts +8 -5
  466. package/dist/index.d.ts.map +1 -1
  467. package/dist/index.js +7 -4
  468. package/dist/index.js.map +1 -1
  469. package/dist/main.d.ts +6 -0
  470. package/dist/main.d.ts.map +1 -1
  471. package/dist/main.js +58 -23
  472. package/dist/main.js.map +1 -1
  473. package/dist/migrations.d.ts.map +1 -1
  474. package/dist/migrations.js +4 -3
  475. package/dist/migrations.js.map +1 -1
  476. package/dist/modes/acp/server.d.ts +55 -0
  477. package/dist/modes/acp/server.d.ts.map +1 -0
  478. package/dist/modes/acp/server.js +244 -0
  479. package/dist/modes/acp/server.js.map +1 -0
  480. package/dist/modes/acp/translate.d.ts +37 -0
  481. package/dist/modes/acp/translate.d.ts.map +1 -0
  482. package/dist/modes/acp/translate.js +50 -0
  483. package/dist/modes/acp/translate.js.map +1 -0
  484. package/dist/modes/index.d.ts +1 -0
  485. package/dist/modes/index.d.ts.map +1 -1
  486. package/dist/modes/index.js +1 -0
  487. package/dist/modes/index.js.map +1 -1
  488. package/dist/modes/interactive/components/assistant-message.d.ts +29 -0
  489. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  490. package/dist/modes/interactive/components/assistant-message.js +182 -23
  491. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  492. package/dist/modes/interactive/components/bash-execution.d.ts +7 -0
  493. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  494. package/dist/modes/interactive/components/bash-execution.js +20 -0
  495. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  496. package/dist/modes/interactive/components/custom-editor.d.ts +9 -4
  497. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  498. package/dist/modes/interactive/components/custom-editor.js +20 -9
  499. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  500. package/dist/modes/interactive/components/extension-selector.d.ts +7 -1
  501. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  502. package/dist/modes/interactive/components/extension-selector.js +7 -3
  503. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  504. package/dist/modes/interactive/components/footer.d.ts +19 -0
  505. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  506. package/dist/modes/interactive/components/footer.js +70 -10
  507. package/dist/modes/interactive/components/footer.js.map +1 -1
  508. package/dist/modes/interactive/components/model-selector.d.ts +10 -3
  509. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  510. package/dist/modes/interactive/components/model-selector.js +56 -14
  511. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  512. package/dist/modes/interactive/components/permission-preview.d.ts +15 -0
  513. package/dist/modes/interactive/components/permission-preview.d.ts.map +1 -0
  514. package/dist/modes/interactive/components/permission-preview.js +33 -0
  515. package/dist/modes/interactive/components/permission-preview.js.map +1 -0
  516. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  517. package/dist/modes/interactive/components/session-selector.js +2 -2
  518. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  519. package/dist/modes/interactive/components/settings-selector.d.ts +9 -2
  520. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  521. package/dist/modes/interactive/components/settings-selector.js +128 -56
  522. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  523. package/dist/modes/interactive/components/settings-submenu.d.ts +72 -0
  524. package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -0
  525. package/dist/modes/interactive/components/settings-submenu.js +165 -0
  526. package/dist/modes/interactive/components/settings-submenu.js.map +1 -0
  527. package/dist/modes/interactive/components/thinking-selector.d.ts +15 -3
  528. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  529. package/dist/modes/interactive/components/thinking-selector.js +74 -17
  530. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  531. package/dist/modes/interactive/components/tool-execution.d.ts +23 -1
  532. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  533. package/dist/modes/interactive/components/tool-execution.js +64 -10
  534. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  535. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  536. package/dist/modes/interactive/external-editor.js +2 -1
  537. package/dist/modes/interactive/external-editor.js.map +1 -1
  538. package/dist/modes/interactive/interactive-mode.d.ts +45 -0
  539. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  540. package/dist/modes/interactive/interactive-mode.js +395 -43
  541. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  542. package/dist/modes/interactive/theme/theme.d.ts +12 -0
  543. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  544. package/dist/modes/interactive/theme/theme.js +20 -9
  545. package/dist/modes/interactive/theme/theme.js.map +1 -1
  546. package/dist/modes/json-event.d.ts +16 -13
  547. package/dist/modes/json-event.d.ts.map +1 -1
  548. package/dist/modes/json-event.js +20 -6
  549. package/dist/modes/json-event.js.map +1 -1
  550. package/dist/modes/print-mode.d.ts.map +1 -1
  551. package/dist/modes/print-mode.js +27 -12
  552. package/dist/modes/print-mode.js.map +1 -1
  553. package/dist/modes/rpc/rpc-client.d.ts +7 -0
  554. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  555. package/dist/modes/rpc/rpc-client.js +7 -0
  556. package/dist/modes/rpc/rpc-client.js.map +1 -1
  557. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  558. package/dist/modes/rpc/rpc-mode.js +3 -0
  559. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  560. package/dist/modes/rpc/rpc-types.d.ts +12 -0
  561. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  562. package/dist/modes/rpc/rpc-types.js.map +1 -1
  563. package/dist/package-manager-cli.d.ts +1 -0
  564. package/dist/package-manager-cli.d.ts.map +1 -1
  565. package/dist/package-manager-cli.js +196 -10
  566. package/dist/package-manager-cli.js.map +1 -1
  567. package/dist/utils/frontmatter.d.ts.map +1 -1
  568. package/dist/utils/frontmatter.js +2 -1
  569. package/dist/utils/frontmatter.js.map +1 -1
  570. package/dist/utils/management-http.d.ts +5 -3
  571. package/dist/utils/management-http.d.ts.map +1 -1
  572. package/dist/utils/management-http.js +14 -10
  573. package/dist/utils/management-http.js.map +1 -1
  574. package/dist/utils/shell.d.ts +3 -0
  575. package/dist/utils/shell.d.ts.map +1 -1
  576. package/dist/utils/shell.js +23 -9
  577. package/dist/utils/shell.js.map +1 -1
  578. package/dist/utils/syntax-highlight.d.ts +1 -0
  579. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  580. package/dist/utils/syntax-highlight.js +60 -1
  581. package/dist/utils/syntax-highlight.js.map +1 -1
  582. package/dist/utils/text.d.ts +8 -0
  583. package/dist/utils/text.d.ts.map +1 -0
  584. package/dist/utils/text.js +9 -0
  585. package/dist/utils/text.js.map +1 -0
  586. package/dist/utils/version-check.d.ts.map +1 -1
  587. package/dist/utils/version-check.js +6 -4
  588. package/dist/utils/version-check.js.map +1 -1
  589. package/docs/compaction.md +19 -0
  590. package/docs/custom-provider.md +12 -9
  591. package/docs/environment-variables.md +1 -1
  592. package/docs/extensions.md +35 -7
  593. package/docs/json.md +7 -2
  594. package/docs/keybindings.md +9 -9
  595. package/docs/llama-cpp.md +2 -0
  596. package/docs/models.md +8 -2
  597. package/docs/packages.md +2 -2
  598. package/docs/quickstart.md +1 -1
  599. package/docs/rpc.md +32 -3
  600. package/docs/sdk.md +32 -2
  601. package/docs/settings.md +23 -7
  602. package/docs/skills.md +4 -3
  603. package/docs/terminal-setup.md +23 -7
  604. package/docs/usage.md +10 -5
  605. package/docs/windows.md +24 -2
  606. package/examples/extensions/border-status-editor.ts +1 -1
  607. package/examples/extensions/built-in-tool-renderer.ts +8 -4
  608. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  609. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  610. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  611. package/examples/extensions/git-checkpoint.ts +24 -36
  612. package/examples/extensions/gondolin/package-lock.json +2 -2
  613. package/examples/extensions/gondolin/package.json +1 -1
  614. package/examples/extensions/minimal-mode.ts +2 -2
  615. package/examples/extensions/notify.ts +3 -1
  616. package/examples/extensions/permission-gate.ts +1 -1
  617. package/examples/extensions/plan-mode/index.ts +1 -1
  618. package/examples/extensions/rpc-demo.ts +1 -1
  619. package/examples/extensions/sandbox/package-lock.json +2 -2
  620. package/examples/extensions/sandbox/package.json +1 -1
  621. package/examples/extensions/subagent/README.md +1 -1
  622. package/examples/extensions/subagent/index.ts +6 -1
  623. package/examples/extensions/titlebar-spinner.ts +1 -1
  624. package/examples/extensions/with-deps/package-lock.json +2 -2
  625. package/examples/extensions/with-deps/package.json +1 -1
  626. package/examples/rpc-extension-ui.ts +1 -1
  627. package/examples/sdk/06-extensions.ts +1 -1
  628. package/examples/sdk/README.md +1 -1
  629. package/npm-shrinkwrap.json +439 -405
  630. package/package.json +17 -17
  631. package/dist/server/create-harness.d.ts +0 -26
  632. package/dist/server/create-harness.d.ts.map +0 -1
  633. package/dist/server/create-harness.js +0 -107
  634. package/dist/server/create-harness.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow.js","sourceRoot":"","sources":["../../../../src/core/mcp/oauth/flow.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,YAAY,EAA0D,MAAM,WAAW,CAAC;AAEjG,OAAO,EAAE,2BAA2B,EAAkB,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACpH,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAElF,MAAM,OAAO,cAAe,SAAQ,KAAK;CAAG;AAU5C,MAAM,kBAAkB,GAAG,CAAC,GAAG,MAAM,CAAC;AACtC,6FAA6F;AAC7F,MAAM,cAAc,GAAG,MAAM,CAAC;AAC9B,MAAM,aAAa,GAAG,WAAW,CAAC;AAgBlC;;;;GAIG;AACH,MAAM,gBAAgB;IACZ,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IACvD,WAAW,GAAG,EAAE,CAAC;IACT,MAAM,CAAqB;IAC3B,WAAW,CAAuC;IAE1D,KAAK,CAAC,KAAK,GAAkB;QAC5B,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;QACnF,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;QAC7E,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;QACjC,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YACrD,MAAM,IAAI,cAAc,CAAC,+CAA+C,CAAC,CAAC;QAC3E,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,WAAW,GAAG,oBAAoB,OAAO,CAAC,IAAI,GAAG,aAAa,EAAE,CAAC;IAAA,CACtE;IAEO,MAAM,CAAC,OAAwB,EAAE,QAAwB,EAAQ;QACxE,MAAM,OAAO,GAAG,CAAC,MAAc,EAAE,IAAY,EAAE,EAAE,CAAC;YACjD,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC;YAC7D,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAAA,CACnB,CAAC;QACF,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,oBAAoB,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/F,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;QACjD,IAAI,GAAG,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;YACpC,OAAO,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;YAC1B,OAAO;QACR,CAAC;QACD,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;YAClD,OAAO,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;YAC9B,OAAO;QACR,CAAC;QACD,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC,IAAI,EAAE,CAAC;YACX,OAAO,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;YAC7B,OAAO;QACR,CAAC;QACD,OAAO,CAAC,GAAG,EAAE,iDAAiD,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC;QACjC,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;QAC7B,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;IAAA,CAChB;IAED,gFAAgF;IAChF,IAAI,CAAC,SAAiB,EAAmB;QACxC,OAAO,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC;YAC/C,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC;gBAC9B,MAAM,CAAC,IAAI,cAAc,CAAC,mBAAmB,SAAS,2CAA2C,CAAC,CAAC,CAAC;YAAA,CACpG,EAAE,SAAS,CAAC,CAAC;YACd,IAAI,CAAC,WAAW,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;gBAC5B,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,OAAO,CAAC,IAAI,CAAC,CAAC;YAAA,CACd,CAAC;QAAA,CACF,CAAC,CAAC;IAAA,CACH;IAED,KAAK,GAAkB;QACtB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC3B,IAAI,CAAC,MAAM;YAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QACtC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAAA,CAC/D;CACD;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAA4B,EAA+B;IAChG,MAAM,IAAI,GAAqB;QAC9B,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnE,WAAW,EAAE,OAAO,CAAC,IAAI,EAAE,WAAW,IAAI,CAAC,GAAG,EAAE,CAAC,EAAC,CAAC,CAAC;QACpD,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,IAAI,UAAU,CAAC,KAAK;QAC9C,GAAG,EAAE,OAAO,CAAC,IAAI,EAAE,GAAG,IAAI,IAAI,CAAC,GAAG;QAClC,SAAS,EAAE,OAAO,CAAC,IAAI,EAAE,SAAS,IAAI,kBAAkB;KACxD,CAAC;IACF,MAAM,QAAQ,GAAG,IAAI,gBAAgB,EAAE,CAAC;IACxC,IAAI,CAAC;QACJ,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC;QAEvB,IAAI,eAAmC,CAAC;QACxC,IAAI,CAAC;YACJ,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;YAClF,eAAe,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,SAAS,CAAC;QACtE,CAAC;QAAC,MAAM,CAAC;YACR,kEAAkE;QACnE,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,2BAA2B,CAAC;YAClD,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,eAAe;YACf,KAAK,EAAE,IAAI,CAAC,KAAK;SACjB,CAAC,CAAC;QAEH,IAAI,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QAChC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACf,IAAI,CAAC,QAAQ,CAAC,oBAAoB,EAAE,CAAC;gBACpC,MAAM,IAAI,cAAc,CACvB,iCAAiC,OAAO,CAAC,UAAU,4HAA4H,QAAQ,CAAC,WAAW,0BAA0B,CAC7N,CAAC;YACH,CAAC;YACD,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC;gBACvC,oBAAoB,EAAE,IAAI,GAAG,CAAC,QAAQ,CAAC,oBAAoB,CAAC;gBAC5D,UAAU,EAAE,6BAA2B,OAAO,CAAC,UAAU,GAAG;gBAC5D,YAAY,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;gBACpC,KAAK,EAAE,IAAI,CAAC,KAAK;aACjB,CAAC,CAAC;YACH,QAAQ,GAAG,UAAU,CAAC,QAAQ,CAAC;QAChC,CAAC;QAED,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;QAC9B,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC;QAC7D,YAAY,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;QACvD,YAAY,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QACrD,YAAY,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;QACpE,YAAY,CAAC,YAAY,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAChE,YAAY,CAAC,YAAY,CAAC,GAAG,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAAC;QAC/D,YAAY,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;QACvD,YAAY,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;QAE7D,IAAI,CAAC,KAAK,CAAC,cAAc,OAAO,CAAC,UAAU,iBAAiB,YAAY,EAAE,CAAC,CAAC;QAC5E,IAAI,CAAC;YACJ,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC3C,CAAC;QAAC,MAAM,CAAC;YACR,mEAAmE;QACpE,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACjD,MAAM,KAAK,GAAG,MAAM,yBAAyB,CAAC;YAC7C,aAAa,EAAE,IAAI,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC;YAC9C,IAAI;YACJ,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,WAAW,EAAE,QAAQ,CAAC,WAAW;YACjC,QAAQ;YACR,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,QAAQ,EAAE,OAAO,CAAC,SAAS;YAC3B,KAAK,EAAE,IAAI,CAAC,KAAK;SACjB,CAAC,CAAC;QAEH,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,gBAAgB,GAAG,IAAI,GAAG,cAAc,CAAC;QAC9E,MAAM,UAAU,GAAe;YAC9B,IAAI,EAAE,OAAO;YACb,MAAM,EAAE,KAAK,CAAC,WAAW;YACzB,sEAAsE;YACtE,OAAO,EAAE,KAAK,CAAC,YAAY,IAAI,EAAE;YACjC,OAAO,EAAE,SAAS;YAClB,aAAa,EAAE,QAAQ,CAAC,aAAa;YACrC,QAAQ,EAAE,OAAO,CAAC,SAAS;YAC3B,QAAQ;SACR,CAAC;QACF,MAAM,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC,UAAU,CAAC,CAAC;QAC/F,OAAO,EAAE,SAAS,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IACC,KAAK,YAAY,cAAc;YAC/B,KAAK,YAAY,mBAAmB;YACpC,KAAK,YAAY,kBAAkB,EAClC,CAAC;YACF,MAAM,KAAK,CAAC;QACb,CAAC;QACD,MAAM,IAAI,cAAc,CAAC,mBAAmB,OAAO,CAAC,UAAU,aAAa,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACxG,CAAC;YAAS,CAAC;QACV,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;AAAA,CACD","sourcesContent":["/**\n * The user-initiated OAuth authorization flow for one MCP server: authorization-code\n * with PKCE against a loopback callback listener that exists only for the duration of\n * the flow. Per ADR 0023's posture, nothing here is reachable from a tool call — the\n * command is the only entry point.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport type { Credential, CredentialStore } from \"@earendil-works/pi-ai\";\nimport { discoverAuthorizationServer, type FetchLike, OAuthDiscoveryError, oauthErrorMessage } from \"./discover.ts\";\nimport { mcpCredentialKey } from \"./mcp-token.ts\";\nimport { createPkcePair } from \"./pkce.ts\";\nimport { registerClient } from \"./register.ts\";\nimport { exchangeAuthorizationCode, TokenEndpointError } from \"./token-client.ts\";\n\nexport class OAuthFlowError extends Error {}\n\nexport interface McpOAuthFlowDeps {\n\tprint: (line: string) => void;\n\topenBrowser: (url: string) => void;\n\tfetch: FetchLike;\n\tnow: () => number;\n\ttimeoutMs: number;\n}\n\nconst DEFAULT_TIMEOUT_MS = 5 * 60_000;\n/** Store the token as expiring a minute early, so in-flight calls never ride it to death. */\nconst EXPIRY_SKEW_MS = 60_000;\nconst CALLBACK_PATH = \"/callback\";\n\nexport interface McpOAuthFlowOptions {\n\tserverName: string;\n\tserverUrl: string;\n\tcredentials: CredentialStore;\n\t/** A manually registered client id; skips dynamic registration when present. */\n\tclientId?: string;\n\tclientSecret?: string;\n\tdeps?: Partial<McpOAuthFlowDeps>;\n}\n\nexport interface McpOAuthFlowResult {\n\texpiresAt: number;\n}\n\n/**\n * Accepts exactly one callback carrying the issued `state`, then stops. A request with\n * the wrong state is answered 400 and the listener stays available for the real one;\n * after the right one, the socket is closed before the flow proceeds to the exchange.\n */\nclass LoopbackCallback {\n\treadonly state = randomBytes(16).toString(\"base64url\");\n\tredirectUri = \"\";\n\tprivate server: Server | undefined;\n\tprivate resolveCode: ((code: string) => void) | undefined;\n\n\tasync start(): Promise<void> {\n\t\tconst server = createServer((request, response) => this.handle(request, response));\n\t\tawait new Promise<void>((resolve) => server.listen(0, \"127.0.0.1\", resolve));\n\t\tconst address = server.address();\n\t\tif (address === null || typeof address === \"string\") {\n\t\t\tthrow new OAuthFlowError(\"could not bind the loopback callback listener\");\n\t\t}\n\t\tthis.server = server;\n\t\tthis.redirectUri = `http://127.0.0.1:${address.port}${CALLBACK_PATH}`;\n\t}\n\n\tprivate handle(request: IncomingMessage, response: ServerResponse): void {\n\t\tconst respond = (status: number, body: string) => {\n\t\t\tresponse.writeHead(status, { \"content-type\": \"text/plain\" });\n\t\t\tresponse.end(body);\n\t\t};\n\t\tconst port = this.server?.address();\n\t\tconst origin = `http://127.0.0.1:${port !== null && typeof port === \"object\" ? port.port : 0}`;\n\t\tconst url = new URL(String(request.url), origin);\n\t\tif (url.pathname !== CALLBACK_PATH) {\n\t\t\trespond(404, \"not found\");\n\t\t\treturn;\n\t\t}\n\t\tif (url.searchParams.get(\"state\") !== this.state) {\n\t\t\trespond(400, \"invalid state\");\n\t\t\treturn;\n\t\t}\n\t\tconst code = url.searchParams.get(\"code\");\n\t\tif (!code) {\n\t\t\trespond(400, \"missing code\");\n\t\t\treturn;\n\t\t}\n\t\trespond(200, \"Authorization complete. You can close this tab.\");\n\t\tconst resolve = this.resolveCode;\n\t\tthis.resolveCode = undefined;\n\t\tresolve?.(code);\n\t}\n\n\t/** Resolves with the authorization code, or rejects when the flow times out. */\n\tcode(timeoutMs: number): Promise<string> {\n\t\treturn new Promise<string>((resolve, reject) => {\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\treject(new OAuthFlowError(`timed out after ${timeoutMs} ms waiting for authorization to complete`));\n\t\t\t}, timeoutMs);\n\t\t\tthis.resolveCode = (code) => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\tresolve(code);\n\t\t\t};\n\t\t});\n\t}\n\n\tclose(): Promise<void> {\n\t\tconst server = this.server;\n\t\tif (!server) return Promise.resolve();\n\t\treturn new Promise((resolve) => server.close(() => resolve()));\n\t}\n}\n\nexport async function runMcpOAuthFlow(options: McpOAuthFlowOptions): Promise<McpOAuthFlowResult> {\n\tconst deps: McpOAuthFlowDeps = {\n\t\tprint: options.deps?.print ?? ((line: string) => console.log(line)),\n\t\topenBrowser: options.deps?.openBrowser ?? (() => {}),\n\t\tfetch: options.deps?.fetch ?? globalThis.fetch,\n\t\tnow: options.deps?.now ?? Date.now,\n\t\ttimeoutMs: options.deps?.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n\t};\n\tconst callback = new LoopbackCallback();\n\ttry {\n\t\tawait callback.start();\n\n\t\tlet wwwAuthenticate: string | undefined;\n\t\ttry {\n\t\t\tconst probe = await deps.fetch(new URL(options.serverUrl), { redirect: \"error\" });\n\t\t\twwwAuthenticate = probe.headers.get(\"www-authenticate\") ?? undefined;\n\t\t} catch {\n\t\t\t// The probe is advisory; discovery falls back to well-known URIs.\n\t\t}\n\t\tconst metadata = await discoverAuthorizationServer({\n\t\t\tserverUrl: options.serverUrl,\n\t\t\twwwAuthenticate,\n\t\t\tfetch: deps.fetch,\n\t\t});\n\n\t\tlet clientId = options.clientId;\n\t\tif (!clientId) {\n\t\t\tif (!metadata.registrationEndpoint) {\n\t\t\t\tthrow new OAuthFlowError(\n\t\t\t\t\t`The authorization server for \"${options.serverName}\" supports no dynamic client registration, so this needs manual client registration: register a client with redirect URI ${callback.redirectUri} and pass its client id.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst registered = await registerClient({\n\t\t\t\tregistrationEndpoint: new URL(metadata.registrationEndpoint),\n\t\t\t\tclientName: `Apex Code — MCP server \"${options.serverName}\"`,\n\t\t\t\tredirectUris: [callback.redirectUri],\n\t\t\t\tfetch: deps.fetch,\n\t\t\t});\n\t\t\tclientId = registered.clientId;\n\t\t}\n\n\t\tconst pkce = createPkcePair();\n\t\tconst authorizeUrl = new URL(metadata.authorizationEndpoint);\n\t\tauthorizeUrl.searchParams.set(\"response_type\", \"code\");\n\t\tauthorizeUrl.searchParams.set(\"client_id\", clientId);\n\t\tauthorizeUrl.searchParams.set(\"redirect_uri\", callback.redirectUri);\n\t\tauthorizeUrl.searchParams.set(\"code_challenge\", pkce.challenge);\n\t\tauthorizeUrl.searchParams.set(\"code_challenge_method\", \"S256\");\n\t\tauthorizeUrl.searchParams.set(\"state\", callback.state);\n\t\tauthorizeUrl.searchParams.set(\"resource\", options.serverUrl);\n\n\t\tdeps.print(`Authorize \"${options.serverName}\" by opening: ${authorizeUrl}`);\n\t\ttry {\n\t\t\tdeps.openBrowser(authorizeUrl.toString());\n\t\t} catch {\n\t\t\t// The URL is printed either way; opening a browser is best-effort.\n\t\t}\n\n\t\tconst code = await callback.code(deps.timeoutMs);\n\t\tconst token = await exchangeAuthorizationCode({\n\t\t\ttokenEndpoint: new URL(metadata.tokenEndpoint),\n\t\t\tcode,\n\t\t\tverifier: pkce.verifier,\n\t\t\tredirectUri: callback.redirectUri,\n\t\t\tclientId,\n\t\t\tclientSecret: options.clientSecret,\n\t\t\tresource: options.serverUrl,\n\t\t\tfetch: deps.fetch,\n\t\t});\n\n\t\tconst expiresAt = deps.now() + token.expiresInSeconds * 1000 - EXPIRY_SKEW_MS;\n\t\tconst credential: Credential = {\n\t\t\ttype: \"oauth\",\n\t\t\taccess: token.accessToken,\n\t\t\t// An absent rotation keeps the refresh token the server still honors.\n\t\t\trefresh: token.refreshToken ?? \"\",\n\t\t\texpires: expiresAt,\n\t\t\ttokenEndpoint: metadata.tokenEndpoint,\n\t\t\tresource: options.serverUrl,\n\t\t\tclientId,\n\t\t};\n\t\tawait options.credentials.modify(mcpCredentialKey(options.serverName), async () => credential);\n\t\treturn { expiresAt };\n\t} catch (error) {\n\t\tif (\n\t\t\terror instanceof OAuthFlowError ||\n\t\t\terror instanceof OAuthDiscoveryError ||\n\t\t\terror instanceof TokenEndpointError\n\t\t) {\n\t\t\tthrow error;\n\t\t}\n\t\tthrow new OAuthFlowError(`OAuth flow for \"${options.serverName}\" failed: ${oauthErrorMessage(error)}`);\n\t} finally {\n\t\tawait callback.close();\n\t}\n}\n"]}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * The MCP credential seam: how an MCP server's OAuth token is keyed, read, and
3
+ * refreshed through the session's existing `CredentialStore`.
4
+ *
5
+ * Which store instance that is depends on where the session runs. On the host it is
6
+ * `AuthStorage` (direct, lock-serialized writes); in a sandboxed child it is
7
+ * `SandboxAuthStorage` (reads from the read-only projection, writes through the
8
+ * supervisor-mediated channel, ADR 0015). A session with neither has a read-only
9
+ * store whose `modify` throws, which is the fail-closed path: refresh never
10
+ * silently degrades to "pretend it worked".
11
+ */
12
+ import type { CredentialStore } from "@earendil-works/pi-ai";
13
+ import type { McpServerConfig } from "../types.ts";
14
+ import { type FetchLike } from "./discover.ts";
15
+ export declare function mcpCredentialKey(serverName: string): string;
16
+ /** Extra fields carried on the `OAuthCredential` index signature, written by the flow. */
17
+ interface McpTokenExtras {
18
+ tokenEndpoint?: string;
19
+ resource?: string;
20
+ clientId?: string;
21
+ }
22
+ export interface StoredServerToken {
23
+ accessToken: string;
24
+ /** Empty when the server issued no refresh token; refresh is impossible then. */
25
+ refreshToken: string;
26
+ expiresAt: number;
27
+ extras: McpTokenExtras;
28
+ }
29
+ export declare class McpOAuthRequiredError extends Error {
30
+ }
31
+ export declare class McpOAuthRefreshError extends Error {
32
+ /** "refused": the server said no; "unavailable": the path to the store or network failed. */
33
+ stage: "refused" | "unavailable";
34
+ constructor(message: string, stage: "refused" | "unavailable");
35
+ }
36
+ export declare function authRequired(serverName: string): McpOAuthRequiredError;
37
+ export declare function readServerToken(credentials: CredentialStore, serverName: string): Promise<StoredServerToken | undefined>;
38
+ /**
39
+ * Returns a current access token for the server, refreshing first when the stored one
40
+ * is at the edge of expiry. Throws `McpOAuthRequiredError` when nothing is stored and
41
+ * `McpOAuthRefreshError` when a refresh cannot be completed; both name the auth
42
+ * command in their message.
43
+ */
44
+ export declare function ensureFreshServerToken(options: {
45
+ server: McpServerConfig;
46
+ credentials: CredentialStore;
47
+ now?: () => number;
48
+ fetch?: FetchLike;
49
+ }): Promise<string>;
50
+ export {};
51
+ //# sourceMappingURL=mcp-token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-token.d.ts","sourceRoot":"","sources":["../../../../src/core/mcp/oauth/mcp-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAc,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAA+B,KAAK,SAAS,EAAqB,MAAM,eAAe,CAAC;AAW/F,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,0FAA0F;AAC1F,UAAU,cAAc;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;CACvB;AAED,qBAAa,qBAAsB,SAAQ,KAAK;CAAG;AAEnD,qBAAa,oBAAqB,SAAQ,KAAK;IAC9C,6FAA6F;IAC7F,KAAK,EAAE,SAAS,GAAG,aAAa,CAAC;IAEjC,YAAY,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,aAAa,EAG5D;CACD;AAED,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,qBAAqB,CAItE;AAqBD,wBAAsB,eAAe,CACpC,WAAW,EAAE,eAAe,EAC5B,UAAU,EAAE,MAAM,GAChB,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAGxC;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE;IACrD,MAAM,EAAE,eAAe,CAAC;IACxB,WAAW,EAAE,eAAe,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,SAAS,CAAC;CAClB,GAAG,OAAO,CAAC,MAAM,CAAC,CA8ElB","sourcesContent":["/**\n * The MCP credential seam: how an MCP server's OAuth token is keyed, read, and\n * refreshed through the session's existing `CredentialStore`.\n *\n * Which store instance that is depends on where the session runs. On the host it is\n * `AuthStorage` (direct, lock-serialized writes); in a sandboxed child it is\n * `SandboxAuthStorage` (reads from the read-only projection, writes through the\n * supervisor-mediated channel, ADR 0015). A session with neither has a read-only\n * store whose `modify` throws, which is the fail-closed path: refresh never\n * silently degrades to \"pretend it worked\".\n */\n\nimport type { Credential, CredentialStore } from \"@earendil-works/pi-ai\";\nimport type { McpServerConfig } from \"../types.ts\";\nimport { discoverAuthorizationServer, type FetchLike, oauthErrorMessage } from \"./discover.ts\";\nimport {\n\trefreshAccessToken,\n\tTokenEndpointError,\n\tTokenEndpointUnreachableError,\n\ttype TokenResponse,\n} from \"./token-client.ts\";\n\n/** Refresh this long before expiry so an in-flight call never rides a dying token. */\nconst REFRESH_SKEW_MS = 60_000;\n\nexport function mcpCredentialKey(serverName: string): string {\n\treturn `mcp/${serverName}`;\n}\n\n/** Extra fields carried on the `OAuthCredential` index signature, written by the flow. */\ninterface McpTokenExtras {\n\ttokenEndpoint?: string;\n\tresource?: string;\n\tclientId?: string;\n}\n\nexport interface StoredServerToken {\n\taccessToken: string;\n\t/** Empty when the server issued no refresh token; refresh is impossible then. */\n\trefreshToken: string;\n\texpiresAt: number;\n\textras: McpTokenExtras;\n}\n\nexport class McpOAuthRequiredError extends Error {}\n\nexport class McpOAuthRefreshError extends Error {\n\t/** \"refused\": the server said no; \"unavailable\": the path to the store or network failed. */\n\tstage: \"refused\" | \"unavailable\";\n\n\tconstructor(message: string, stage: \"refused\" | \"unavailable\") {\n\t\tsuper(message);\n\t\tthis.stage = stage;\n\t}\n}\n\nexport function authRequired(serverName: string): McpOAuthRequiredError {\n\treturn new McpOAuthRequiredError(\n\t\t`MCP server \"${serverName}\" requires OAuth and has no stored authorization. Run \\`apex-code mcp auth ${serverName}\\` to authorize it, then retry.`,\n\t);\n}\n\nfunction extrasOf(credential: Credential): McpTokenExtras {\n\tif (credential.type !== \"oauth\") return {};\n\tconst extras: McpTokenExtras = {};\n\tif (typeof credential.tokenEndpoint === \"string\") extras.tokenEndpoint = credential.tokenEndpoint;\n\tif (typeof credential.resource === \"string\") extras.resource = credential.resource;\n\tif (typeof credential.clientId === \"string\") extras.clientId = credential.clientId;\n\treturn extras;\n}\n\nfunction toStoredToken(credential: Credential): StoredServerToken | undefined {\n\tif (credential.type !== \"oauth\") return undefined;\n\treturn {\n\t\taccessToken: credential.access,\n\t\trefreshToken: credential.refresh,\n\t\texpiresAt: credential.expires,\n\t\textras: extrasOf(credential),\n\t};\n}\n\nexport async function readServerToken(\n\tcredentials: CredentialStore,\n\tserverName: string,\n): Promise<StoredServerToken | undefined> {\n\tconst credential: Credential | undefined = await credentials.read(mcpCredentialKey(serverName));\n\treturn credential ? toStoredToken(credential) : undefined;\n}\n\n/**\n * Returns a current access token for the server, refreshing first when the stored one\n * is at the edge of expiry. Throws `McpOAuthRequiredError` when nothing is stored and\n * `McpOAuthRefreshError` when a refresh cannot be completed; both name the auth\n * command in their message.\n */\nexport async function ensureFreshServerToken(options: {\n\tserver: McpServerConfig;\n\tcredentials: CredentialStore;\n\tnow?: () => number;\n\tfetch?: FetchLike;\n}): Promise<string> {\n\tconst { server, credentials } = options;\n\tconst now = options.now ?? Date.now;\n\tconst serverName = server.name;\n\tconst stored = await readServerToken(credentials, serverName);\n\tif (!stored) throw authRequired(serverName);\n\tif (stored.expiresAt - REFRESH_SKEW_MS > now()) return stored.accessToken;\n\tif (!stored.refreshToken) {\n\t\tthrow new McpOAuthRefreshError(\n\t\t\t`MCP server \"${serverName}\" authorization has expired and no refresh token was issued. Run \\`apex-code mcp auth ${serverName}\\` to authorize it again.`,\n\t\t\t\"refused\",\n\t\t);\n\t}\n\tif (server.transport.kind !== \"http\") {\n\t\tthrow new McpOAuthRefreshError(\n\t\t\t`MCP server \"${serverName}\" is not an HTTP server; run \\`apex-code mcp auth ${serverName}\\`.`,\n\t\t\t\"refused\",\n\t\t);\n\t}\n\tconst resource = stored.extras.resource ?? server.transport.url;\n\n\tlet tokenEndpoint = stored.extras.tokenEndpoint;\n\tif (!tokenEndpoint) {\n\t\tconst metadata = await discoverAuthorizationServer({ serverUrl: server.transport.url, fetch: options.fetch });\n\t\ttokenEndpoint = metadata.tokenEndpoint;\n\t}\n\n\tlet refreshed: TokenResponse;\n\ttry {\n\t\trefreshed = await refreshAccessToken({\n\t\t\ttokenEndpoint: new URL(tokenEndpoint),\n\t\t\trefreshToken: stored.refreshToken,\n\t\t\tclientId: stored.extras.clientId ?? `apex-code-mcp-${serverName}`,\n\t\t\tresource,\n\t\t\tfetch: options.fetch,\n\t\t});\n\t} catch (error) {\n\t\tif (error instanceof TokenEndpointError && error.code === \"invalid_grant\") {\n\t\t\tthrow new McpOAuthRefreshError(\n\t\t\t\t`MCP server \"${serverName}\" rejected its refresh token. Run \\`apex-code mcp auth ${serverName}\\` to authorize it again.`,\n\t\t\t\t\"refused\",\n\t\t\t);\n\t\t}\n\t\tif (error instanceof TokenEndpointUnreachableError) {\n\t\t\tthrow new McpOAuthRefreshError(`MCP server \"${serverName}\" refresh failed: ${error.message}`, \"unavailable\");\n\t\t}\n\t\tif (error instanceof TokenEndpointError) {\n\t\t\tthrow new McpOAuthRefreshError(`MCP server \"${serverName}\" refresh failed: ${error.message}`, \"refused\");\n\t\t}\n\t\tthrow new McpOAuthRefreshError(\n\t\t\t`MCP server \"${serverName}\" refresh failed: ${oauthErrorMessage(error)}`,\n\t\t\t\"unavailable\",\n\t\t);\n\t}\n\n\tconst expiresAt = now() + refreshed.expiresInSeconds * 1000 - REFRESH_SKEW_MS;\n\tconst credential: Credential = {\n\t\ttype: \"oauth\",\n\t\taccess: refreshed.accessToken,\n\t\t// No rotation: keep the refresh token the server still honors.\n\t\trefresh: refreshed.refreshToken ?? stored.refreshToken,\n\t\texpires: expiresAt,\n\t\ttokenEndpoint,\n\t\tresource,\n\t\tclientId: stored.extras.clientId,\n\t};\n\ttry {\n\t\tawait credentials.modify(mcpCredentialKey(serverName), async () => credential);\n\t} catch (error) {\n\t\t// The fresh access token works for this connection, but the store could not\n\t\t// record the rotation — for a sandboxed child, that is the channel refusing.\n\t\t// Fail this call closed rather than run ahead of what the store knows.\n\t\tthrow new McpOAuthRefreshError(\n\t\t\t`MCP server \"${serverName}\" was refreshed but the session cannot store the new token: ${oauthErrorMessage(error)}`,\n\t\t\t\"unavailable\",\n\t\t);\n\t}\n\treturn refreshed.accessToken;\n}\n"]}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * The MCP credential seam: how an MCP server's OAuth token is keyed, read, and
3
+ * refreshed through the session's existing `CredentialStore`.
4
+ *
5
+ * Which store instance that is depends on where the session runs. On the host it is
6
+ * `AuthStorage` (direct, lock-serialized writes); in a sandboxed child it is
7
+ * `SandboxAuthStorage` (reads from the read-only projection, writes through the
8
+ * supervisor-mediated channel, ADR 0015). A session with neither has a read-only
9
+ * store whose `modify` throws, which is the fail-closed path: refresh never
10
+ * silently degrades to "pretend it worked".
11
+ */
12
+ import { discoverAuthorizationServer, oauthErrorMessage } from "./discover.js";
13
+ import { refreshAccessToken, TokenEndpointError, TokenEndpointUnreachableError, } from "./token-client.js";
14
+ /** Refresh this long before expiry so an in-flight call never rides a dying token. */
15
+ const REFRESH_SKEW_MS = 60_000;
16
+ export function mcpCredentialKey(serverName) {
17
+ return `mcp/${serverName}`;
18
+ }
19
+ export class McpOAuthRequiredError extends Error {
20
+ }
21
+ export class McpOAuthRefreshError extends Error {
22
+ /** "refused": the server said no; "unavailable": the path to the store or network failed. */
23
+ stage;
24
+ constructor(message, stage) {
25
+ super(message);
26
+ this.stage = stage;
27
+ }
28
+ }
29
+ export function authRequired(serverName) {
30
+ return new McpOAuthRequiredError(`MCP server "${serverName}" requires OAuth and has no stored authorization. Run \`apex-code mcp auth ${serverName}\` to authorize it, then retry.`);
31
+ }
32
+ function extrasOf(credential) {
33
+ if (credential.type !== "oauth")
34
+ return {};
35
+ const extras = {};
36
+ if (typeof credential.tokenEndpoint === "string")
37
+ extras.tokenEndpoint = credential.tokenEndpoint;
38
+ if (typeof credential.resource === "string")
39
+ extras.resource = credential.resource;
40
+ if (typeof credential.clientId === "string")
41
+ extras.clientId = credential.clientId;
42
+ return extras;
43
+ }
44
+ function toStoredToken(credential) {
45
+ if (credential.type !== "oauth")
46
+ return undefined;
47
+ return {
48
+ accessToken: credential.access,
49
+ refreshToken: credential.refresh,
50
+ expiresAt: credential.expires,
51
+ extras: extrasOf(credential),
52
+ };
53
+ }
54
+ export async function readServerToken(credentials, serverName) {
55
+ const credential = await credentials.read(mcpCredentialKey(serverName));
56
+ return credential ? toStoredToken(credential) : undefined;
57
+ }
58
+ /**
59
+ * Returns a current access token for the server, refreshing first when the stored one
60
+ * is at the edge of expiry. Throws `McpOAuthRequiredError` when nothing is stored and
61
+ * `McpOAuthRefreshError` when a refresh cannot be completed; both name the auth
62
+ * command in their message.
63
+ */
64
+ export async function ensureFreshServerToken(options) {
65
+ const { server, credentials } = options;
66
+ const now = options.now ?? Date.now;
67
+ const serverName = server.name;
68
+ const stored = await readServerToken(credentials, serverName);
69
+ if (!stored)
70
+ throw authRequired(serverName);
71
+ if (stored.expiresAt - REFRESH_SKEW_MS > now())
72
+ return stored.accessToken;
73
+ if (!stored.refreshToken) {
74
+ throw new McpOAuthRefreshError(`MCP server "${serverName}" authorization has expired and no refresh token was issued. Run \`apex-code mcp auth ${serverName}\` to authorize it again.`, "refused");
75
+ }
76
+ if (server.transport.kind !== "http") {
77
+ throw new McpOAuthRefreshError(`MCP server "${serverName}" is not an HTTP server; run \`apex-code mcp auth ${serverName}\`.`, "refused");
78
+ }
79
+ const resource = stored.extras.resource ?? server.transport.url;
80
+ let tokenEndpoint = stored.extras.tokenEndpoint;
81
+ if (!tokenEndpoint) {
82
+ const metadata = await discoverAuthorizationServer({ serverUrl: server.transport.url, fetch: options.fetch });
83
+ tokenEndpoint = metadata.tokenEndpoint;
84
+ }
85
+ let refreshed;
86
+ try {
87
+ refreshed = await refreshAccessToken({
88
+ tokenEndpoint: new URL(tokenEndpoint),
89
+ refreshToken: stored.refreshToken,
90
+ clientId: stored.extras.clientId ?? `apex-code-mcp-${serverName}`,
91
+ resource,
92
+ fetch: options.fetch,
93
+ });
94
+ }
95
+ catch (error) {
96
+ if (error instanceof TokenEndpointError && error.code === "invalid_grant") {
97
+ throw new McpOAuthRefreshError(`MCP server "${serverName}" rejected its refresh token. Run \`apex-code mcp auth ${serverName}\` to authorize it again.`, "refused");
98
+ }
99
+ if (error instanceof TokenEndpointUnreachableError) {
100
+ throw new McpOAuthRefreshError(`MCP server "${serverName}" refresh failed: ${error.message}`, "unavailable");
101
+ }
102
+ if (error instanceof TokenEndpointError) {
103
+ throw new McpOAuthRefreshError(`MCP server "${serverName}" refresh failed: ${error.message}`, "refused");
104
+ }
105
+ throw new McpOAuthRefreshError(`MCP server "${serverName}" refresh failed: ${oauthErrorMessage(error)}`, "unavailable");
106
+ }
107
+ const expiresAt = now() + refreshed.expiresInSeconds * 1000 - REFRESH_SKEW_MS;
108
+ const credential = {
109
+ type: "oauth",
110
+ access: refreshed.accessToken,
111
+ // No rotation: keep the refresh token the server still honors.
112
+ refresh: refreshed.refreshToken ?? stored.refreshToken,
113
+ expires: expiresAt,
114
+ tokenEndpoint,
115
+ resource,
116
+ clientId: stored.extras.clientId,
117
+ };
118
+ try {
119
+ await credentials.modify(mcpCredentialKey(serverName), async () => credential);
120
+ }
121
+ catch (error) {
122
+ // The fresh access token works for this connection, but the store could not
123
+ // record the rotation — for a sandboxed child, that is the channel refusing.
124
+ // Fail this call closed rather than run ahead of what the store knows.
125
+ throw new McpOAuthRefreshError(`MCP server "${serverName}" was refreshed but the session cannot store the new token: ${oauthErrorMessage(error)}`, "unavailable");
126
+ }
127
+ return refreshed.accessToken;
128
+ }
129
+ //# sourceMappingURL=mcp-token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-token.js","sourceRoot":"","sources":["../../../../src/core/mcp/oauth/mcp-token.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The MCP credential seam: how an MCP server's OAuth token is keyed, read, and\n * refreshed through the session's existing `CredentialStore`.\n *\n * Which store instance that is depends on where the session runs. On the host it is\n * `AuthStorage` (direct, lock-serialized writes); in a sandboxed child it is\n * `SandboxAuthStorage` (reads from the read-only projection, writes through the\n * supervisor-mediated channel, ADR 0015). A session with neither has a read-only\n * store whose `modify` throws, which is the fail-closed path: refresh never\n * silently degrades to \"pretend it worked\".\n */\n\nimport type { Credential, CredentialStore } from \"@earendil-works/pi-ai\";\nimport type { McpServerConfig } from \"../types.ts\";\nimport { discoverAuthorizationServer, type FetchLike, oauthErrorMessage } from \"./discover.ts\";\nimport {\n\trefreshAccessToken,\n\tTokenEndpointError,\n\tTokenEndpointUnreachableError,\n\ttype TokenResponse,\n} from \"./token-client.ts\";\n\n/** Refresh this long before expiry so an in-flight call never rides a dying token. */\nconst REFRESH_SKEW_MS = 60_000;\n\nexport function mcpCredentialKey(serverName: string): string {\n\treturn `mcp/${serverName}`;\n}\n\n/** Extra fields carried on the `OAuthCredential` index signature, written by the flow. */\ninterface McpTokenExtras {\n\ttokenEndpoint?: string;\n\tresource?: string;\n\tclientId?: string;\n}\n\nexport interface StoredServerToken {\n\taccessToken: string;\n\t/** Empty when the server issued no refresh token; refresh is impossible then. */\n\trefreshToken: string;\n\texpiresAt: number;\n\textras: McpTokenExtras;\n}\n\nexport class McpOAuthRequiredError extends Error {}\n\nexport class McpOAuthRefreshError extends Error {\n\t/** \"refused\": the server said no; \"unavailable\": the path to the store or network failed. */\n\tstage: \"refused\" | \"unavailable\";\n\n\tconstructor(message: string, stage: \"refused\" | \"unavailable\") {\n\t\tsuper(message);\n\t\tthis.stage = stage;\n\t}\n}\n\nexport function authRequired(serverName: string): McpOAuthRequiredError {\n\treturn new McpOAuthRequiredError(\n\t\t`MCP server \"${serverName}\" requires OAuth and has no stored authorization. Run \\`apex-code mcp auth ${serverName}\\` to authorize it, then retry.`,\n\t);\n}\n\nfunction extrasOf(credential: Credential): McpTokenExtras {\n\tif (credential.type !== \"oauth\") return {};\n\tconst extras: McpTokenExtras = {};\n\tif (typeof credential.tokenEndpoint === \"string\") extras.tokenEndpoint = credential.tokenEndpoint;\n\tif (typeof credential.resource === \"string\") extras.resource = credential.resource;\n\tif (typeof credential.clientId === \"string\") extras.clientId = credential.clientId;\n\treturn extras;\n}\n\nfunction toStoredToken(credential: Credential): StoredServerToken | undefined {\n\tif (credential.type !== \"oauth\") return undefined;\n\treturn {\n\t\taccessToken: credential.access,\n\t\trefreshToken: credential.refresh,\n\t\texpiresAt: credential.expires,\n\t\textras: extrasOf(credential),\n\t};\n}\n\nexport async function readServerToken(\n\tcredentials: CredentialStore,\n\tserverName: string,\n): Promise<StoredServerToken | undefined> {\n\tconst credential: Credential | undefined = await credentials.read(mcpCredentialKey(serverName));\n\treturn credential ? toStoredToken(credential) : undefined;\n}\n\n/**\n * Returns a current access token for the server, refreshing first when the stored one\n * is at the edge of expiry. Throws `McpOAuthRequiredError` when nothing is stored and\n * `McpOAuthRefreshError` when a refresh cannot be completed; both name the auth\n * command in their message.\n */\nexport async function ensureFreshServerToken(options: {\n\tserver: McpServerConfig;\n\tcredentials: CredentialStore;\n\tnow?: () => number;\n\tfetch?: FetchLike;\n}): Promise<string> {\n\tconst { server, credentials } = options;\n\tconst now = options.now ?? Date.now;\n\tconst serverName = server.name;\n\tconst stored = await readServerToken(credentials, serverName);\n\tif (!stored) throw authRequired(serverName);\n\tif (stored.expiresAt - REFRESH_SKEW_MS > now()) return stored.accessToken;\n\tif (!stored.refreshToken) {\n\t\tthrow new McpOAuthRefreshError(\n\t\t\t`MCP server \"${serverName}\" authorization has expired and no refresh token was issued. Run \\`apex-code mcp auth ${serverName}\\` to authorize it again.`,\n\t\t\t\"refused\",\n\t\t);\n\t}\n\tif (server.transport.kind !== \"http\") {\n\t\tthrow new McpOAuthRefreshError(\n\t\t\t`MCP server \"${serverName}\" is not an HTTP server; run \\`apex-code mcp auth ${serverName}\\`.`,\n\t\t\t\"refused\",\n\t\t);\n\t}\n\tconst resource = stored.extras.resource ?? server.transport.url;\n\n\tlet tokenEndpoint = stored.extras.tokenEndpoint;\n\tif (!tokenEndpoint) {\n\t\tconst metadata = await discoverAuthorizationServer({ serverUrl: server.transport.url, fetch: options.fetch });\n\t\ttokenEndpoint = metadata.tokenEndpoint;\n\t}\n\n\tlet refreshed: TokenResponse;\n\ttry {\n\t\trefreshed = await refreshAccessToken({\n\t\t\ttokenEndpoint: new URL(tokenEndpoint),\n\t\t\trefreshToken: stored.refreshToken,\n\t\t\tclientId: stored.extras.clientId ?? `apex-code-mcp-${serverName}`,\n\t\t\tresource,\n\t\t\tfetch: options.fetch,\n\t\t});\n\t} catch (error) {\n\t\tif (error instanceof TokenEndpointError && error.code === \"invalid_grant\") {\n\t\t\tthrow new McpOAuthRefreshError(\n\t\t\t\t`MCP server \"${serverName}\" rejected its refresh token. Run \\`apex-code mcp auth ${serverName}\\` to authorize it again.`,\n\t\t\t\t\"refused\",\n\t\t\t);\n\t\t}\n\t\tif (error instanceof TokenEndpointUnreachableError) {\n\t\t\tthrow new McpOAuthRefreshError(`MCP server \"${serverName}\" refresh failed: ${error.message}`, \"unavailable\");\n\t\t}\n\t\tif (error instanceof TokenEndpointError) {\n\t\t\tthrow new McpOAuthRefreshError(`MCP server \"${serverName}\" refresh failed: ${error.message}`, \"refused\");\n\t\t}\n\t\tthrow new McpOAuthRefreshError(\n\t\t\t`MCP server \"${serverName}\" refresh failed: ${oauthErrorMessage(error)}`,\n\t\t\t\"unavailable\",\n\t\t);\n\t}\n\n\tconst expiresAt = now() + refreshed.expiresInSeconds * 1000 - REFRESH_SKEW_MS;\n\tconst credential: Credential = {\n\t\ttype: \"oauth\",\n\t\taccess: refreshed.accessToken,\n\t\t// No rotation: keep the refresh token the server still honors.\n\t\trefresh: refreshed.refreshToken ?? stored.refreshToken,\n\t\texpires: expiresAt,\n\t\ttokenEndpoint,\n\t\tresource,\n\t\tclientId: stored.extras.clientId,\n\t};\n\ttry {\n\t\tawait credentials.modify(mcpCredentialKey(serverName), async () => credential);\n\t} catch (error) {\n\t\t// The fresh access token works for this connection, but the store could not\n\t\t// record the rotation — for a sandboxed child, that is the channel refusing.\n\t\t// Fail this call closed rather than run ahead of what the store knows.\n\t\tthrow new McpOAuthRefreshError(\n\t\t\t`MCP server \"${serverName}\" was refreshed but the session cannot store the new token: ${oauthErrorMessage(error)}`,\n\t\t\t\"unavailable\",\n\t\t);\n\t}\n\treturn refreshed.accessToken;\n}\n"]}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * PKCE (RFC 7636), the S256 method only. Every MCP authorization server is required
3
+ * to support it, and a verifier that never travels with the code is the only thing
4
+ * standing between a callback URL and a token, so there is no plain fallback here.
5
+ */
6
+ export interface PkcePair {
7
+ verifier: string;
8
+ challenge: string;
9
+ }
10
+ export declare function pkceChallenge(verifier: string): string;
11
+ export declare function createPkcePair(random?: (size: number) => Buffer): PkcePair;
12
+ //# sourceMappingURL=pkce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../../../../src/core/mcp/oauth/pkce.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,MAAM,WAAW,QAAQ;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CAClB;AAKD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,cAAc,CAAC,MAAM,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAoB,GAAG,QAAQ,CAGvF","sourcesContent":["import { createHash, randomBytes } from \"node:crypto\";\n\n/**\n * PKCE (RFC 7636), the S256 method only. Every MCP authorization server is required\n * to support it, and a verifier that never travels with the code is the only thing\n * standing between a callback URL and a token, so there is no plain fallback here.\n */\n\nexport interface PkcePair {\n\tverifier: string;\n\tchallenge: string;\n}\n\n/** 48 bytes → 64 base64url characters, inside RFC 7636's 43-128 range. */\nconst VERIFIER_BYTES = 48;\n\nexport function pkceChallenge(verifier: string): string {\n\treturn createHash(\"sha256\").update(verifier, \"ascii\").digest(\"base64url\");\n}\n\nexport function createPkcePair(random: (size: number) => Buffer = randomBytes): PkcePair {\n\tconst verifier = random(VERIFIER_BYTES).toString(\"base64url\");\n\treturn { verifier, challenge: pkceChallenge(verifier) };\n}\n"]}
@@ -0,0 +1,11 @@
1
+ import { createHash, randomBytes } from "node:crypto";
2
+ /** 48 bytes → 64 base64url characters, inside RFC 7636's 43-128 range. */
3
+ const VERIFIER_BYTES = 48;
4
+ export function pkceChallenge(verifier) {
5
+ return createHash("sha256").update(verifier, "ascii").digest("base64url");
6
+ }
7
+ export function createPkcePair(random = randomBytes) {
8
+ const verifier = random(VERIFIER_BYTES).toString("base64url");
9
+ return { verifier, challenge: pkceChallenge(verifier) };
10
+ }
11
+ //# sourceMappingURL=pkce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.js","sourceRoot":"","sources":["../../../../src/core/mcp/oauth/pkce.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAatD,4EAA0E;AAC1E,MAAM,cAAc,GAAG,EAAE,CAAC;AAE1B,MAAM,UAAU,aAAa,CAAC,QAAgB,EAAU;IACvD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;AAAA,CAC1E;AAED,MAAM,UAAU,cAAc,CAAC,MAAM,GAA6B,WAAW,EAAY;IACxF,MAAM,QAAQ,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC9D,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC;AAAA,CACxD","sourcesContent":["import { createHash, randomBytes } from \"node:crypto\";\n\n/**\n * PKCE (RFC 7636), the S256 method only. Every MCP authorization server is required\n * to support it, and a verifier that never travels with the code is the only thing\n * standing between a callback URL and a token, so there is no plain fallback here.\n */\n\nexport interface PkcePair {\n\tverifier: string;\n\tchallenge: string;\n}\n\n/** 48 bytes → 64 base64url characters, inside RFC 7636's 43-128 range. */\nconst VERIFIER_BYTES = 48;\n\nexport function pkceChallenge(verifier: string): string {\n\treturn createHash(\"sha256\").update(verifier, \"ascii\").digest(\"base64url\");\n}\n\nexport function createPkcePair(random: (size: number) => Buffer = randomBytes): PkcePair {\n\tconst verifier = random(VERIFIER_BYTES).toString(\"base64url\");\n\treturn { verifier, challenge: pkceChallenge(verifier) };\n}\n"]}
@@ -0,0 +1,16 @@
1
+ import { type FetchLike } from "./discover.ts";
2
+ export interface RegisteredClient {
3
+ clientId: string;
4
+ clientSecret: string | undefined;
5
+ }
6
+ /**
7
+ * RFC 7591 dynamic client registration. Public client only: the redirect lands on a
8
+ * loopback listener and there is no client secret unless the server issues one.
9
+ */
10
+ export declare function registerClient(options: {
11
+ registrationEndpoint: URL;
12
+ clientName: string;
13
+ redirectUris: string[];
14
+ fetch?: FetchLike;
15
+ }): Promise<RegisteredClient>;
16
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../../src/core/mcp/oauth/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAqB,MAAM,eAAe,CAAC;AAElE,MAAM,WAAW,gBAAgB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE;IAC7C,oBAAoB,EAAE,GAAG,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,SAAS,CAAC;CAClB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAoC5B","sourcesContent":["import { type FetchLike, oauthErrorMessage } from \"./discover.ts\";\n\nexport interface RegisteredClient {\n\tclientId: string;\n\tclientSecret: string | undefined;\n}\n\n/**\n * RFC 7591 dynamic client registration. Public client only: the redirect lands on a\n * loopback listener and there is no client secret unless the server issues one.\n */\nexport async function registerClient(options: {\n\tregistrationEndpoint: URL;\n\tclientName: string;\n\tredirectUris: string[];\n\tfetch?: FetchLike;\n}): Promise<RegisteredClient> {\n\tconst fetch = options.fetch ?? globalThis.fetch;\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(options.registrationEndpoint, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { \"content-type\": \"application/json\" },\n\t\t\tbody: JSON.stringify({\n\t\t\t\tclient_name: options.clientName,\n\t\t\t\tredirect_uris: options.redirectUris,\n\t\t\t\tgrant_types: [\"authorization_code\"],\n\t\t\t\tresponse_types: [\"code\"],\n\t\t\t\ttoken_endpoint_auth_method: \"none\",\n\t\t\t}),\n\t\t});\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`dynamic client registration unreachable at ${options.registrationEndpoint}: ${oauthErrorMessage(error)}`,\n\t\t);\n\t}\n\tlet parsed: Record<string, unknown> = {};\n\ttry {\n\t\tconst value: unknown = await response.json();\n\t\tif (typeof value === \"object\" && value !== null) parsed = value as Record<string, unknown>;\n\t} catch {\n\t\t// Falls through to the failure below.\n\t}\n\tif (!response.ok || typeof parsed.client_id !== \"string\") {\n\t\tthrow new Error(\n\t\t\t`dynamic client registration failed at ${options.registrationEndpoint} (HTTP ${response.status})`,\n\t\t);\n\t}\n\treturn {\n\t\tclientId: parsed.client_id,\n\t\tclientSecret: typeof parsed.client_secret === \"string\" ? parsed.client_secret : undefined,\n\t};\n}\n"]}
@@ -0,0 +1,42 @@
1
+ import { oauthErrorMessage } from "./discover.js";
2
+ /**
3
+ * RFC 7591 dynamic client registration. Public client only: the redirect lands on a
4
+ * loopback listener and there is no client secret unless the server issues one.
5
+ */
6
+ export async function registerClient(options) {
7
+ const fetch = options.fetch ?? globalThis.fetch;
8
+ let response;
9
+ try {
10
+ response = await fetch(options.registrationEndpoint, {
11
+ method: "POST",
12
+ headers: { "content-type": "application/json" },
13
+ body: JSON.stringify({
14
+ client_name: options.clientName,
15
+ redirect_uris: options.redirectUris,
16
+ grant_types: ["authorization_code"],
17
+ response_types: ["code"],
18
+ token_endpoint_auth_method: "none",
19
+ }),
20
+ });
21
+ }
22
+ catch (error) {
23
+ throw new Error(`dynamic client registration unreachable at ${options.registrationEndpoint}: ${oauthErrorMessage(error)}`);
24
+ }
25
+ let parsed = {};
26
+ try {
27
+ const value = await response.json();
28
+ if (typeof value === "object" && value !== null)
29
+ parsed = value;
30
+ }
31
+ catch {
32
+ // Falls through to the failure below.
33
+ }
34
+ if (!response.ok || typeof parsed.client_id !== "string") {
35
+ throw new Error(`dynamic client registration failed at ${options.registrationEndpoint} (HTTP ${response.status})`);
36
+ }
37
+ return {
38
+ clientId: parsed.client_id,
39
+ clientSecret: typeof parsed.client_secret === "string" ? parsed.client_secret : undefined,
40
+ };
41
+ }
42
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../../../../src/core/mcp/oauth/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAOlE;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAKpC,EAA6B;IAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC;IAChD,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACJ,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,oBAAoB,EAAE;YACpD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACpB,WAAW,EAAE,OAAO,CAAC,UAAU;gBAC/B,aAAa,EAAE,OAAO,CAAC,YAAY;gBACnC,WAAW,EAAE,CAAC,oBAAoB,CAAC;gBACnC,cAAc,EAAE,CAAC,MAAM,CAAC;gBACxB,0BAA0B,EAAE,MAAM;aAClC,CAAC;SACF,CAAC,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACd,8CAA8C,OAAO,CAAC,oBAAoB,KAAK,iBAAiB,CAAC,KAAK,CAAC,EAAE,CACzG,CAAC;IACH,CAAC;IACD,IAAI,MAAM,GAA4B,EAAE,CAAC;IACzC,IAAI,CAAC;QACJ,MAAM,KAAK,GAAY,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC7C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;YAAE,MAAM,GAAG,KAAgC,CAAC;IAC5F,CAAC;IAAC,MAAM,CAAC;QACR,sCAAsC;IACvC,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;QAC1D,MAAM,IAAI,KAAK,CACd,yCAAyC,OAAO,CAAC,oBAAoB,UAAU,QAAQ,CAAC,MAAM,GAAG,CACjG,CAAC;IACH,CAAC;IACD,OAAO;QACN,QAAQ,EAAE,MAAM,CAAC,SAAS;QAC1B,YAAY,EAAE,OAAO,MAAM,CAAC,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS;KACzF,CAAC;AAAA,CACF","sourcesContent":["import { type FetchLike, oauthErrorMessage } from \"./discover.ts\";\n\nexport interface RegisteredClient {\n\tclientId: string;\n\tclientSecret: string | undefined;\n}\n\n/**\n * RFC 7591 dynamic client registration. Public client only: the redirect lands on a\n * loopback listener and there is no client secret unless the server issues one.\n */\nexport async function registerClient(options: {\n\tregistrationEndpoint: URL;\n\tclientName: string;\n\tredirectUris: string[];\n\tfetch?: FetchLike;\n}): Promise<RegisteredClient> {\n\tconst fetch = options.fetch ?? globalThis.fetch;\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(options.registrationEndpoint, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { \"content-type\": \"application/json\" },\n\t\t\tbody: JSON.stringify({\n\t\t\t\tclient_name: options.clientName,\n\t\t\t\tredirect_uris: options.redirectUris,\n\t\t\t\tgrant_types: [\"authorization_code\"],\n\t\t\t\tresponse_types: [\"code\"],\n\t\t\t\ttoken_endpoint_auth_method: \"none\",\n\t\t\t}),\n\t\t});\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`dynamic client registration unreachable at ${options.registrationEndpoint}: ${oauthErrorMessage(error)}`,\n\t\t);\n\t}\n\tlet parsed: Record<string, unknown> = {};\n\ttry {\n\t\tconst value: unknown = await response.json();\n\t\tif (typeof value === \"object\" && value !== null) parsed = value as Record<string, unknown>;\n\t} catch {\n\t\t// Falls through to the failure below.\n\t}\n\tif (!response.ok || typeof parsed.client_id !== \"string\") {\n\t\tthrow new Error(\n\t\t\t`dynamic client registration failed at ${options.registrationEndpoint} (HTTP ${response.status})`,\n\t\t);\n\t}\n\treturn {\n\t\tclientId: parsed.client_id,\n\t\tclientSecret: typeof parsed.client_secret === \"string\" ? parsed.client_secret : undefined,\n\t};\n}\n"]}
@@ -0,0 +1,33 @@
1
+ import { type FetchLike } from "./discover.ts";
2
+ export declare class TokenEndpointError extends Error {
3
+ /** The OAuth `error` code from the response body, when the server sent one (e.g. invalid_grant). */
4
+ code: string | undefined;
5
+ constructor(message: string, code: string | undefined);
6
+ }
7
+ /** The endpoint could not be reached at all — a path problem, not a server refusal. */
8
+ export declare class TokenEndpointUnreachableError extends TokenEndpointError {
9
+ }
10
+ export interface TokenResponse {
11
+ accessToken: string;
12
+ /** Absent when the server did not rotate; callers keep their previous refresh token then. */
13
+ refreshToken: string | undefined;
14
+ expiresInSeconds: number;
15
+ }
16
+ interface TokenEndpointOptions {
17
+ tokenEndpoint: URL;
18
+ clientId: string;
19
+ clientSecret?: string;
20
+ /** The MCP resource indicator; pins the issued token to this server (RFC 8707). */
21
+ resource?: string;
22
+ fetch?: FetchLike;
23
+ }
24
+ export declare function exchangeAuthorizationCode(options: TokenEndpointOptions & {
25
+ code: string;
26
+ verifier: string;
27
+ redirectUri: string;
28
+ }): Promise<TokenResponse>;
29
+ export declare function refreshAccessToken(options: TokenEndpointOptions & {
30
+ refreshToken: string;
31
+ }): Promise<TokenResponse>;
32
+ export {};
33
+ //# sourceMappingURL=token-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-client.d.ts","sourceRoot":"","sources":["../../../../src/core/mcp/oauth/token-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAqB,MAAM,eAAe,CAAC;AAElE,qBAAa,kBAAmB,SAAQ,KAAK;IAC5C,oGAAoG;IACpG,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAEzB,YAAY,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAGpD;CACD;AAED,yFAAuF;AACvF,qBAAa,6BAA8B,SAAQ,kBAAkB;CAAG;AAExE,MAAM,WAAW,aAAa;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,6FAA6F;IAC7F,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,gBAAgB,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,oBAAoB;IAC7B,aAAa,EAAE,GAAG,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mFAAmF;IACnF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,SAAS,CAAC;CAClB;AA4CD,wBAAgB,yBAAyB,CACxC,OAAO,EAAE,oBAAoB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACrF,OAAO,CAAC,aAAa,CAAC,CAOxB;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,oBAAoB,GAAG;IAAE,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAEnH","sourcesContent":["import { type FetchLike, oauthErrorMessage } from \"./discover.ts\";\n\nexport class TokenEndpointError extends Error {\n\t/** The OAuth `error` code from the response body, when the server sent one (e.g. invalid_grant). */\n\tcode: string | undefined;\n\n\tconstructor(message: string, code: string | undefined) {\n\t\tsuper(message);\n\t\tthis.code = code;\n\t}\n}\n\n/** The endpoint could not be reached at all — a path problem, not a server refusal. */\nexport class TokenEndpointUnreachableError extends TokenEndpointError {}\n\nexport interface TokenResponse {\n\taccessToken: string;\n\t/** Absent when the server did not rotate; callers keep their previous refresh token then. */\n\trefreshToken: string | undefined;\n\texpiresInSeconds: number;\n}\n\ninterface TokenEndpointOptions {\n\ttokenEndpoint: URL;\n\tclientId: string;\n\tclientSecret?: string;\n\t/** The MCP resource indicator; pins the issued token to this server (RFC 8707). */\n\tresource?: string;\n\tfetch?: FetchLike;\n}\n\nasync function postTokenForm(options: TokenEndpointOptions, grant: Record<string, string>): Promise<TokenResponse> {\n\tconst fetch = options.fetch ?? globalThis.fetch;\n\tconst body = new URLSearchParams({ client_id: options.clientId, ...grant });\n\tif (options.clientSecret) body.set(\"client_secret\", options.clientSecret);\n\tif (options.resource) body.set(\"resource\", options.resource);\n\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(options.tokenEndpoint, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { \"content-type\": \"application/x-www-form-urlencoded\" },\n\t\t\tbody,\n\t\t});\n\t} catch (error) {\n\t\tthrow new TokenEndpointUnreachableError(\n\t\t\t`token endpoint unreachable at ${options.tokenEndpoint}: ${oauthErrorMessage(error)}`,\n\t\t\tundefined,\n\t\t);\n\t}\n\n\tconst text = await response.text();\n\tlet parsed: Record<string, unknown> = {};\n\ttry {\n\t\tconst value: unknown = JSON.parse(text);\n\t\tif (typeof value === \"object\" && value !== null) parsed = value as Record<string, unknown>;\n\t} catch {\n\t\t// A non-JSON error body still lands in the status branch below.\n\t}\n\tif (!response.ok) {\n\t\tconst code = typeof parsed.error === \"string\" ? parsed.error : undefined;\n\t\tthrow new TokenEndpointError(`token endpoint answered HTTP ${response.status}${code ? ` (${code})` : \"\"}`, code);\n\t}\n\tif (typeof parsed.access_token !== \"string\" || typeof parsed.expires_in !== \"number\") {\n\t\tthrow new TokenEndpointError(\"token endpoint response is missing access_token or expires_in\", undefined);\n\t}\n\treturn {\n\t\taccessToken: parsed.access_token,\n\t\trefreshToken: typeof parsed.refresh_token === \"string\" ? parsed.refresh_token : undefined,\n\t\texpiresInSeconds: parsed.expires_in,\n\t};\n}\n\nexport function exchangeAuthorizationCode(\n\toptions: TokenEndpointOptions & { code: string; verifier: string; redirectUri: string },\n): Promise<TokenResponse> {\n\treturn postTokenForm(options, {\n\t\tgrant_type: \"authorization_code\",\n\t\tcode: options.code,\n\t\tcode_verifier: options.verifier,\n\t\tredirect_uri: options.redirectUri,\n\t});\n}\n\nexport function refreshAccessToken(options: TokenEndpointOptions & { refreshToken: string }): Promise<TokenResponse> {\n\treturn postTokenForm(options, { grant_type: \"refresh_token\", refresh_token: options.refreshToken });\n}\n"]}
@@ -0,0 +1,65 @@
1
+ import { oauthErrorMessage } from "./discover.js";
2
+ export class TokenEndpointError extends Error {
3
+ /** The OAuth `error` code from the response body, when the server sent one (e.g. invalid_grant). */
4
+ code;
5
+ constructor(message, code) {
6
+ super(message);
7
+ this.code = code;
8
+ }
9
+ }
10
+ /** The endpoint could not be reached at all — a path problem, not a server refusal. */
11
+ export class TokenEndpointUnreachableError extends TokenEndpointError {
12
+ }
13
+ async function postTokenForm(options, grant) {
14
+ const fetch = options.fetch ?? globalThis.fetch;
15
+ const body = new URLSearchParams({ client_id: options.clientId, ...grant });
16
+ if (options.clientSecret)
17
+ body.set("client_secret", options.clientSecret);
18
+ if (options.resource)
19
+ body.set("resource", options.resource);
20
+ let response;
21
+ try {
22
+ response = await fetch(options.tokenEndpoint, {
23
+ method: "POST",
24
+ headers: { "content-type": "application/x-www-form-urlencoded" },
25
+ body,
26
+ });
27
+ }
28
+ catch (error) {
29
+ throw new TokenEndpointUnreachableError(`token endpoint unreachable at ${options.tokenEndpoint}: ${oauthErrorMessage(error)}`, undefined);
30
+ }
31
+ const text = await response.text();
32
+ let parsed = {};
33
+ try {
34
+ const value = JSON.parse(text);
35
+ if (typeof value === "object" && value !== null)
36
+ parsed = value;
37
+ }
38
+ catch {
39
+ // A non-JSON error body still lands in the status branch below.
40
+ }
41
+ if (!response.ok) {
42
+ const code = typeof parsed.error === "string" ? parsed.error : undefined;
43
+ throw new TokenEndpointError(`token endpoint answered HTTP ${response.status}${code ? ` (${code})` : ""}`, code);
44
+ }
45
+ if (typeof parsed.access_token !== "string" || typeof parsed.expires_in !== "number") {
46
+ throw new TokenEndpointError("token endpoint response is missing access_token or expires_in", undefined);
47
+ }
48
+ return {
49
+ accessToken: parsed.access_token,
50
+ refreshToken: typeof parsed.refresh_token === "string" ? parsed.refresh_token : undefined,
51
+ expiresInSeconds: parsed.expires_in,
52
+ };
53
+ }
54
+ export function exchangeAuthorizationCode(options) {
55
+ return postTokenForm(options, {
56
+ grant_type: "authorization_code",
57
+ code: options.code,
58
+ code_verifier: options.verifier,
59
+ redirect_uri: options.redirectUri,
60
+ });
61
+ }
62
+ export function refreshAccessToken(options) {
63
+ return postTokenForm(options, { grant_type: "refresh_token", refresh_token: options.refreshToken });
64
+ }
65
+ //# sourceMappingURL=token-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-client.js","sourceRoot":"","sources":["../../../../src/core/mcp/oauth/token-client.ts"],"names":[],"mappings":"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","sourcesContent":["import { type FetchLike, oauthErrorMessage } from \"./discover.ts\";\n\nexport class TokenEndpointError extends Error {\n\t/** The OAuth `error` code from the response body, when the server sent one (e.g. invalid_grant). */\n\tcode: string | undefined;\n\n\tconstructor(message: string, code: string | undefined) {\n\t\tsuper(message);\n\t\tthis.code = code;\n\t}\n}\n\n/** The endpoint could not be reached at all — a path problem, not a server refusal. */\nexport class TokenEndpointUnreachableError extends TokenEndpointError {}\n\nexport interface TokenResponse {\n\taccessToken: string;\n\t/** Absent when the server did not rotate; callers keep their previous refresh token then. */\n\trefreshToken: string | undefined;\n\texpiresInSeconds: number;\n}\n\ninterface TokenEndpointOptions {\n\ttokenEndpoint: URL;\n\tclientId: string;\n\tclientSecret?: string;\n\t/** The MCP resource indicator; pins the issued token to this server (RFC 8707). */\n\tresource?: string;\n\tfetch?: FetchLike;\n}\n\nasync function postTokenForm(options: TokenEndpointOptions, grant: Record<string, string>): Promise<TokenResponse> {\n\tconst fetch = options.fetch ?? globalThis.fetch;\n\tconst body = new URLSearchParams({ client_id: options.clientId, ...grant });\n\tif (options.clientSecret) body.set(\"client_secret\", options.clientSecret);\n\tif (options.resource) body.set(\"resource\", options.resource);\n\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(options.tokenEndpoint, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { \"content-type\": \"application/x-www-form-urlencoded\" },\n\t\t\tbody,\n\t\t});\n\t} catch (error) {\n\t\tthrow new TokenEndpointUnreachableError(\n\t\t\t`token endpoint unreachable at ${options.tokenEndpoint}: ${oauthErrorMessage(error)}`,\n\t\t\tundefined,\n\t\t);\n\t}\n\n\tconst text = await response.text();\n\tlet parsed: Record<string, unknown> = {};\n\ttry {\n\t\tconst value: unknown = JSON.parse(text);\n\t\tif (typeof value === \"object\" && value !== null) parsed = value as Record<string, unknown>;\n\t} catch {\n\t\t// A non-JSON error body still lands in the status branch below.\n\t}\n\tif (!response.ok) {\n\t\tconst code = typeof parsed.error === \"string\" ? parsed.error : undefined;\n\t\tthrow new TokenEndpointError(`token endpoint answered HTTP ${response.status}${code ? ` (${code})` : \"\"}`, code);\n\t}\n\tif (typeof parsed.access_token !== \"string\" || typeof parsed.expires_in !== \"number\") {\n\t\tthrow new TokenEndpointError(\"token endpoint response is missing access_token or expires_in\", undefined);\n\t}\n\treturn {\n\t\taccessToken: parsed.access_token,\n\t\trefreshToken: typeof parsed.refresh_token === \"string\" ? parsed.refresh_token : undefined,\n\t\texpiresInSeconds: parsed.expires_in,\n\t};\n}\n\nexport function exchangeAuthorizationCode(\n\toptions: TokenEndpointOptions & { code: string; verifier: string; redirectUri: string },\n): Promise<TokenResponse> {\n\treturn postTokenForm(options, {\n\t\tgrant_type: \"authorization_code\",\n\t\tcode: options.code,\n\t\tcode_verifier: options.verifier,\n\t\tredirect_uri: options.redirectUri,\n\t});\n}\n\nexport function refreshAccessToken(options: TokenEndpointOptions & { refreshToken: string }): Promise<TokenResponse> {\n\treturn postTokenForm(options, { grant_type: \"refresh_token\", refresh_token: options.refreshToken });\n}\n"]}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Assembles the MCP subsystem for one session, or returns undefined when nothing is
3
+ * configured.
4
+ *
5
+ * The undefined case is the point. A session with no `.mcp.json` builds no cache, no
6
+ * manager, and no tool, so its registry and static prompt prefix are identical to a
7
+ * build from before this subsystem existed.
8
+ */
9
+ import type { McpToolOptions } from "./mcp-tool.ts";
10
+ import type { McpConfigDiagnostic, McpConnector } from "./types.ts";
11
+ export interface McpRuntime extends McpToolOptions {
12
+ diagnostics: readonly McpConfigDiagnostic[];
13
+ /** Connect `eager` servers and cache their tools, so they are discoverable cold. */
14
+ warm(): Promise<void>;
15
+ close(): Promise<void>;
16
+ }
17
+ export declare function createMcpRuntime(cwd: string, connector?: McpConnector, options?: {
18
+ projectTrusted?: boolean;
19
+ }): McpRuntime | undefined;
20
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/core/mcp/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEpE,MAAM,WAAW,UAAW,SAAQ,cAAc;IACjD,WAAW,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC5C,oFAAoF;IACpF,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,wBAAgB,gBAAgB,CAC/B,GAAG,EAAE,MAAM,EACX,SAAS,GAAE,YAA+B,EAC1C,OAAO,GAAE;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,GACxC,UAAU,GAAG,SAAS,CAwBxB","sourcesContent":["/**\n * Assembles the MCP subsystem for one session, or returns undefined when nothing is\n * configured.\n *\n * The undefined case is the point. A session with no `.mcp.json` builds no cache, no\n * manager, and no tool, so its registry and static prompt prefix are identical to a\n * build from before this subsystem existed.\n */\n\nimport { join } from \"node:path\";\nimport { loadMcpConfig, PROJECT_CONFIG_FILENAME } from \"./config.ts\";\nimport { connectMcpServer } from \"./connector.ts\";\nimport type { McpToolOptions } from \"./mcp-tool.ts\";\nimport { McpMetadataCache } from \"./metadata-cache.ts\";\nimport { McpServerManager } from \"./server-manager.ts\";\nimport type { McpConfigDiagnostic, McpConnector } from \"./types.ts\";\n\nexport interface McpRuntime extends McpToolOptions {\n\tdiagnostics: readonly McpConfigDiagnostic[];\n\t/** Connect `eager` servers and cache their tools, so they are discoverable cold. */\n\twarm(): Promise<void>;\n\tclose(): Promise<void>;\n}\n\nexport function createMcpRuntime(\n\tcwd: string,\n\tconnector: McpConnector = connectMcpServer,\n\toptions: { projectTrusted?: boolean } = {},\n): McpRuntime | undefined {\n\tconst { servers, diagnostics } = loadMcpConfig({\n\t\tprojectPath: options.projectTrusted === false ? undefined : join(cwd, PROJECT_CONFIG_FILENAME),\n\t});\n\tif (servers.size === 0) return undefined;\n\n\tconst cache = new McpMetadataCache();\n\t// A server removed from config stops appearing in search immediately, rather than\n\t// lingering until something happens to overwrite its cache entry.\n\tcache.prune([...servers.values()]);\n\n\tconst manager = new McpServerManager({ servers, connector });\n\n\treturn {\n\t\tservers,\n\t\tcache,\n\t\tmanager,\n\t\tdiagnostics,\n\t\twarm: async () => {\n\t\t\tawait manager.warmEagerServers((server, tools) => cache.set(server, tools));\n\t\t\tcache.save();\n\t\t},\n\t\tclose: () => manager.closeAll(),\n\t};\n}\n"]}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Assembles the MCP subsystem for one session, or returns undefined when nothing is
3
+ * configured.
4
+ *
5
+ * The undefined case is the point. A session with no `.mcp.json` builds no cache, no
6
+ * manager, and no tool, so its registry and static prompt prefix are identical to a
7
+ * build from before this subsystem existed.
8
+ */
9
+ import { join } from "node:path";
10
+ import { loadMcpConfig, PROJECT_CONFIG_FILENAME } from "./config.js";
11
+ import { connectMcpServer } from "./connector.js";
12
+ import { McpMetadataCache } from "./metadata-cache.js";
13
+ import { McpServerManager } from "./server-manager.js";
14
+ export function createMcpRuntime(cwd, connector = connectMcpServer, options = {}) {
15
+ const { servers, diagnostics } = loadMcpConfig({
16
+ projectPath: options.projectTrusted === false ? undefined : join(cwd, PROJECT_CONFIG_FILENAME),
17
+ });
18
+ if (servers.size === 0)
19
+ return undefined;
20
+ const cache = new McpMetadataCache();
21
+ // A server removed from config stops appearing in search immediately, rather than
22
+ // lingering until something happens to overwrite its cache entry.
23
+ cache.prune([...servers.values()]);
24
+ const manager = new McpServerManager({ servers, connector });
25
+ return {
26
+ servers,
27
+ cache,
28
+ manager,
29
+ diagnostics,
30
+ warm: async () => {
31
+ await manager.warmEagerServers((server, tools) => cache.set(server, tools));
32
+ cache.save();
33
+ },
34
+ close: () => manager.closeAll(),
35
+ };
36
+ }
37
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/core/mcp/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAUvD,MAAM,UAAU,gBAAgB,CAC/B,GAAW,EACX,SAAS,GAAiB,gBAAgB,EAC1C,OAAO,GAAiC,EAAE,EACjB;IACzB,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,aAAa,CAAC;QAC9C,WAAW,EAAE,OAAO,CAAC,cAAc,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,uBAAuB,CAAC;KAC9F,CAAC,CAAC;IACH,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAEzC,MAAM,KAAK,GAAG,IAAI,gBAAgB,EAAE,CAAC;IACrC,kFAAkF;IAClF,kEAAkE;IAClE,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAEnC,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;IAE7D,OAAO;QACN,OAAO;QACP,KAAK;QACL,OAAO;QACP,WAAW;QACX,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YACjB,MAAM,OAAO,CAAC,gBAAgB,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;YAC5E,KAAK,CAAC,IAAI,EAAE,CAAC;QAAA,CACb;QACD,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE;KAC/B,CAAC;AAAA,CACF","sourcesContent":["/**\n * Assembles the MCP subsystem for one session, or returns undefined when nothing is\n * configured.\n *\n * The undefined case is the point. A session with no `.mcp.json` builds no cache, no\n * manager, and no tool, so its registry and static prompt prefix are identical to a\n * build from before this subsystem existed.\n */\n\nimport { join } from \"node:path\";\nimport { loadMcpConfig, PROJECT_CONFIG_FILENAME } from \"./config.ts\";\nimport { connectMcpServer } from \"./connector.ts\";\nimport type { McpToolOptions } from \"./mcp-tool.ts\";\nimport { McpMetadataCache } from \"./metadata-cache.ts\";\nimport { McpServerManager } from \"./server-manager.ts\";\nimport type { McpConfigDiagnostic, McpConnector } from \"./types.ts\";\n\nexport interface McpRuntime extends McpToolOptions {\n\tdiagnostics: readonly McpConfigDiagnostic[];\n\t/** Connect `eager` servers and cache their tools, so they are discoverable cold. */\n\twarm(): Promise<void>;\n\tclose(): Promise<void>;\n}\n\nexport function createMcpRuntime(\n\tcwd: string,\n\tconnector: McpConnector = connectMcpServer,\n\toptions: { projectTrusted?: boolean } = {},\n): McpRuntime | undefined {\n\tconst { servers, diagnostics } = loadMcpConfig({\n\t\tprojectPath: options.projectTrusted === false ? undefined : join(cwd, PROJECT_CONFIG_FILENAME),\n\t});\n\tif (servers.size === 0) return undefined;\n\n\tconst cache = new McpMetadataCache();\n\t// A server removed from config stops appearing in search immediately, rather than\n\t// lingering until something happens to overwrite its cache entry.\n\tcache.prune([...servers.values()]);\n\n\tconst manager = new McpServerManager({ servers, connector });\n\n\treturn {\n\t\tservers,\n\t\tcache,\n\t\tmanager,\n\t\tdiagnostics,\n\t\twarm: async () => {\n\t\t\tawait manager.warmEagerServers((server, tools) => cache.set(server, tools));\n\t\t\tcache.save();\n\t\t},\n\t\tclose: () => manager.closeAll(),\n\t};\n}\n"]}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The `mcp` tool's parameter schema, and the single source of its param type.
3
+ *
4
+ * It lives apart from the tool itself so the contract (`contract.ts`) can type its
5
+ * permission grammar against the same shape without importing the tool, which would
6
+ * be a cycle: the tool needs the contract.
7
+ */
8
+ import { type Static, Type } from "typebox";
9
+ export declare const mcpToolSchema: Type.TObject<{
10
+ search: Type.TOptional<Type.TString>;
11
+ server: Type.TOptional<Type.TString>;
12
+ describe: Type.TOptional<Type.TString>;
13
+ tool: Type.TOptional<Type.TString>;
14
+ args: Type.TOptional<Type.TUnknown>;
15
+ }>;
16
+ export type McpToolParams = Static<typeof mcpToolSchema>;
17
+ export interface McpToolDetails {
18
+ action: "search" | "describe" | "list" | "call";
19
+ server: string | undefined;
20
+ tool: string | undefined;
21
+ }
22
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/core/mcp/schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,eAAO,MAAM,aAAa;;;;;;EAmBxB,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAEzD,MAAM,WAAW,cAAc;IAC9B,MAAM,EAAE,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;IAChD,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;CACzB","sourcesContent":["/**\n * The `mcp` tool's parameter schema, and the single source of its param type.\n *\n * It lives apart from the tool itself so the contract (`contract.ts`) can type its\n * permission grammar against the same shape without importing the tool, which would\n * be a cycle: the tool needs the contract.\n */\n\nimport { type Static, Type } from \"typebox\";\n\nexport const mcpToolSchema = Type.Object({\n\tsearch: Type.Optional(\n\t\tType.String({\n\t\t\tdescription:\n\t\t\t\t\"Find tools across configured MCP servers by keyword. Reads a local cache, so it works without starting a server.\",\n\t\t}),\n\t),\n\tserver: Type.Optional(\n\t\tType.String({ description: \"Restrict a search to one server, or list that server's tools when used alone.\" }),\n\t),\n\tdescribe: Type.Optional(\n\t\tType.String({ description: 'Show one tool\\'s full input schema. Qualified as \"<server>:<tool>\".' }),\n\t),\n\ttool: Type.Optional(\n\t\tType.String({\n\t\t\tdescription: 'The tool to call, qualified as \"<server>:<tool>\". Requires the server to be reachable.',\n\t\t}),\n\t),\n\targs: Type.Optional(Type.Unknown({ description: \"Arguments for the called tool, matching its input schema.\" })),\n});\n\nexport type McpToolParams = Static<typeof mcpToolSchema>;\n\nexport interface McpToolDetails {\n\taction: \"search\" | \"describe\" | \"list\" | \"call\";\n\tserver: string | undefined;\n\ttool: string | undefined;\n}\n"]}