@chances-ai/engine 24.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (389) hide show
  1. package/dist/agents/discover.d.ts +30 -0
  2. package/dist/agents/discover.d.ts.map +1 -0
  3. package/dist/agents/discover.js +183 -0
  4. package/dist/agents/discover.js.map +1 -0
  5. package/dist/agents/index.d.ts +20 -0
  6. package/dist/agents/index.d.ts.map +1 -0
  7. package/dist/agents/index.js +52 -0
  8. package/dist/agents/index.js.map +1 -0
  9. package/dist/agents/parse.d.ts +61 -0
  10. package/dist/agents/parse.d.ts.map +1 -0
  11. package/dist/agents/parse.js +527 -0
  12. package/dist/agents/parse.js.map +1 -0
  13. package/dist/agents/types.d.ts +52 -0
  14. package/dist/agents/types.d.ts.map +1 -0
  15. package/dist/agents/types.js +8 -0
  16. package/dist/agents/types.js.map +1 -0
  17. package/dist/ai/adapters/ai-sdk-stream.d.ts +19 -0
  18. package/dist/ai/adapters/ai-sdk-stream.d.ts.map +1 -0
  19. package/dist/ai/adapters/ai-sdk-stream.js +125 -0
  20. package/dist/ai/adapters/ai-sdk-stream.js.map +1 -0
  21. package/dist/ai/adapters/ai-sdk.d.ts +56 -0
  22. package/dist/ai/adapters/ai-sdk.d.ts.map +1 -0
  23. package/dist/ai/adapters/ai-sdk.js +112 -0
  24. package/dist/ai/adapters/ai-sdk.js.map +1 -0
  25. package/dist/ai/adapters/mock.d.ts +13 -0
  26. package/dist/ai/adapters/mock.d.ts.map +1 -0
  27. package/dist/ai/adapters/mock.js +54 -0
  28. package/dist/ai/adapters/mock.js.map +1 -0
  29. package/dist/ai/adapters/openai-compatible.d.ts +23 -0
  30. package/dist/ai/adapters/openai-compatible.d.ts.map +1 -0
  31. package/dist/ai/adapters/openai-compatible.js +45 -0
  32. package/dist/ai/adapters/openai-compatible.js.map +1 -0
  33. package/dist/ai/cost.d.ts +3 -0
  34. package/dist/ai/cost.d.ts.map +1 -0
  35. package/dist/ai/cost.js +5 -0
  36. package/dist/ai/cost.js.map +1 -0
  37. package/dist/ai/index.d.ts +12 -0
  38. package/dist/ai/index.d.ts.map +1 -0
  39. package/dist/ai/index.js +11 -0
  40. package/dist/ai/index.js.map +1 -0
  41. package/dist/ai/known-models.d.ts +20 -0
  42. package/dist/ai/known-models.d.ts.map +1 -0
  43. package/dist/ai/known-models.js +129 -0
  44. package/dist/ai/known-models.js.map +1 -0
  45. package/dist/ai/registry.d.ts +12 -0
  46. package/dist/ai/registry.d.ts.map +1 -0
  47. package/dist/ai/registry.js +24 -0
  48. package/dist/ai/registry.js.map +1 -0
  49. package/dist/ai/retry.d.ts +11 -0
  50. package/dist/ai/retry.d.ts.map +1 -0
  51. package/dist/ai/retry.js +14 -0
  52. package/dist/ai/retry.js.map +1 -0
  53. package/dist/ai/router.d.ts +25 -0
  54. package/dist/ai/router.d.ts.map +1 -0
  55. package/dist/ai/router.js +36 -0
  56. package/dist/ai/router.js.map +1 -0
  57. package/dist/ai/setup.d.ts +23 -0
  58. package/dist/ai/setup.d.ts.map +1 -0
  59. package/dist/ai/setup.js +47 -0
  60. package/dist/ai/setup.js.map +1 -0
  61. package/dist/ai/summarizer.d.ts +24 -0
  62. package/dist/ai/summarizer.d.ts.map +1 -0
  63. package/dist/ai/summarizer.js +56 -0
  64. package/dist/ai/summarizer.js.map +1 -0
  65. package/dist/ai/types.d.ts +83 -0
  66. package/dist/ai/types.d.ts.map +1 -0
  67. package/dist/ai/types.js +2 -0
  68. package/dist/ai/types.js.map +1 -0
  69. package/dist/core/compaction/circuit-breaker.d.ts +32 -0
  70. package/dist/core/compaction/circuit-breaker.d.ts.map +1 -0
  71. package/dist/core/compaction/circuit-breaker.js +42 -0
  72. package/dist/core/compaction/circuit-breaker.js.map +1 -0
  73. package/dist/core/compaction/compactor.d.ts +75 -0
  74. package/dist/core/compaction/compactor.d.ts.map +1 -0
  75. package/dist/core/compaction/compactor.js +261 -0
  76. package/dist/core/compaction/compactor.js.map +1 -0
  77. package/dist/core/compaction/estimate.d.ts +39 -0
  78. package/dist/core/compaction/estimate.d.ts.map +1 -0
  79. package/dist/core/compaction/estimate.js +74 -0
  80. package/dist/core/compaction/estimate.js.map +1 -0
  81. package/dist/core/compaction/index.d.ts +5 -0
  82. package/dist/core/compaction/index.d.ts.map +1 -0
  83. package/dist/core/compaction/index.js +5 -0
  84. package/dist/core/compaction/index.js.map +1 -0
  85. package/dist/core/compaction/prune.d.ts +43 -0
  86. package/dist/core/compaction/prune.d.ts.map +1 -0
  87. package/dist/core/compaction/prune.js +51 -0
  88. package/dist/core/compaction/prune.js.map +1 -0
  89. package/dist/core/engine.d.ts +268 -0
  90. package/dist/core/engine.d.ts.map +1 -0
  91. package/dist/core/engine.js +767 -0
  92. package/dist/core/engine.js.map +1 -0
  93. package/dist/core/index.d.ts +6 -0
  94. package/dist/core/index.d.ts.map +1 -0
  95. package/dist/core/index.js +6 -0
  96. package/dist/core/index.js.map +1 -0
  97. package/dist/core/task-tool.d.ts +175 -0
  98. package/dist/core/task-tool.d.ts.map +1 -0
  99. package/dist/core/task-tool.js +901 -0
  100. package/dist/core/task-tool.js.map +1 -0
  101. package/dist/core/workspace-query.d.ts +83 -0
  102. package/dist/core/workspace-query.d.ts.map +1 -0
  103. package/dist/core/workspace-query.js +217 -0
  104. package/dist/core/workspace-query.js.map +1 -0
  105. package/dist/core/worktree/active-marker.d.ts +31 -0
  106. package/dist/core/worktree/active-marker.d.ts.map +1 -0
  107. package/dist/core/worktree/active-marker.js +109 -0
  108. package/dist/core/worktree/active-marker.js.map +1 -0
  109. package/dist/core/worktree/create.d.ts +40 -0
  110. package/dist/core/worktree/create.d.ts.map +1 -0
  111. package/dist/core/worktree/create.js +121 -0
  112. package/dist/core/worktree/create.js.map +1 -0
  113. package/dist/core/worktree/errors.d.ts +7 -0
  114. package/dist/core/worktree/errors.d.ts.map +1 -0
  115. package/dist/core/worktree/errors.js +11 -0
  116. package/dist/core/worktree/errors.js.map +1 -0
  117. package/dist/core/worktree/gc.d.ts +39 -0
  118. package/dist/core/worktree/gc.d.ts.map +1 -0
  119. package/dist/core/worktree/gc.js +146 -0
  120. package/dist/core/worktree/gc.js.map +1 -0
  121. package/dist/core/worktree/git.d.ts +53 -0
  122. package/dist/core/worktree/git.d.ts.map +1 -0
  123. package/dist/core/worktree/git.js +166 -0
  124. package/dist/core/worktree/git.js.map +1 -0
  125. package/dist/core/worktree/index.d.ts +8 -0
  126. package/dist/core/worktree/index.d.ts.map +1 -0
  127. package/dist/core/worktree/index.js +8 -0
  128. package/dist/core/worktree/index.js.map +1 -0
  129. package/dist/core/worktree/paths.d.ts +26 -0
  130. package/dist/core/worktree/paths.d.ts.map +1 -0
  131. package/dist/core/worktree/paths.js +57 -0
  132. package/dist/core/worktree/paths.js.map +1 -0
  133. package/dist/core/worktree/slug.d.ts +6 -0
  134. package/dist/core/worktree/slug.d.ts.map +1 -0
  135. package/dist/core/worktree/slug.js +21 -0
  136. package/dist/core/worktree/slug.js.map +1 -0
  137. package/dist/local-vault/file-store.d.ts +64 -0
  138. package/dist/local-vault/file-store.d.ts.map +1 -0
  139. package/dist/local-vault/file-store.js +225 -0
  140. package/dist/local-vault/file-store.js.map +1 -0
  141. package/dist/local-vault/index.d.ts +57 -0
  142. package/dist/local-vault/index.d.ts.map +1 -0
  143. package/dist/local-vault/index.js +68 -0
  144. package/dist/local-vault/index.js.map +1 -0
  145. package/dist/local-vault/keychain.d.ts +58 -0
  146. package/dist/local-vault/keychain.d.ts.map +1 -0
  147. package/dist/local-vault/keychain.js +200 -0
  148. package/dist/local-vault/keychain.js.map +1 -0
  149. package/dist/local-vault/mutex.d.ts +20 -0
  150. package/dist/local-vault/mutex.d.ts.map +1 -0
  151. package/dist/local-vault/mutex.js +44 -0
  152. package/dist/local-vault/mutex.js.map +1 -0
  153. package/dist/local-vault/passphrase.d.ts +30 -0
  154. package/dist/local-vault/passphrase.d.ts.map +1 -0
  155. package/dist/local-vault/passphrase.js +72 -0
  156. package/dist/local-vault/passphrase.js.map +1 -0
  157. package/dist/lsp/config.d.ts +34 -0
  158. package/dist/lsp/config.d.ts.map +1 -0
  159. package/dist/lsp/config.js +68 -0
  160. package/dist/lsp/config.js.map +1 -0
  161. package/dist/lsp/detect.d.ts +7 -0
  162. package/dist/lsp/detect.d.ts.map +1 -0
  163. package/dist/lsp/detect.js +78 -0
  164. package/dist/lsp/detect.js.map +1 -0
  165. package/dist/lsp/errors.d.ts +11 -0
  166. package/dist/lsp/errors.d.ts.map +1 -0
  167. package/dist/lsp/errors.js +11 -0
  168. package/dist/lsp/errors.js.map +1 -0
  169. package/dist/lsp/formatters.d.ts +147 -0
  170. package/dist/lsp/formatters.d.ts.map +1 -0
  171. package/dist/lsp/formatters.js +259 -0
  172. package/dist/lsp/formatters.js.map +1 -0
  173. package/dist/lsp/index.d.ts +31 -0
  174. package/dist/lsp/index.d.ts.map +1 -0
  175. package/dist/lsp/index.js +31 -0
  176. package/dist/lsp/index.js.map +1 -0
  177. package/dist/lsp/instance.d.ts +72 -0
  178. package/dist/lsp/instance.d.ts.map +1 -0
  179. package/dist/lsp/instance.js +489 -0
  180. package/dist/lsp/instance.js.map +1 -0
  181. package/dist/lsp/lazy-load.d.ts +27 -0
  182. package/dist/lsp/lazy-load.d.ts.map +1 -0
  183. package/dist/lsp/lazy-load.js +57 -0
  184. package/dist/lsp/lazy-load.js.map +1 -0
  185. package/dist/lsp/manager.d.ts +59 -0
  186. package/dist/lsp/manager.d.ts.map +1 -0
  187. package/dist/lsp/manager.js +242 -0
  188. package/dist/lsp/manager.js.map +1 -0
  189. package/dist/lsp/ops.d.ts +13 -0
  190. package/dist/lsp/ops.d.ts.map +1 -0
  191. package/dist/lsp/ops.js +225 -0
  192. package/dist/lsp/ops.js.map +1 -0
  193. package/dist/lsp/rpc.d.ts +47 -0
  194. package/dist/lsp/rpc.d.ts.map +1 -0
  195. package/dist/lsp/rpc.js +134 -0
  196. package/dist/lsp/rpc.js.map +1 -0
  197. package/dist/lsp/safe-uri.d.ts +18 -0
  198. package/dist/lsp/safe-uri.d.ts.map +1 -0
  199. package/dist/lsp/safe-uri.js +96 -0
  200. package/dist/lsp/safe-uri.js.map +1 -0
  201. package/dist/lsp/types.d.ts +70 -0
  202. package/dist/lsp/types.d.ts.map +1 -0
  203. package/dist/lsp/types.js +16 -0
  204. package/dist/lsp/types.js.map +1 -0
  205. package/dist/mcp/bridge.d.ts +57 -0
  206. package/dist/mcp/bridge.d.ts.map +1 -0
  207. package/dist/mcp/bridge.js +98 -0
  208. package/dist/mcp/bridge.js.map +1 -0
  209. package/dist/mcp/category.d.ts +22 -0
  210. package/dist/mcp/category.d.ts.map +1 -0
  211. package/dist/mcp/category.js +11 -0
  212. package/dist/mcp/category.js.map +1 -0
  213. package/dist/mcp/client.d.ts +228 -0
  214. package/dist/mcp/client.d.ts.map +1 -0
  215. package/dist/mcp/client.js +352 -0
  216. package/dist/mcp/client.js.map +1 -0
  217. package/dist/mcp/content.d.ts +86 -0
  218. package/dist/mcp/content.d.ts.map +1 -0
  219. package/dist/mcp/content.js +147 -0
  220. package/dist/mcp/content.js.map +1 -0
  221. package/dist/mcp/env.d.ts +19 -0
  222. package/dist/mcp/env.d.ts.map +1 -0
  223. package/dist/mcp/env.js +50 -0
  224. package/dist/mcp/env.js.map +1 -0
  225. package/dist/mcp/host.d.ts +199 -0
  226. package/dist/mcp/host.d.ts.map +1 -0
  227. package/dist/mcp/host.js +530 -0
  228. package/dist/mcp/host.js.map +1 -0
  229. package/dist/mcp/index.d.ts +18 -0
  230. package/dist/mcp/index.d.ts.map +1 -0
  231. package/dist/mcp/index.js +17 -0
  232. package/dist/mcp/index.js.map +1 -0
  233. package/dist/mcp/load-mcp-host.d.ts +32 -0
  234. package/dist/mcp/load-mcp-host.d.ts.map +1 -0
  235. package/dist/mcp/load-mcp-host.js +49 -0
  236. package/dist/mcp/load-mcp-host.js.map +1 -0
  237. package/dist/mcp/oauth/callback-server.d.ts +73 -0
  238. package/dist/mcp/oauth/callback-server.d.ts.map +1 -0
  239. package/dist/mcp/oauth/callback-server.js +280 -0
  240. package/dist/mcp/oauth/callback-server.js.map +1 -0
  241. package/dist/mcp/oauth/config-hash.d.ts +24 -0
  242. package/dist/mcp/oauth/config-hash.d.ts.map +1 -0
  243. package/dist/mcp/oauth/config-hash.js +55 -0
  244. package/dist/mcp/oauth/config-hash.js.map +1 -0
  245. package/dist/mcp/oauth/error-normalize.d.ts +39 -0
  246. package/dist/mcp/oauth/error-normalize.d.ts.map +1 -0
  247. package/dist/mcp/oauth/error-normalize.js +91 -0
  248. package/dist/mcp/oauth/error-normalize.js.map +1 -0
  249. package/dist/mcp/oauth/provider.d.ts +190 -0
  250. package/dist/mcp/oauth/provider.d.ts.map +1 -0
  251. package/dist/mcp/oauth/provider.js +305 -0
  252. package/dist/mcp/oauth/provider.js.map +1 -0
  253. package/dist/mcp/oauth/refresh-coalescer.d.ts +46 -0
  254. package/dist/mcp/oauth/refresh-coalescer.d.ts.map +1 -0
  255. package/dist/mcp/oauth/refresh-coalescer.js +77 -0
  256. package/dist/mcp/oauth/refresh-coalescer.js.map +1 -0
  257. package/dist/mcp/oauth/sdk-shapes.d.ts +77 -0
  258. package/dist/mcp/oauth/sdk-shapes.d.ts.map +1 -0
  259. package/dist/mcp/oauth/sdk-shapes.js +21 -0
  260. package/dist/mcp/oauth/sdk-shapes.js.map +1 -0
  261. package/dist/mcp/parse.d.ts +28 -0
  262. package/dist/mcp/parse.d.ts.map +1 -0
  263. package/dist/mcp/parse.js +209 -0
  264. package/dist/mcp/parse.js.map +1 -0
  265. package/dist/mcp/prompts.d.ts +31 -0
  266. package/dist/mcp/prompts.d.ts.map +1 -0
  267. package/dist/mcp/prompts.js +71 -0
  268. package/dist/mcp/prompts.js.map +1 -0
  269. package/dist/mcp/redact.d.ts +62 -0
  270. package/dist/mcp/redact.d.ts.map +1 -0
  271. package/dist/mcp/redact.js +87 -0
  272. package/dist/mcp/redact.js.map +1 -0
  273. package/dist/mcp/resources.d.ts +70 -0
  274. package/dist/mcp/resources.d.ts.map +1 -0
  275. package/dist/mcp/resources.js +170 -0
  276. package/dist/mcp/resources.js.map +1 -0
  277. package/dist/mcp/types.d.ts +123 -0
  278. package/dist/mcp/types.d.ts.map +1 -0
  279. package/dist/mcp/types.js +2 -0
  280. package/dist/mcp/types.js.map +1 -0
  281. package/dist/memory/frontmatter.d.ts +18 -0
  282. package/dist/memory/frontmatter.d.ts.map +1 -0
  283. package/dist/memory/frontmatter.js +81 -0
  284. package/dist/memory/frontmatter.js.map +1 -0
  285. package/dist/memory/index.d.ts +5 -0
  286. package/dist/memory/index.d.ts.map +1 -0
  287. package/dist/memory/index.js +5 -0
  288. package/dist/memory/index.js.map +1 -0
  289. package/dist/memory/store.d.ts +44 -0
  290. package/dist/memory/store.d.ts.map +1 -0
  291. package/dist/memory/store.js +237 -0
  292. package/dist/memory/store.js.map +1 -0
  293. package/dist/memory/tools.d.ts +11 -0
  294. package/dist/memory/tools.d.ts.map +1 -0
  295. package/dist/memory/tools.js +159 -0
  296. package/dist/memory/tools.js.map +1 -0
  297. package/dist/memory/types.d.ts +32 -0
  298. package/dist/memory/types.d.ts.map +1 -0
  299. package/dist/memory/types.js +20 -0
  300. package/dist/memory/types.js.map +1 -0
  301. package/dist/plugin-api/index.d.ts +167 -0
  302. package/dist/plugin-api/index.d.ts.map +1 -0
  303. package/dist/plugin-api/index.js +151 -0
  304. package/dist/plugin-api/index.js.map +1 -0
  305. package/dist/plugin-logger/index.d.ts +21 -0
  306. package/dist/plugin-logger/index.d.ts.map +1 -0
  307. package/dist/plugin-logger/index.js +59 -0
  308. package/dist/plugin-logger/index.js.map +1 -0
  309. package/dist/session/index.d.ts +125 -0
  310. package/dist/session/index.d.ts.map +1 -0
  311. package/dist/session/index.js +202 -0
  312. package/dist/session/index.js.map +1 -0
  313. package/dist/tools/approval.d.ts +33 -0
  314. package/dist/tools/approval.d.ts.map +1 -0
  315. package/dist/tools/approval.js +53 -0
  316. package/dist/tools/approval.js.map +1 -0
  317. package/dist/tools/builtins/_shared.d.ts +94 -0
  318. package/dist/tools/builtins/_shared.d.ts.map +1 -0
  319. package/dist/tools/builtins/_shared.js +246 -0
  320. package/dist/tools/builtins/_shared.js.map +1 -0
  321. package/dist/tools/builtins/ask-user-question.d.ts +27 -0
  322. package/dist/tools/builtins/ask-user-question.d.ts.map +1 -0
  323. package/dist/tools/builtins/ask-user-question.js +191 -0
  324. package/dist/tools/builtins/ask-user-question.js.map +1 -0
  325. package/dist/tools/builtins/bash.d.ts +3 -0
  326. package/dist/tools/builtins/bash.d.ts.map +1 -0
  327. package/dist/tools/builtins/bash.js +158 -0
  328. package/dist/tools/builtins/bash.js.map +1 -0
  329. package/dist/tools/builtins/diff.d.ts +3 -0
  330. package/dist/tools/builtins/diff.d.ts.map +1 -0
  331. package/dist/tools/builtins/diff.js +83 -0
  332. package/dist/tools/builtins/diff.js.map +1 -0
  333. package/dist/tools/builtins/edit.d.ts +3 -0
  334. package/dist/tools/builtins/edit.d.ts.map +1 -0
  335. package/dist/tools/builtins/edit.js +40 -0
  336. package/dist/tools/builtins/edit.js.map +1 -0
  337. package/dist/tools/builtins/glob.d.ts +3 -0
  338. package/dist/tools/builtins/glob.d.ts.map +1 -0
  339. package/dist/tools/builtins/glob.js +37 -0
  340. package/dist/tools/builtins/glob.js.map +1 -0
  341. package/dist/tools/builtins/grep.d.ts +3 -0
  342. package/dist/tools/builtins/grep.d.ts.map +1 -0
  343. package/dist/tools/builtins/grep.js +81 -0
  344. package/dist/tools/builtins/grep.js.map +1 -0
  345. package/dist/tools/builtins/lsp.d.ts +3 -0
  346. package/dist/tools/builtins/lsp.d.ts.map +1 -0
  347. package/dist/tools/builtins/lsp.js +102 -0
  348. package/dist/tools/builtins/lsp.js.map +1 -0
  349. package/dist/tools/builtins/pty.d.ts +64 -0
  350. package/dist/tools/builtins/pty.d.ts.map +1 -0
  351. package/dist/tools/builtins/pty.js +536 -0
  352. package/dist/tools/builtins/pty.js.map +1 -0
  353. package/dist/tools/builtins/read.d.ts +3 -0
  354. package/dist/tools/builtins/read.d.ts.map +1 -0
  355. package/dist/tools/builtins/read.js +18 -0
  356. package/dist/tools/builtins/read.js.map +1 -0
  357. package/dist/tools/builtins/web-fetch.d.ts +4 -0
  358. package/dist/tools/builtins/web-fetch.d.ts.map +1 -0
  359. package/dist/tools/builtins/web-fetch.js +353 -0
  360. package/dist/tools/builtins/web-fetch.js.map +1 -0
  361. package/dist/tools/builtins/write.d.ts +3 -0
  362. package/dist/tools/builtins/write.d.ts.map +1 -0
  363. package/dist/tools/builtins/write.js +48 -0
  364. package/dist/tools/builtins/write.js.map +1 -0
  365. package/dist/tools/builtins.d.ts +9 -0
  366. package/dist/tools/builtins.d.ts.map +1 -0
  367. package/dist/tools/builtins.js +29 -0
  368. package/dist/tools/builtins.js.map +1 -0
  369. package/dist/tools/diff.d.ts +18 -0
  370. package/dist/tools/diff.d.ts.map +1 -0
  371. package/dist/tools/diff.js +57 -0
  372. package/dist/tools/diff.js.map +1 -0
  373. package/dist/tools/index.d.ts +10 -0
  374. package/dist/tools/index.d.ts.map +1 -0
  375. package/dist/tools/index.js +9 -0
  376. package/dist/tools/index.js.map +1 -0
  377. package/dist/tools/permission.d.ts +120 -0
  378. package/dist/tools/permission.d.ts.map +1 -0
  379. package/dist/tools/permission.js +208 -0
  380. package/dist/tools/permission.js.map +1 -0
  381. package/dist/tools/registry.d.ts +12 -0
  382. package/dist/tools/registry.d.ts.map +1 -0
  383. package/dist/tools/registry.js +19 -0
  384. package/dist/tools/registry.js.map +1 -0
  385. package/dist/tools/types.d.ts +244 -0
  386. package/dist/tools/types.d.ts.map +1 -0
  387. package/dist/tools/types.js +15 -0
  388. package/dist/tools/types.js.map +1 -0
  389. package/package.json +109 -0
@@ -0,0 +1,49 @@
1
+ /**
2
+ * (3.7) `loadMcpHost({withVault})` — boot-time factory for `McpHost` that
3
+ * lazily resolves `@chances-ai/local-vault` ONLY when the caller asks for
4
+ * a vault. Keeps the cold-start budget intact when no OAuth-configured
5
+ * MCP server is present (`apps/cli/src/boot/load-runtime.ts` passes
6
+ * `withVault: needsOAuth`).
7
+ *
8
+ * **Boundary decision (codex Round-1 NICE).** `apps/cli` MUST NOT import
9
+ * `@chances-ai/local-vault` directly — the only `app → local-vault` edge
10
+ * would force dependency-cruiser to permit a new boundary rule. Routing
11
+ * vault creation through this factory keeps the graph clean: only
12
+ * `@chances-ai/mcp` reaches into the vault package.
13
+ *
14
+ * **`bun build --compile` story.** The vault specifier is COMPUTED
15
+ * (`["@chances-ai", "local-vault"].join("/")`) so Bun's bundler doesn't
16
+ * statically resolve it. A binary built without `@chances-ai/local-vault`
17
+ * in node_modules still compiles cleanly — at runtime, the dynamic
18
+ * import fails, we log a clear diagnostic, and OAuth-configured MCP
19
+ * servers individually fail with the same diagnostic (the non-OAuth
20
+ * servers keep working). § 13.4 / § 16 of `docs/3.7-design.md` cover
21
+ * the five-permutation smoke gate that pins this property.
22
+ */
23
+ import { McpHost } from "./host.js";
24
+ export async function loadMcpHost(opts) {
25
+ let vault;
26
+ if (opts.withVault) {
27
+ const loader = opts.vaultLoader ?? defaultVaultLoader;
28
+ try {
29
+ vault = await loader();
30
+ }
31
+ catch (e) {
32
+ // Vault load failure isn't fatal — non-OAuth servers keep working,
33
+ // and OAuth servers will fail individually with a clear message
34
+ // inside `startServer`. We surface the load error here so admins
35
+ // see why the vault is missing.
36
+ opts.logger.warn(`mcp: local-vault init failed (${e.message}); OAuth MCP servers will be unavailable until resolved`);
37
+ }
38
+ }
39
+ return McpHost.start({ ...opts, vault });
40
+ }
41
+ async function defaultVaultLoader() {
42
+ // (7.1 Step 5) local-vault folded into @chances-ai/engine — always present, so
43
+ // a plain relative dynamic import. Still lazy: it defers loading the optional
44
+ // @napi-rs/keyring peer (which local-vault itself resolves via a computed
45
+ // specifier in keychain.ts), so `bun build --compile` stays clean without keyring.
46
+ const mod = (await import("../local-vault/index.js"));
47
+ return mod.createLocalVault();
48
+ }
49
+ //# sourceMappingURL=load-mcp-host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-mcp-host.js","sourceRoot":"","sources":["../../src/mcp/load-mcp-host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,OAAO,EAA4C,MAAM,WAAW,CAAC;AAU9E,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAwB;IACxD,IAAI,KAAiC,CAAC;IACtC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,IAAI,kBAAkB,CAAC;QACtD,IAAI,CAAC;YACH,KAAK,GAAG,MAAM,MAAM,EAAE,CAAC;QACzB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,mEAAmE;YACnE,gEAAgE;YAChE,iEAAiE;YACjE,gCAAgC;YAChC,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,iCAAkC,CAAW,CAAC,OAAO,yDAAyD,CAC/G,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED,KAAK,UAAU,kBAAkB;IAC/B,+EAA+E;IAC/E,8EAA8E;IAC9E,0EAA0E;IAC1E,mFAAmF;IACnF,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAEnD,CAAC;IACF,OAAO,GAAG,CAAC,gBAAgB,EAAE,CAAC;AAChC,CAAC"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * (3.7) Loopback HTTP listener for the OAuth authorization-code callback.
3
+ *
4
+ * Lifecycle:
5
+ * 1. `bind({preferredPort, allowFallback})` → reserves a port,
6
+ * returns the loopback URL the caller registers as the redirect_uri.
7
+ * 2. `waitForCode({expectedState, timeoutMs, signal})` → resolves with
8
+ * the auth code when a callback arrives whose `state` matches.
9
+ * 3. `close()` → shuts down the listener. Idempotent.
10
+ *
11
+ * **(codex Round-1 MUST-FIX #2)** OAuth `state` and PKCE `code_verifier`
12
+ * are independent: `state` travels in the browser redirect and is the
13
+ * CSRF binding; `code_verifier` stays in the chances process and goes
14
+ * to the token endpoint. We accept `expectedState` per-flow; the SDK
15
+ * generates and stores the verifier separately.
16
+ *
17
+ * **(codex Round-1 MUST-FIX #3)** Manual mode reuses the same loopback
18
+ * URL as a registered redirect_uri but never binds — see `register-only`
19
+ * mode in `bind()`.
20
+ *
21
+ * **(codex Round-1 SHOULD-FIX Q8)** Response carries strict CSP +
22
+ * `X-Content-Type-Options: nosniff` so a future contributor who adds
23
+ * dynamic content can't introduce an XSS sink.
24
+ *
25
+ * **(codex Round-1 SHOULD-FIX)** Default port is OS-assigned via
26
+ * `bind(0)` — accepts any unprivileged port. Fixed 3118 fallback ONLY
27
+ * if `bind(0)` itself fails (rare). RFC 8252 §7.3.
28
+ */
29
+ export interface BindOptions {
30
+ /** Explicit port from config (`auth.callbackPort` or env override).
31
+ * When set, port-fallback is DISABLED (exact-URI-match per oh-my-pi
32
+ * commit c246d88db). */
33
+ preferredPort?: number;
34
+ /** When false, this is "register-only" mode — manual flow. We compute
35
+ * the URL but do NOT bind a listener. */
36
+ bindListener: boolean;
37
+ }
38
+ export interface WaitForCodeOptions {
39
+ /** The state value we expect to see echoed back. */
40
+ expectedState: string;
41
+ /** Timeout in ms. Default 300_000 (5 min). */
42
+ timeoutMs?: number;
43
+ /** Optional caller-provided abort signal (e.g. user Ctrl-C). */
44
+ signal?: AbortSignal;
45
+ }
46
+ export interface CallbackResult {
47
+ /** The OAuth authorization code from the callback URL. */
48
+ code: string;
49
+ }
50
+ export declare class LoopbackCallbackServer {
51
+ private server;
52
+ private resolvedPort;
53
+ private pending;
54
+ private closed;
55
+ /** Resolved redirect URL. Throws when `bind()` hasn't run. */
56
+ get redirectUrl(): URL;
57
+ bind(opts: BindOptions): Promise<URL>;
58
+ /** Bind a listener on the given port. Resolves with the actual port
59
+ * (may differ from the request when port=0). */
60
+ private bindServerOn;
61
+ waitForCode(opts: WaitForCodeOptions): Promise<CallbackResult>;
62
+ /** Parses a manually-pasted callback URL (manual mode, § 6.5).
63
+ * Validates state internally. */
64
+ parseManualCallback(pastedUrl: string, expectedState: string): CallbackResult;
65
+ close(): Promise<void>;
66
+ /** Test seam — the resolved port after bind(). Undefined before bind. */
67
+ get port(): number | undefined;
68
+ private handleRequest;
69
+ private sendSuccess;
70
+ private sendError;
71
+ private writeWithCsp;
72
+ }
73
+ //# sourceMappingURL=callback-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callback-server.d.ts","sourceRoot":"","sources":["../../../src/mcp/oauth/callback-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAOH,MAAM,WAAW,WAAW;IAC1B;;6BAEyB;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;8CAC0C;IAC1C,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,oDAAoD;IACpD,aAAa,EAAE,MAAM,CAAC;IACtB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,sBAAsB;IACjC,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,OAAO,CAED;IACd,OAAO,CAAC,MAAM,CAAS;IAEvB,8DAA8D;IAC9D,IAAI,WAAW,IAAI,GAAG,CAKrB;IAEK,IAAI,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC;IAyC3C;qDACiD;IACjD,OAAO,CAAC,YAAY;IAiBd,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,cAAc,CAAC;IAsDpE;sCACkC;IAClC,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,cAAc;IAyBvE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB5B,yEAAyE;IACzE,IAAI,IAAI,IAAI,MAAM,GAAG,SAAS,CAE7B;IAED,OAAO,CAAC,aAAa;IAyCrB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,YAAY;CASrB"}
@@ -0,0 +1,280 @@
1
+ /**
2
+ * (3.7) Loopback HTTP listener for the OAuth authorization-code callback.
3
+ *
4
+ * Lifecycle:
5
+ * 1. `bind({preferredPort, allowFallback})` → reserves a port,
6
+ * returns the loopback URL the caller registers as the redirect_uri.
7
+ * 2. `waitForCode({expectedState, timeoutMs, signal})` → resolves with
8
+ * the auth code when a callback arrives whose `state` matches.
9
+ * 3. `close()` → shuts down the listener. Idempotent.
10
+ *
11
+ * **(codex Round-1 MUST-FIX #2)** OAuth `state` and PKCE `code_verifier`
12
+ * are independent: `state` travels in the browser redirect and is the
13
+ * CSRF binding; `code_verifier` stays in the chances process and goes
14
+ * to the token endpoint. We accept `expectedState` per-flow; the SDK
15
+ * generates and stores the verifier separately.
16
+ *
17
+ * **(codex Round-1 MUST-FIX #3)** Manual mode reuses the same loopback
18
+ * URL as a registered redirect_uri but never binds — see `register-only`
19
+ * mode in `bind()`.
20
+ *
21
+ * **(codex Round-1 SHOULD-FIX Q8)** Response carries strict CSP +
22
+ * `X-Content-Type-Options: nosniff` so a future contributor who adds
23
+ * dynamic content can't introduce an XSS sink.
24
+ *
25
+ * **(codex Round-1 SHOULD-FIX)** Default port is OS-assigned via
26
+ * `bind(0)` — accepts any unprivileged port. Fixed 3118 fallback ONLY
27
+ * if `bind(0)` itself fails (rare). RFC 8252 §7.3.
28
+ */
29
+ import { createServer } from "node:http";
30
+ const FALLBACK_PORT = 3118;
31
+ const LOOPBACK_HOST = "127.0.0.1";
32
+ export class LoopbackCallbackServer {
33
+ server;
34
+ resolvedPort;
35
+ pending;
36
+ closed = false;
37
+ /** Resolved redirect URL. Throws when `bind()` hasn't run. */
38
+ get redirectUrl() {
39
+ if (this.resolvedPort === undefined) {
40
+ throw new Error("LoopbackCallbackServer: bind() not called");
41
+ }
42
+ return new URL(`http://${LOOPBACK_HOST}:${this.resolvedPort}/callback`);
43
+ }
44
+ async bind(opts) {
45
+ if (this.resolvedPort !== undefined) {
46
+ throw new Error("LoopbackCallbackServer: already bound");
47
+ }
48
+ if (opts.preferredPort !== undefined) {
49
+ // Explicit port — bind exactly or fail. No fallback.
50
+ this.resolvedPort = opts.preferredPort;
51
+ if (opts.bindListener) {
52
+ await this.bindServerOn(opts.preferredPort, /*fallbackOnFail=*/ false);
53
+ }
54
+ return this.redirectUrl;
55
+ }
56
+ // Default: bind(0) — let the OS assign an unprivileged port.
57
+ if (opts.bindListener) {
58
+ try {
59
+ const port = await this.bindServerOn(0, /*fallbackOnFail=*/ false);
60
+ this.resolvedPort = port;
61
+ }
62
+ catch (e0) {
63
+ // Rare: OS refused to assign. Try fixed 3118.
64
+ try {
65
+ await this.bindServerOn(FALLBACK_PORT, /*fallbackOnFail=*/ false);
66
+ this.resolvedPort = FALLBACK_PORT;
67
+ }
68
+ catch (e1) {
69
+ throw new Error(`LoopbackCallbackServer: could not bind any loopback port. ` +
70
+ `bind(0) failed: ${e0.message}. ` +
71
+ `Fallback ${FALLBACK_PORT} failed: ${e1.message}.`);
72
+ }
73
+ }
74
+ }
75
+ else {
76
+ // Register-only (manual mode): just pick a port without binding.
77
+ // Use fallback so the user has a stable URL to register with the
78
+ // IdP; not binding means another flow can reuse it.
79
+ this.resolvedPort = FALLBACK_PORT;
80
+ }
81
+ return this.redirectUrl;
82
+ }
83
+ /** Bind a listener on the given port. Resolves with the actual port
84
+ * (may differ from the request when port=0). */
85
+ bindServerOn(port, _fallbackOnFail) {
86
+ return new Promise((resolve, reject) => {
87
+ const server = createServer((req, res) => this.handleRequest(req, res));
88
+ server.on("error", (err) => reject(err));
89
+ server.listen(port, LOOPBACK_HOST, () => {
90
+ const addr = server.address();
91
+ if (addr === null || typeof addr === "string") {
92
+ server.close();
93
+ reject(new Error(`unexpected listen address shape: ${addr}`));
94
+ return;
95
+ }
96
+ this.server = server;
97
+ resolve(addr.port);
98
+ });
99
+ });
100
+ }
101
+ async waitForCode(opts) {
102
+ if (this.server === undefined) {
103
+ throw new Error("LoopbackCallbackServer: waitForCode requires a bound listener (manual mode uses parseManualCallback)");
104
+ }
105
+ if (this.pending) {
106
+ throw new Error("LoopbackCallbackServer: a previous waitForCode is still in flight");
107
+ }
108
+ const timeoutMs = opts.timeoutMs ?? 300_000;
109
+ return new Promise((resolve, reject) => {
110
+ this.pending = { resolve, reject, expectedState: opts.expectedState };
111
+ const timer = setTimeout(() => {
112
+ if (this.pending) {
113
+ const p = this.pending;
114
+ this.pending = undefined;
115
+ // (codex Round-2 SHOULD-FIX #4) Free the port on timeout — the
116
+ // design (§ 6.4) requires close-on-timeout, and a held-open
117
+ // listener after a 5-minute timeout would block the next
118
+ // /mcp login from binding the same port.
119
+ void this.close().catch(() => undefined);
120
+ p.reject(new Error("OAuth callback timed out — close the browser window and retry."));
121
+ }
122
+ }, timeoutMs);
123
+ // Honor abort signal — caller's Ctrl-C / `/mcp logout` etc.
124
+ const onAbort = () => {
125
+ if (this.pending) {
126
+ const p = this.pending;
127
+ this.pending = undefined;
128
+ clearTimeout(timer);
129
+ void this.close().catch(() => undefined);
130
+ p.reject(new Error("OAuth callback aborted"));
131
+ }
132
+ };
133
+ if (opts.signal) {
134
+ if (opts.signal.aborted) {
135
+ onAbort();
136
+ }
137
+ else {
138
+ opts.signal.addEventListener("abort", onAbort, { once: true });
139
+ }
140
+ }
141
+ // Wrap resolve/reject so they also clear the timer.
142
+ const origResolve = resolve;
143
+ const origReject = reject;
144
+ this.pending.resolve = (r) => {
145
+ clearTimeout(timer);
146
+ origResolve(r);
147
+ };
148
+ this.pending.reject = (e) => {
149
+ clearTimeout(timer);
150
+ origReject(e);
151
+ };
152
+ });
153
+ }
154
+ /** Parses a manually-pasted callback URL (manual mode, § 6.5).
155
+ * Validates state internally. */
156
+ parseManualCallback(pastedUrl, expectedState) {
157
+ let url;
158
+ try {
159
+ url = new URL(pastedUrl);
160
+ }
161
+ catch {
162
+ throw new Error("OAuth manual mode: pasted value is not a valid URL");
163
+ }
164
+ if (url.protocol !== "http:" || (url.hostname !== LOOPBACK_HOST && url.hostname.toLowerCase() !== "localhost" && url.hostname !== "[::1]")) {
165
+ throw new Error("OAuth manual mode: pasted URL must be the loopback redirect (http://127.0.0.1:...)");
166
+ }
167
+ const error = url.searchParams.get("error");
168
+ if (error !== null) {
169
+ const desc = url.searchParams.get("error_description") ?? "";
170
+ throw new Error(`OAuth authorization denied: ${error}${desc ? ` — ${desc}` : ""}`);
171
+ }
172
+ const code = url.searchParams.get("code");
173
+ const state = url.searchParams.get("state");
174
+ if (code === null)
175
+ throw new Error("OAuth manual mode: pasted URL is missing the 'code' query parameter");
176
+ if (state === null)
177
+ throw new Error("OAuth manual mode: pasted URL is missing the 'state' query parameter");
178
+ if (!constantTimeEqual(state, expectedState)) {
179
+ throw new Error("OAuth manual mode: state mismatch (CSRF guard) — abandoned flow or copy/paste error");
180
+ }
181
+ return { code };
182
+ }
183
+ async close() {
184
+ if (this.closed)
185
+ return;
186
+ this.closed = true;
187
+ if (this.pending) {
188
+ const p = this.pending;
189
+ this.pending = undefined;
190
+ p.reject(new Error("OAuth callback server closed"));
191
+ }
192
+ if (this.server) {
193
+ await new Promise((resolve) => {
194
+ this.server.close(() => resolve());
195
+ });
196
+ this.server = undefined;
197
+ }
198
+ }
199
+ /** Test seam — the resolved port after bind(). Undefined before bind. */
200
+ get port() {
201
+ return this.resolvedPort;
202
+ }
203
+ handleRequest(req, res) {
204
+ if (!req.url) {
205
+ this.sendError(res, 400, "Bad Request");
206
+ return;
207
+ }
208
+ const url = new URL(req.url, `http://${LOOPBACK_HOST}:${this.resolvedPort}`);
209
+ if (url.pathname !== "/callback") {
210
+ this.sendError(res, 404, "Not Found");
211
+ return;
212
+ }
213
+ const error = url.searchParams.get("error");
214
+ if (error !== null) {
215
+ const desc = url.searchParams.get("error_description") ?? "";
216
+ this.sendError(res, 200, "Authorization denied", `Authorization denied: ${escapeHtml(error)}${desc ? ` — ${escapeHtml(desc)}` : ""}`);
217
+ if (this.pending) {
218
+ const p = this.pending;
219
+ this.pending = undefined;
220
+ p.reject(new Error(`OAuth authorization denied: ${error}${desc ? ` — ${desc}` : ""}`));
221
+ }
222
+ return;
223
+ }
224
+ const code = url.searchParams.get("code");
225
+ const state = url.searchParams.get("state");
226
+ if (code === null || state === null) {
227
+ this.sendError(res, 400, "Bad Request", "Callback is missing required parameters.");
228
+ return;
229
+ }
230
+ // codex Round-1 MUST-FIX #2 — state vs verifier. Constant-time
231
+ // compare to defend against timing oracles.
232
+ if (!this.pending || !constantTimeEqual(state, this.pending.expectedState)) {
233
+ this.sendError(res, 400, "Bad Request", "Callback state mismatch.");
234
+ // Don't disclose what state was expected.
235
+ return;
236
+ }
237
+ // Success path.
238
+ this.sendSuccess(res);
239
+ const p = this.pending;
240
+ this.pending = undefined;
241
+ p.resolve({ code });
242
+ }
243
+ sendSuccess(res) {
244
+ const body = `<!doctype html><html><head><meta charset="utf-8"><title>chances · OAuth</title></head><body style="font-family:system-ui,sans-serif;padding:2rem"><h1>Authorization complete</h1><p>You can close this tab.</p></body></html>`;
245
+ this.writeWithCsp(res, 200, "text/html; charset=utf-8", body);
246
+ }
247
+ sendError(res, status, _label, body) {
248
+ const safe = body ?? "OAuth callback error.";
249
+ const html = `<!doctype html><html><head><meta charset="utf-8"><title>chances · OAuth</title></head><body style="font-family:system-ui,sans-serif;padding:2rem"><h1>OAuth callback error</h1><p>${escapeHtml(safe)}</p></body></html>`;
250
+ this.writeWithCsp(res, status, "text/html; charset=utf-8", html);
251
+ }
252
+ writeWithCsp(res, status, contentType, body) {
253
+ res.statusCode = status;
254
+ res.setHeader("Content-Type", contentType);
255
+ res.setHeader("Content-Security-Policy", "default-src 'none'; base-uri 'none'; frame-ancestors 'none'");
256
+ res.setHeader("X-Content-Type-Options", "nosniff");
257
+ res.setHeader("Cache-Control", "no-store");
258
+ res.setHeader("Referrer-Policy", "no-referrer");
259
+ res.end(body);
260
+ }
261
+ }
262
+ function escapeHtml(s) {
263
+ return s
264
+ .replace(/&/g, "&amp;")
265
+ .replace(/</g, "&lt;")
266
+ .replace(/>/g, "&gt;")
267
+ .replace(/"/g, "&quot;")
268
+ .replace(/'/g, "&#39;");
269
+ }
270
+ /** Length-then-content constant-time compare; safe against tiny strings. */
271
+ function constantTimeEqual(a, b) {
272
+ if (a.length !== b.length)
273
+ return false;
274
+ let diff = 0;
275
+ for (let i = 0; i < a.length; i++) {
276
+ diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
277
+ }
278
+ return diff === 0;
279
+ }
280
+ //# sourceMappingURL=callback-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callback-server.js","sourceRoot":"","sources":["../../../src/mcp/oauth/callback-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * (3.7) Deterministic config hash for vault key derivation.
3
+ *
4
+ * Vault keys are `mcp-oauth|<serverName>|<configHash16>` so that:
5
+ * - Changing the server URL invalidates the stored tokens (you'd
6
+ * otherwise authenticate against the wrong server).
7
+ * - Changing `auth.scopes` invalidates them (need a new consent
8
+ * screen).
9
+ * - Cosmetic changes (header order, URL trailing slashes, scope
10
+ * ordering) do NOT invalidate — same logical config = same hash.
11
+ *
12
+ * Per claude-code's `auth.ts:325-341` pattern. Hash is sha256, kept
13
+ * to 16 hex chars (8 bytes) — enough entropy to distinguish unrelated
14
+ * configs but short enough to remain readable in diagnostics.
15
+ */
16
+ import type { HttpMcpConfig } from "../types.js";
17
+ /**
18
+ * Computes the stable hash for an OAuth-configured HTTP server entry.
19
+ * Throws if the server isn't OAuth-configured (caller's bug).
20
+ */
21
+ export declare function makeConfigHash(config: HttpMcpConfig): string;
22
+ /** Convenience: full vault key for an OAuth-configured server. */
23
+ export declare function makeVaultKey(serverName: string, config: HttpMcpConfig): string;
24
+ //# sourceMappingURL=config-hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-hash.d.ts","sourceRoot":"","sources":["../../../src/mcp/oauth/config-hash.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CA6B5D;AAED,kEAAkE;AAClE,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,MAAM,CAE9E"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * (3.7) Deterministic config hash for vault key derivation.
3
+ *
4
+ * Vault keys are `mcp-oauth|<serverName>|<configHash16>` so that:
5
+ * - Changing the server URL invalidates the stored tokens (you'd
6
+ * otherwise authenticate against the wrong server).
7
+ * - Changing `auth.scopes` invalidates them (need a new consent
8
+ * screen).
9
+ * - Cosmetic changes (header order, URL trailing slashes, scope
10
+ * ordering) do NOT invalidate — same logical config = same hash.
11
+ *
12
+ * Per claude-code's `auth.ts:325-341` pattern. Hash is sha256, kept
13
+ * to 16 hex chars (8 bytes) — enough entropy to distinguish unrelated
14
+ * configs but short enough to remain readable in diagnostics.
15
+ */
16
+ import { createHash } from "node:crypto";
17
+ const HASH_LEN_HEX = 16;
18
+ /**
19
+ * Computes the stable hash for an OAuth-configured HTTP server entry.
20
+ * Throws if the server isn't OAuth-configured (caller's bug).
21
+ */
22
+ export function makeConfigHash(config) {
23
+ if (config.type !== "http" || !config.auth || config.auth.kind !== "oauth") {
24
+ throw new Error("makeConfigHash: server is not OAuth-configured");
25
+ }
26
+ // Normalise URL: trim trailing slashes, lowercase host. Path-case
27
+ // and query stay as-is (some IdPs are path-sensitive).
28
+ let url;
29
+ try {
30
+ url = new URL(config.url);
31
+ }
32
+ catch {
33
+ // If the URL isn't parseable, hash the raw string — caller's
34
+ // parse.ts would have rejected before reaching us, but be defensive.
35
+ return createHash("sha256").update(config.url).digest("hex").slice(0, HASH_LEN_HEX);
36
+ }
37
+ const normalisedUrl = `${url.protocol}//${url.host.toLowerCase()}${url.pathname.replace(/\/+$/, "")}${url.search}`;
38
+ // Canonical scope list: dedup + sort.
39
+ const scopes = config.auth.scopes ? [...new Set(config.auth.scopes)].sort() : [];
40
+ // Stable JSON: only fields that affect IdP-side identity.
41
+ const stable = {
42
+ url: normalisedUrl,
43
+ authServerMetadataUrl: config.auth.authServerMetadataUrl ?? null,
44
+ clientId: config.auth.clientId ?? null,
45
+ clientSecret: config.auth.clientSecret ?? null,
46
+ scopes,
47
+ callbackPort: config.auth.callbackPort ?? null,
48
+ };
49
+ return createHash("sha256").update(JSON.stringify(stable)).digest("hex").slice(0, HASH_LEN_HEX);
50
+ }
51
+ /** Convenience: full vault key for an OAuth-configured server. */
52
+ export function makeVaultKey(serverName, config) {
53
+ return `mcp-oauth|${serverName}|${makeConfigHash(config)}`;
54
+ }
55
+ //# sourceMappingURL=config-hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-hash.js","sourceRoot":"","sources":["../../../src/mcp/oauth/config-hash.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,MAAM,YAAY,GAAG,EAAE,CAAC;AAExB;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,MAAqB;IAClD,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC3E,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IACD,kEAAkE;IAClE,uDAAuD;IACvD,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,6DAA6D;QAC7D,qEAAqE;QACrE,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;IACtF,CAAC;IACD,MAAM,aAAa,GAAG,GAAG,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC;IAEnH,sCAAsC;IACtC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAEjF,0DAA0D;IAC1D,MAAM,MAAM,GAAG;QACb,GAAG,EAAE,aAAa;QAClB,qBAAqB,EAAE,MAAM,CAAC,IAAI,CAAC,qBAAqB,IAAI,IAAI;QAChE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI;QACtC,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI;QAC9C,MAAM;QACN,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI;KAC/C,CAAC;IACF,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;AAClG,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,YAAY,CAAC,UAAkB,EAAE,MAAqB;IACpE,OAAO,aAAa,UAAU,IAAI,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC;AAC7D,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * (3.7) Normalises non-RFC-6749 OAuth error responses.
3
+ *
4
+ * Some IdPs return HTTP 200 + JSON body with `{"ok": false, "error": ...}`
5
+ * instead of the RFC 6749 standard (HTTP 4xx + JSON body with
6
+ * `{"error": "...", "error_description": "..."}`). Slack is the
7
+ * canonical offender; claude-code's
8
+ * `services/mcp/auth.ts:157-190` has a `normalizeOAuthErrorBody()`
9
+ * helper for exactly this case.
10
+ *
11
+ * Without normalisation, the SDK's strict 4xx-based detection silently
12
+ * accepts the 200 response as success and downstream code is confused
13
+ * when the access_token field is missing.
14
+ */
15
+ export interface NormalisedOAuthError {
16
+ /** RFC 6749 error code; defaults to `invalid_request` when unspecified. */
17
+ error: string;
18
+ /** Optional human-readable detail. Already control-stripped. */
19
+ errorDescription?: string;
20
+ /** Optional URI to a page with more info. */
21
+ errorUri?: string;
22
+ }
23
+ /**
24
+ * Inspects a `Response` (already-parsed JSON body) plus HTTP status
25
+ * code and returns:
26
+ * - `{ ok: true }` when the response represents success;
27
+ * - `{ ok: false, error }` when it represents an OAuth failure
28
+ * (regardless of whether the HTTP status is 200 or 4xx).
29
+ */
30
+ export declare function classifyOAuthResponse(status: number, body: unknown): {
31
+ ok: true;
32
+ } | {
33
+ ok: false;
34
+ error: NormalisedOAuthError;
35
+ };
36
+ /** Returns true when an OAuth error is "definitive" — refresh will
37
+ * never succeed without user intervention. */
38
+ export declare function isDefinitiveOAuthError(err: NormalisedOAuthError): boolean;
39
+ //# sourceMappingURL=error-normalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-normalize.d.ts","sourceRoot":"","sources":["../../../src/mcp/oauth/error-normalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,oBAAoB;IACnC,2EAA2E;IAC3E,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AASD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,OAAO,GACZ;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,oBAAoB,CAAA;CAAE,CAmC3D;AA0BD;+CAC+C;AAC/C,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,oBAAoB,GAAG,OAAO,CAEzE"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * (3.7) Normalises non-RFC-6749 OAuth error responses.
3
+ *
4
+ * Some IdPs return HTTP 200 + JSON body with `{"ok": false, "error": ...}`
5
+ * instead of the RFC 6749 standard (HTTP 4xx + JSON body with
6
+ * `{"error": "...", "error_description": "..."}`). Slack is the
7
+ * canonical offender; claude-code's
8
+ * `services/mcp/auth.ts:157-190` has a `normalizeOAuthErrorBody()`
9
+ * helper for exactly this case.
10
+ *
11
+ * Without normalisation, the SDK's strict 4xx-based detection silently
12
+ * accepts the 200 response as success and downstream code is confused
13
+ * when the access_token field is missing.
14
+ */
15
+ /** Strip control chars from a string — defensive on attacker-controlled
16
+ * error_description that might carry newlines/escapes. */
17
+ function clean(s) {
18
+ if (s === undefined || s === null)
19
+ return undefined;
20
+ return s.replace(/[\x00-\x1F\x7F]+/g, " ").trim() || undefined;
21
+ }
22
+ /**
23
+ * Inspects a `Response` (already-parsed JSON body) plus HTTP status
24
+ * code and returns:
25
+ * - `{ ok: true }` when the response represents success;
26
+ * - `{ ok: false, error }` when it represents an OAuth failure
27
+ * (regardless of whether the HTTP status is 200 or 4xx).
28
+ */
29
+ export function classifyOAuthResponse(status, body) {
30
+ // RFC 6749: 4xx with JSON body containing `error`.
31
+ if (status >= 400 && status < 600) {
32
+ const err = extractRfc6749(body);
33
+ return { ok: false, error: err ?? { error: "server_error", errorDescription: `HTTP ${status}` } };
34
+ }
35
+ // Slack-style: 200 with `{ok: false, error: ...}`.
36
+ if (status >= 200 && status < 300) {
37
+ if (isObject(body) && body.ok === false && typeof body.error === "string") {
38
+ return {
39
+ ok: false,
40
+ error: {
41
+ error: body.error,
42
+ errorDescription: clean(typeof body.error_description === "string" ? body.error_description : undefined),
43
+ errorUri: clean(typeof body.error_uri === "string" ? body.error_uri : undefined),
44
+ },
45
+ };
46
+ }
47
+ // Some servers return 200 with a top-level `error` field but no `ok`.
48
+ if (isObject(body) && typeof body.error === "string" && !("access_token" in body)) {
49
+ return {
50
+ ok: false,
51
+ error: {
52
+ error: body.error,
53
+ errorDescription: clean(typeof body.error_description === "string" ? body.error_description : undefined),
54
+ errorUri: clean(typeof body.error_uri === "string" ? body.error_uri : undefined),
55
+ },
56
+ };
57
+ }
58
+ return { ok: true };
59
+ }
60
+ // 1xx / 3xx — surface as unknown.
61
+ return { ok: false, error: { error: "server_error", errorDescription: `HTTP ${status}` } };
62
+ }
63
+ function extractRfc6749(body) {
64
+ if (!isObject(body))
65
+ return undefined;
66
+ if (typeof body.error !== "string")
67
+ return undefined;
68
+ return {
69
+ error: body.error,
70
+ errorDescription: clean(typeof body.error_description === "string" ? body.error_description : undefined),
71
+ errorUri: clean(typeof body.error_uri === "string" ? body.error_uri : undefined),
72
+ };
73
+ }
74
+ function isObject(v) {
75
+ return typeof v === "object" && v !== null && !Array.isArray(v);
76
+ }
77
+ /** RFC 6749 "definitive failure" codes — refresh CANNOT succeed by
78
+ * retrying, must force full re-auth. (oh-my-pi commit c936620c6.) */
79
+ const DEFINITIVE_ERRORS = new Set([
80
+ "invalid_grant",
81
+ "invalid_client",
82
+ "unauthorized_client",
83
+ "unsupported_grant_type",
84
+ "invalid_scope",
85
+ ]);
86
+ /** Returns true when an OAuth error is "definitive" — refresh will
87
+ * never succeed without user intervention. */
88
+ export function isDefinitiveOAuthError(err) {
89
+ return DEFINITIVE_ERRORS.has(err.error);
90
+ }
91
+ //# sourceMappingURL=error-normalize.js.map