@sayknow-cli/ai 0.2.2

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 (361) hide show
  1. package/CHANGELOG.md +2788 -0
  2. package/README.md +1183 -0
  3. package/dist/types/api-registry.d.ts +30 -0
  4. package/dist/types/auth-broker/client.d.ts +66 -0
  5. package/dist/types/auth-broker/index.d.ts +5 -0
  6. package/dist/types/auth-broker/refresher.d.ts +25 -0
  7. package/dist/types/auth-broker/remote-store.d.ts +96 -0
  8. package/dist/types/auth-broker/server.d.ts +32 -0
  9. package/dist/types/auth-broker/types.d.ts +105 -0
  10. package/dist/types/auth-broker/wire-schemas.d.ts +412 -0
  11. package/dist/types/auth-gateway/http.d.ts +39 -0
  12. package/dist/types/auth-gateway/index.d.ts +3 -0
  13. package/dist/types/auth-gateway/server.d.ts +17 -0
  14. package/dist/types/auth-gateway/types.d.ts +115 -0
  15. package/dist/types/auth-storage.d.ts +660 -0
  16. package/dist/types/cli.d.ts +2 -0
  17. package/dist/types/index.d.ts +51 -0
  18. package/dist/types/model-cache.d.ts +17 -0
  19. package/dist/types/model-manager.d.ts +62 -0
  20. package/dist/types/model-thinking.d.ts +74 -0
  21. package/dist/types/models.d.ts +12 -0
  22. package/dist/types/provider-details.d.ts +24 -0
  23. package/dist/types/provider-models/bundled-references.d.ts +4 -0
  24. package/dist/types/provider-models/descriptors.d.ts +48 -0
  25. package/dist/types/provider-models/google.d.ts +20 -0
  26. package/dist/types/provider-models/index.d.ts +5 -0
  27. package/dist/types/provider-models/ollama.d.ts +7 -0
  28. package/dist/types/provider-models/openai-compat.d.ts +244 -0
  29. package/dist/types/provider-models/special.d.ts +16 -0
  30. package/dist/types/providers/amazon-bedrock.d.ts +60 -0
  31. package/dist/types/providers/anthropic-messages-server-schema.d.ts +450 -0
  32. package/dist/types/providers/anthropic-messages-server.d.ts +17 -0
  33. package/dist/types/providers/anthropic.d.ts +198 -0
  34. package/dist/types/providers/aws-credentials.d.ts +43 -0
  35. package/dist/types/providers/aws-eventstream.d.ts +38 -0
  36. package/dist/types/providers/aws-sigv4.d.ts +55 -0
  37. package/dist/types/providers/azure-openai-responses.d.ts +15 -0
  38. package/dist/types/providers/composer-discipline.d.ts +26 -0
  39. package/dist/types/providers/cursor/gen/agent_pb.d.ts +13022 -0
  40. package/dist/types/providers/cursor.d.ts +44 -0
  41. package/dist/types/providers/error-message.d.ts +27 -0
  42. package/dist/types/providers/github-copilot-headers.d.ts +40 -0
  43. package/dist/types/providers/gitlab-duo.d.ts +27 -0
  44. package/dist/types/providers/google-auth.d.ts +24 -0
  45. package/dist/types/providers/google-gemini-cli.d.ts +72 -0
  46. package/dist/types/providers/google-gemini-headers.d.ts +18 -0
  47. package/dist/types/providers/google-shared.d.ts +173 -0
  48. package/dist/types/providers/google-types.d.ts +138 -0
  49. package/dist/types/providers/google-vertex.d.ts +7 -0
  50. package/dist/types/providers/google.d.ts +4 -0
  51. package/dist/types/providers/grammar.d.ts +1 -0
  52. package/dist/types/providers/kimi.d.ts +27 -0
  53. package/dist/types/providers/mock.d.ts +175 -0
  54. package/dist/types/providers/ollama.d.ts +41 -0
  55. package/dist/types/providers/openai-anthropic-shim.d.ts +31 -0
  56. package/dist/types/providers/openai-chat-server-schema.d.ts +815 -0
  57. package/dist/types/providers/openai-chat-server.d.ts +16 -0
  58. package/dist/types/providers/openai-codex/constants.d.ts +26 -0
  59. package/dist/types/providers/openai-codex/request-transformer.d.ts +49 -0
  60. package/dist/types/providers/openai-codex/response-handler.d.ts +17 -0
  61. package/dist/types/providers/openai-codex-responses.d.ts +67 -0
  62. package/dist/types/providers/openai-completions-compat.d.ts +27 -0
  63. package/dist/types/providers/openai-completions.d.ts +33 -0
  64. package/dist/types/providers/openai-request-transform.d.ts +4 -0
  65. package/dist/types/providers/openai-responses-server-schema.d.ts +392 -0
  66. package/dist/types/providers/openai-responses-server.d.ts +17 -0
  67. package/dist/types/providers/openai-responses-shared.d.ts +89 -0
  68. package/dist/types/providers/openai-responses.d.ts +32 -0
  69. package/dist/types/providers/pi-native-client.d.ts +13 -0
  70. package/dist/types/providers/pi-native-server.d.ts +68 -0
  71. package/dist/types/providers/register-builtins.d.ts +31 -0
  72. package/dist/types/providers/synthetic.d.ts +26 -0
  73. package/dist/types/providers/transform-messages.d.ts +14 -0
  74. package/dist/types/providers/vision-guard.d.ts +8 -0
  75. package/dist/types/rate-limit-utils.d.ts +19 -0
  76. package/dist/types/stream.d.ts +43 -0
  77. package/dist/types/types.d.ts +811 -0
  78. package/dist/types/usage/claude.d.ts +3 -0
  79. package/dist/types/usage/gemini.d.ts +2 -0
  80. package/dist/types/usage/github-copilot.d.ts +7 -0
  81. package/dist/types/usage/google-antigravity.d.ts +2 -0
  82. package/dist/types/usage/grok-cli.d.ts +10 -0
  83. package/dist/types/usage/kimi.d.ts +2 -0
  84. package/dist/types/usage/minimax-code.d.ts +2 -0
  85. package/dist/types/usage/openai-codex.d.ts +3 -0
  86. package/dist/types/usage/shared.d.ts +1 -0
  87. package/dist/types/usage/zai.d.ts +2 -0
  88. package/dist/types/usage.d.ts +258 -0
  89. package/dist/types/utils/abort.d.ts +19 -0
  90. package/dist/types/utils/anthropic-auth.d.ts +31 -0
  91. package/dist/types/utils/discovery/antigravity.d.ts +61 -0
  92. package/dist/types/utils/discovery/codex.d.ts +38 -0
  93. package/dist/types/utils/discovery/cursor.d.ts +23 -0
  94. package/dist/types/utils/discovery/gemini.d.ts +25 -0
  95. package/dist/types/utils/discovery/index.d.ts +4 -0
  96. package/dist/types/utils/discovery/openai-compatible.d.ts +74 -0
  97. package/dist/types/utils/event-stream.d.ts +33 -0
  98. package/dist/types/utils/fireworks-model-id.d.ts +10 -0
  99. package/dist/types/utils/foundry.d.ts +1 -0
  100. package/dist/types/utils/h2-fetch.d.ts +22 -0
  101. package/dist/types/utils/http-inspector.d.ts +35 -0
  102. package/dist/types/utils/idle-iterator.d.ts +67 -0
  103. package/dist/types/utils/json-parse.d.ts +10 -0
  104. package/dist/types/utils/oauth/alibaba-coding-plan.d.ts +18 -0
  105. package/dist/types/utils/oauth/anthropic.d.ts +22 -0
  106. package/dist/types/utils/oauth/api-key-login.d.ts +35 -0
  107. package/dist/types/utils/oauth/api-key-validation.d.ts +27 -0
  108. package/dist/types/utils/oauth/callback-server.d.ts +60 -0
  109. package/dist/types/utils/oauth/cerebras.d.ts +1 -0
  110. package/dist/types/utils/oauth/cloudflare-ai-gateway.d.ts +18 -0
  111. package/dist/types/utils/oauth/cursor.d.ts +15 -0
  112. package/dist/types/utils/oauth/deepseek.d.ts +10 -0
  113. package/dist/types/utils/oauth/firepass.d.ts +1 -0
  114. package/dist/types/utils/oauth/fireworks.d.ts +1 -0
  115. package/dist/types/utils/oauth/github-copilot.d.ts +38 -0
  116. package/dist/types/utils/oauth/gitlab-duo.d.ts +3 -0
  117. package/dist/types/utils/oauth/google-antigravity.d.ts +11 -0
  118. package/dist/types/utils/oauth/google-gemini-cli.d.ts +10 -0
  119. package/dist/types/utils/oauth/google-oauth-shared.d.ts +28 -0
  120. package/dist/types/utils/oauth/huggingface.d.ts +19 -0
  121. package/dist/types/utils/oauth/index.d.ts +38 -0
  122. package/dist/types/utils/oauth/kagi.d.ts +17 -0
  123. package/dist/types/utils/oauth/kilo.d.ts +5 -0
  124. package/dist/types/utils/oauth/kimi.d.ts +21 -0
  125. package/dist/types/utils/oauth/litellm.d.ts +18 -0
  126. package/dist/types/utils/oauth/lm-studio.d.ts +17 -0
  127. package/dist/types/utils/oauth/minimax-code.d.ts +28 -0
  128. package/dist/types/utils/oauth/moonshot.d.ts +1 -0
  129. package/dist/types/utils/oauth/nanogpt.d.ts +1 -0
  130. package/dist/types/utils/oauth/nvidia.d.ts +18 -0
  131. package/dist/types/utils/oauth/ollama-cloud.d.ts +2 -0
  132. package/dist/types/utils/oauth/ollama.d.ts +18 -0
  133. package/dist/types/utils/oauth/openai-codex.d.ts +21 -0
  134. package/dist/types/utils/oauth/opencode.d.ts +18 -0
  135. package/dist/types/utils/oauth/parallel.d.ts +17 -0
  136. package/dist/types/utils/oauth/perplexity.d.ts +9 -0
  137. package/dist/types/utils/oauth/pkce.d.ts +8 -0
  138. package/dist/types/utils/oauth/qianfan.d.ts +17 -0
  139. package/dist/types/utils/oauth/qwen-portal.d.ts +19 -0
  140. package/dist/types/utils/oauth/synthetic.d.ts +1 -0
  141. package/dist/types/utils/oauth/tavily.d.ts +17 -0
  142. package/dist/types/utils/oauth/together.d.ts +1 -0
  143. package/dist/types/utils/oauth/types.d.ts +45 -0
  144. package/dist/types/utils/oauth/venice.d.ts +18 -0
  145. package/dist/types/utils/oauth/vercel-ai-gateway.d.ts +18 -0
  146. package/dist/types/utils/oauth/vllm.d.ts +16 -0
  147. package/dist/types/utils/oauth/xai.d.ts +30 -0
  148. package/dist/types/utils/oauth/xiaomi.d.ts +25 -0
  149. package/dist/types/utils/oauth/zai.d.ts +18 -0
  150. package/dist/types/utils/oauth/zenmux.d.ts +1 -0
  151. package/dist/types/utils/overflow.d.ts +54 -0
  152. package/dist/types/utils/parse-bind.d.ts +23 -0
  153. package/dist/types/utils/provider-response.d.ts +3 -0
  154. package/dist/types/utils/retry-after.d.ts +3 -0
  155. package/dist/types/utils/retry-budget.d.ts +1 -0
  156. package/dist/types/utils/retry.d.ts +26 -0
  157. package/dist/types/utils/schema/adapt.d.ts +24 -0
  158. package/dist/types/utils/schema/compatibility.d.ts +30 -0
  159. package/dist/types/utils/schema/dereference.d.ts +11 -0
  160. package/dist/types/utils/schema/draft.d.ts +10 -0
  161. package/dist/types/utils/schema/equality.d.ts +4 -0
  162. package/dist/types/utils/schema/fields.d.ts +49 -0
  163. package/dist/types/utils/schema/index.d.ts +13 -0
  164. package/dist/types/utils/schema/json-schema-validator.d.ts +12 -0
  165. package/dist/types/utils/schema/meta-validator.d.ts +2 -0
  166. package/dist/types/utils/schema/normalize.d.ts +93 -0
  167. package/dist/types/utils/schema/spill.d.ts +8 -0
  168. package/dist/types/utils/schema/stamps.d.ts +25 -0
  169. package/dist/types/utils/schema/types.d.ts +4 -0
  170. package/dist/types/utils/schema/wire.d.ts +54 -0
  171. package/dist/types/utils/schema/zod-decontaminate.d.ts +31 -0
  172. package/dist/types/utils/sse-debug.d.ts +10 -0
  173. package/dist/types/utils/tool-call-healing.d.ts +71 -0
  174. package/dist/types/utils/tool-choice-capability.d.ts +41 -0
  175. package/dist/types/utils/tool-choice.d.ts +50 -0
  176. package/dist/types/utils/validation.d.ts +17 -0
  177. package/dist/types/utils.d.ts +34 -0
  178. package/package.json +146 -0
  179. package/src/api-registry.ts +96 -0
  180. package/src/auth-broker/client.ts +358 -0
  181. package/src/auth-broker/index.ts +5 -0
  182. package/src/auth-broker/refresher.ts +127 -0
  183. package/src/auth-broker/remote-store.ts +623 -0
  184. package/src/auth-broker/server.ts +644 -0
  185. package/src/auth-broker/types.ts +127 -0
  186. package/src/auth-broker/wire-schemas.ts +200 -0
  187. package/src/auth-gateway/http.ts +194 -0
  188. package/src/auth-gateway/index.ts +3 -0
  189. package/src/auth-gateway/server.ts +717 -0
  190. package/src/auth-gateway/types.ts +134 -0
  191. package/src/auth-storage.ts +4179 -0
  192. package/src/cli.ts +263 -0
  193. package/src/index.ts +56 -0
  194. package/src/model-cache.ts +129 -0
  195. package/src/model-manager.ts +486 -0
  196. package/src/model-thinking.ts +772 -0
  197. package/src/models.json +75437 -0
  198. package/src/models.json.d.ts +9 -0
  199. package/src/models.ts +82 -0
  200. package/src/prompts/turn-aborted-guidance.md +4 -0
  201. package/src/provider-details.ts +90 -0
  202. package/src/provider-models/bundled-references.ts +38 -0
  203. package/src/provider-models/descriptors.ts +327 -0
  204. package/src/provider-models/google.ts +91 -0
  205. package/src/provider-models/index.ts +5 -0
  206. package/src/provider-models/ollama.ts +153 -0
  207. package/src/provider-models/openai-compat.ts +2352 -0
  208. package/src/provider-models/special.ts +67 -0
  209. package/src/providers/amazon-bedrock.ts +937 -0
  210. package/src/providers/anthropic-messages-server-schema.ts +229 -0
  211. package/src/providers/anthropic-messages-server.ts +677 -0
  212. package/src/providers/anthropic.ts +2940 -0
  213. package/src/providers/aws-credentials.ts +501 -0
  214. package/src/providers/aws-eventstream.ts +185 -0
  215. package/src/providers/aws-sigv4.ts +218 -0
  216. package/src/providers/azure-openai-responses.ts +379 -0
  217. package/src/providers/composer-discipline.ts +41 -0
  218. package/src/providers/cursor/gen/agent_pb.ts +15274 -0
  219. package/src/providers/cursor/proto/agent.proto +3526 -0
  220. package/src/providers/cursor/proto/buf.gen.yaml +6 -0
  221. package/src/providers/cursor/proto/buf.yaml +17 -0
  222. package/src/providers/cursor.ts +2671 -0
  223. package/src/providers/error-message.ts +21 -0
  224. package/src/providers/github-copilot-headers.ts +140 -0
  225. package/src/providers/gitlab-duo.ts +372 -0
  226. package/src/providers/google-auth.ts +252 -0
  227. package/src/providers/google-gemini-cli.ts +856 -0
  228. package/src/providers/google-gemini-headers.ts +41 -0
  229. package/src/providers/google-shared.ts +951 -0
  230. package/src/providers/google-types.ts +167 -0
  231. package/src/providers/google-vertex.ts +88 -0
  232. package/src/providers/google.ts +41 -0
  233. package/src/providers/grammar.ts +70 -0
  234. package/src/providers/kimi.ts +52 -0
  235. package/src/providers/mock.ts +500 -0
  236. package/src/providers/ollama.ts +603 -0
  237. package/src/providers/openai-anthropic-shim.ts +138 -0
  238. package/src/providers/openai-chat-server-schema.ts +243 -0
  239. package/src/providers/openai-chat-server.ts +635 -0
  240. package/src/providers/openai-codex/constants.ts +43 -0
  241. package/src/providers/openai-codex/request-transformer.ts +161 -0
  242. package/src/providers/openai-codex/response-handler.ts +81 -0
  243. package/src/providers/openai-codex-responses.ts +2774 -0
  244. package/src/providers/openai-completions-compat.ts +289 -0
  245. package/src/providers/openai-completions.ts +1935 -0
  246. package/src/providers/openai-request-transform.ts +136 -0
  247. package/src/providers/openai-responses-server-schema.ts +290 -0
  248. package/src/providers/openai-responses-server.ts +1190 -0
  249. package/src/providers/openai-responses-shared.ts +800 -0
  250. package/src/providers/openai-responses.ts +738 -0
  251. package/src/providers/pi-native-client.ts +227 -0
  252. package/src/providers/pi-native-server.ts +210 -0
  253. package/src/providers/register-builtins.ts +411 -0
  254. package/src/providers/synthetic.ts +50 -0
  255. package/src/providers/transform-messages.ts +319 -0
  256. package/src/providers/vision-guard.ts +31 -0
  257. package/src/rate-limit-utils.ts +93 -0
  258. package/src/stream.ts +960 -0
  259. package/src/types.ts +967 -0
  260. package/src/usage/claude.ts +431 -0
  261. package/src/usage/gemini.ts +250 -0
  262. package/src/usage/github-copilot.ts +421 -0
  263. package/src/usage/google-antigravity.ts +201 -0
  264. package/src/usage/grok-cli.ts +163 -0
  265. package/src/usage/kimi.ts +271 -0
  266. package/src/usage/minimax-code.ts +31 -0
  267. package/src/usage/openai-codex.ts +503 -0
  268. package/src/usage/shared.ts +10 -0
  269. package/src/usage/zai.ts +247 -0
  270. package/src/usage.ts +183 -0
  271. package/src/utils/abort.ts +51 -0
  272. package/src/utils/anthropic-auth.ts +87 -0
  273. package/src/utils/discovery/antigravity.ts +261 -0
  274. package/src/utils/discovery/codex.ts +371 -0
  275. package/src/utils/discovery/cursor.ts +306 -0
  276. package/src/utils/discovery/gemini.ts +248 -0
  277. package/src/utils/discovery/index.ts +4 -0
  278. package/src/utils/discovery/openai-compatible.ts +230 -0
  279. package/src/utils/event-stream.ts +172 -0
  280. package/src/utils/fireworks-model-id.ts +30 -0
  281. package/src/utils/foundry.ts +8 -0
  282. package/src/utils/h2-fetch.ts +60 -0
  283. package/src/utils/http-inspector.ts +255 -0
  284. package/src/utils/idle-iterator.ts +257 -0
  285. package/src/utils/json-parse.ts +148 -0
  286. package/src/utils/oauth/alibaba-coding-plan.ts +59 -0
  287. package/src/utils/oauth/anthropic.ts +200 -0
  288. package/src/utils/oauth/api-key-login.ts +87 -0
  289. package/src/utils/oauth/api-key-validation.ts +92 -0
  290. package/src/utils/oauth/callback-server.ts +281 -0
  291. package/src/utils/oauth/cerebras.ts +16 -0
  292. package/src/utils/oauth/cloudflare-ai-gateway.ts +48 -0
  293. package/src/utils/oauth/cursor.ts +157 -0
  294. package/src/utils/oauth/deepseek.ts +53 -0
  295. package/src/utils/oauth/firepass.ts +24 -0
  296. package/src/utils/oauth/fireworks.ts +15 -0
  297. package/src/utils/oauth/github-copilot.ts +362 -0
  298. package/src/utils/oauth/gitlab-duo.ts +123 -0
  299. package/src/utils/oauth/google-antigravity.ts +200 -0
  300. package/src/utils/oauth/google-gemini-cli.ts +256 -0
  301. package/src/utils/oauth/google-oauth-shared.ts +110 -0
  302. package/src/utils/oauth/huggingface.ts +62 -0
  303. package/src/utils/oauth/index.ts +469 -0
  304. package/src/utils/oauth/kagi.ts +47 -0
  305. package/src/utils/oauth/kilo.ts +87 -0
  306. package/src/utils/oauth/kimi.ts +254 -0
  307. package/src/utils/oauth/litellm.ts +47 -0
  308. package/src/utils/oauth/lm-studio.ts +38 -0
  309. package/src/utils/oauth/minimax-code.ts +78 -0
  310. package/src/utils/oauth/moonshot.ts +16 -0
  311. package/src/utils/oauth/nanogpt.ts +15 -0
  312. package/src/utils/oauth/nvidia.ts +70 -0
  313. package/src/utils/oauth/oauth.html +199 -0
  314. package/src/utils/oauth/ollama-cloud.ts +28 -0
  315. package/src/utils/oauth/ollama.ts +47 -0
  316. package/src/utils/oauth/openai-codex.ts +299 -0
  317. package/src/utils/oauth/opencode.ts +49 -0
  318. package/src/utils/oauth/parallel.ts +46 -0
  319. package/src/utils/oauth/perplexity.ts +206 -0
  320. package/src/utils/oauth/pkce.ts +18 -0
  321. package/src/utils/oauth/qianfan.ts +58 -0
  322. package/src/utils/oauth/qwen-portal.ts +60 -0
  323. package/src/utils/oauth/synthetic.ts +16 -0
  324. package/src/utils/oauth/tavily.ts +46 -0
  325. package/src/utils/oauth/together.ts +16 -0
  326. package/src/utils/oauth/types.ts +99 -0
  327. package/src/utils/oauth/venice.ts +59 -0
  328. package/src/utils/oauth/vercel-ai-gateway.ts +47 -0
  329. package/src/utils/oauth/vllm.ts +40 -0
  330. package/src/utils/oauth/xai.ts +246 -0
  331. package/src/utils/oauth/xiaomi.ts +199 -0
  332. package/src/utils/oauth/zai.ts +60 -0
  333. package/src/utils/oauth/zenmux.ts +15 -0
  334. package/src/utils/overflow.ts +137 -0
  335. package/src/utils/parse-bind.ts +54 -0
  336. package/src/utils/provider-response.ts +30 -0
  337. package/src/utils/retry-after.ts +110 -0
  338. package/src/utils/retry-budget.ts +4 -0
  339. package/src/utils/retry.ts +54 -0
  340. package/src/utils/schema/CONSTRAINTS.md +164 -0
  341. package/src/utils/schema/adapt.ts +36 -0
  342. package/src/utils/schema/compatibility.ts +435 -0
  343. package/src/utils/schema/dereference.ts +98 -0
  344. package/src/utils/schema/draft.ts +341 -0
  345. package/src/utils/schema/equality.ts +97 -0
  346. package/src/utils/schema/fields.ts +190 -0
  347. package/src/utils/schema/index.ts +13 -0
  348. package/src/utils/schema/json-schema-validator.ts +577 -0
  349. package/src/utils/schema/meta-validator.ts +167 -0
  350. package/src/utils/schema/normalize.ts +1588 -0
  351. package/src/utils/schema/spill.ts +43 -0
  352. package/src/utils/schema/stamps.ts +97 -0
  353. package/src/utils/schema/types.ts +11 -0
  354. package/src/utils/schema/wire.ts +213 -0
  355. package/src/utils/schema/zod-decontaminate.ts +331 -0
  356. package/src/utils/sse-debug.ts +289 -0
  357. package/src/utils/tool-call-healing.ts +271 -0
  358. package/src/utils/tool-choice-capability.ts +220 -0
  359. package/src/utils/tool-choice.ts +99 -0
  360. package/src/utils/validation.ts +1019 -0
  361. package/src/utils.ts +178 -0
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Alibaba Coding Plan login flow.
3
+ *
4
+ * Alibaba Coding Plan provides OpenAI-compatible models via https://coding-intl.dashscope.aliyuncs.com/v1.
5
+ *
6
+ * This is not OAuth - it's a simple API key flow:
7
+ * 1. Open browser to Alibaba Cloud DashScope API key settings
8
+ * 2. User copies their API key
9
+ * 3. User pastes the API key into the CLI
10
+ */
11
+
12
+ import { validateOpenAICompatibleApiKey } from "./api-key-validation";
13
+ import type { OAuthController } from "./types";
14
+
15
+ const AUTH_URL = "https://modelstudio.console.alibabacloud.com/";
16
+ const API_BASE_URL = "https://coding-intl.dashscope.aliyuncs.com/v1";
17
+ const VALIDATION_MODEL = "qwen3.5-plus";
18
+
19
+ /**
20
+ * Login to Alibaba Coding Plan.
21
+ *
22
+ * Opens browser to API keys page, prompts user to paste their API key.
23
+ * Returns the API key directly (not OAuthCredentials - this isn't OAuth).
24
+ */
25
+ export async function loginAlibabaCodingPlan(options: OAuthController): Promise<string> {
26
+ if (!options.onPrompt) {
27
+ throw new Error("Alibaba Coding Plan login requires onPrompt callback");
28
+ }
29
+
30
+ options.onAuth?.({
31
+ url: AUTH_URL,
32
+ instructions: "Copy your API key from the Alibaba Cloud DashScope console",
33
+ });
34
+
35
+ const apiKey = await options.onPrompt({
36
+ message: "Paste your Alibaba Coding Plan API key",
37
+ placeholder: "sk-...",
38
+ });
39
+
40
+ if (options.signal?.aborted) {
41
+ throw new Error("Login cancelled");
42
+ }
43
+
44
+ const trimmed = apiKey.trim();
45
+ if (!trimmed) {
46
+ throw new Error("API key is required");
47
+ }
48
+
49
+ options.onProgress?.("Validating API key...");
50
+ await validateOpenAICompatibleApiKey({
51
+ provider: "Alibaba Coding Plan",
52
+ apiKey: trimmed,
53
+ baseUrl: API_BASE_URL,
54
+ model: VALIDATION_MODEL,
55
+ signal: options.signal,
56
+ });
57
+
58
+ return trimmed;
59
+ }
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Anthropic OAuth flow (Anthropic model Pro/Max)
3
+ */
4
+ import { OAuthCallbackFlow } from "./callback-server";
5
+ import { generatePKCE } from "./pkce";
6
+ import type { OAuthController, OAuthCredentials } from "./types";
7
+
8
+ const decode = (s: string) => atob(s);
9
+ const CLIENT_ID = decode("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
10
+ const AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
11
+ const TOKEN_URL = "https://api.anthropic.com/v1/oauth/token";
12
+ const CALLBACK_PORT = 54545;
13
+ const CALLBACK_PATH = "/callback";
14
+ const SCOPES = "org:create_api_key user:profile user:inference";
15
+
16
+ function formatErrorDetails(error: unknown): string {
17
+ if (error instanceof Error) {
18
+ const details: string[] = [`${error.name}: ${error.message}`];
19
+ const errorWithCode = error as Error & { code?: string; errno?: number | string; cause?: unknown };
20
+ if (errorWithCode.code) details.push(`code=${errorWithCode.code}`);
21
+ if (typeof errorWithCode.errno !== "undefined") details.push(`errno=${String(errorWithCode.errno)}`);
22
+ if (typeof error.cause !== "undefined") {
23
+ details.push(`cause=${formatErrorDetails(error.cause)}`);
24
+ }
25
+ if (error.stack) {
26
+ details.push(`stack=${error.stack}`);
27
+ }
28
+ return details.join("; ");
29
+ }
30
+ return String(error);
31
+ }
32
+
33
+ async function postJson(url: string, body: Record<string, string | number>): Promise<string> {
34
+ const response = await fetch(url, {
35
+ method: "POST",
36
+ headers: {
37
+ "Content-Type": "application/json",
38
+ Accept: "application/json",
39
+ },
40
+ body: JSON.stringify(body),
41
+ signal: AbortSignal.timeout(30_000),
42
+ });
43
+
44
+ const responseBody = await response.text();
45
+ if (!response.ok) {
46
+ throw new Error(`HTTP request failed. status=${response.status}; url=${url}; body=${responseBody}`);
47
+ }
48
+ return responseBody;
49
+ }
50
+
51
+ /**
52
+ * Decoded shape of Anthropic's `/v1/oauth/token` response (both
53
+ * `authorization_code` exchange and `refresh_token` refresh return the same
54
+ * envelope). The `account` block is inlined alongside the tokens, so we can
55
+ * surface `accountId` / `email` on {@link OAuthCredentials} without a separate
56
+ * `/api/oauth/profile` round-trip.
57
+ */
58
+ interface AnthropicTokenResponse {
59
+ access_token: string;
60
+ refresh_token: string;
61
+ expires_in: number;
62
+ account?: { uuid?: string; email_address?: string };
63
+ }
64
+
65
+ function parseOAuthTokenResponse(responseBody: string, operation: string): AnthropicTokenResponse {
66
+ try {
67
+ return JSON.parse(responseBody) as AnthropicTokenResponse;
68
+ } catch (error) {
69
+ throw new Error(
70
+ `Anthropic ${operation} returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`,
71
+ );
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Lift the OAuth response's `account: { uuid, email_address }` block onto
77
+ * {@link OAuthCredentials} so downstream identity propagation (e.g.
78
+ * `metadata.user_id.account_uuid`, usage tracking) works without a separate
79
+ * `/api/oauth/profile` round-trip. Returns `undefined` for either field when
80
+ * the response omits it or carries a non-string / empty value.
81
+ */
82
+ function extractAccountFromTokenResponse(data: AnthropicTokenResponse): {
83
+ accountId?: string;
84
+ email?: string;
85
+ } {
86
+ const accountUuid = data.account?.uuid;
87
+ const emailAddress = data.account?.email_address;
88
+ return {
89
+ accountId: typeof accountUuid === "string" && accountUuid.length > 0 ? accountUuid : undefined,
90
+ email: typeof emailAddress === "string" && emailAddress.length > 0 ? emailAddress : undefined,
91
+ };
92
+ }
93
+
94
+ export class AnthropicOAuthFlow extends OAuthCallbackFlow {
95
+ #verifier: string = "";
96
+ #challenge: string = "";
97
+
98
+ constructor(ctrl: OAuthController) {
99
+ super(ctrl, CALLBACK_PORT, CALLBACK_PATH);
100
+ }
101
+
102
+ async generateAuthUrl(state: string, redirectUri: string): Promise<{ url: string; instructions?: string }> {
103
+ const pkce = await generatePKCE();
104
+ this.#verifier = pkce.verifier;
105
+ this.#challenge = pkce.challenge;
106
+
107
+ const authParams = new URLSearchParams({
108
+ code: "true",
109
+ client_id: CLIENT_ID,
110
+ response_type: "code",
111
+ redirect_uri: redirectUri,
112
+ scope: SCOPES,
113
+ code_challenge: this.#challenge,
114
+ code_challenge_method: "S256",
115
+ state,
116
+ });
117
+ const url = `${AUTHORIZE_URL}?${authParams.toString()}`;
118
+
119
+ return {
120
+ url,
121
+ instructions:
122
+ "Complete login in your browser. If the browser cannot reach this machine, paste the final redirect URL or authorization code when prompted.",
123
+ };
124
+ }
125
+
126
+ async exchangeToken(code: string, state: string, redirectUri: string): Promise<OAuthCredentials> {
127
+ let exchangeCode = code;
128
+ let exchangeState = state;
129
+ const codeFragmentIndex = code.indexOf("#");
130
+ if (codeFragmentIndex >= 0) {
131
+ exchangeCode = code.slice(0, codeFragmentIndex);
132
+ const codeFragmentState = code.slice(codeFragmentIndex + 1);
133
+ if (codeFragmentState.length > 0) {
134
+ exchangeState = codeFragmentState;
135
+ }
136
+ }
137
+
138
+ let responseBody: string;
139
+ try {
140
+ responseBody = await postJson(TOKEN_URL, {
141
+ grant_type: "authorization_code",
142
+ client_id: CLIENT_ID,
143
+ code: exchangeCode,
144
+ state: exchangeState,
145
+ redirect_uri: redirectUri,
146
+ code_verifier: this.#verifier,
147
+ });
148
+ } catch (error) {
149
+ throw new Error(
150
+ `Token exchange request failed. url=${TOKEN_URL}; redirect_uri=${redirectUri}; response_type=authorization_code; details=${formatErrorDetails(error)}`,
151
+ );
152
+ }
153
+
154
+ const tokenData = parseOAuthTokenResponse(responseBody, "token exchange");
155
+ const { accountId, email } = extractAccountFromTokenResponse(tokenData);
156
+
157
+ return {
158
+ refresh: tokenData.refresh_token,
159
+ access: tokenData.access_token,
160
+ expires: Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000,
161
+ accountId,
162
+ email,
163
+ };
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Login with Anthropic OAuth
169
+ */
170
+ export async function loginAnthropic(ctrl: OAuthController): Promise<OAuthCredentials> {
171
+ const flow = new AnthropicOAuthFlow(ctrl);
172
+ return flow.login();
173
+ }
174
+
175
+ /**
176
+ * Refresh Anthropic OAuth token
177
+ */
178
+ export async function refreshAnthropicToken(refreshToken: string): Promise<OAuthCredentials> {
179
+ let responseBody: string;
180
+ try {
181
+ responseBody = await postJson(TOKEN_URL, {
182
+ grant_type: "refresh_token",
183
+ client_id: CLIENT_ID,
184
+ refresh_token: refreshToken,
185
+ });
186
+ } catch (error) {
187
+ throw new Error(`Anthropic token refresh request failed. url=${TOKEN_URL}; details=${formatErrorDetails(error)}`);
188
+ }
189
+
190
+ const data = parseOAuthTokenResponse(responseBody, "token refresh");
191
+ const { accountId, email } = extractAccountFromTokenResponse(data);
192
+
193
+ return {
194
+ refresh: data.refresh_token || refreshToken,
195
+ access: data.access_token,
196
+ expires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,
197
+ accountId,
198
+ email,
199
+ };
200
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Shared factory for API-key-paste "login" flows.
3
+ *
4
+ * Several providers (Cerebras, Synthetic, Moonshot, Together, NanoGPT, ZenMux)
5
+ * don't actually implement OAuth — they just ask the user to paste an API key,
6
+ * optionally validate it, and return the trimmed key.
7
+ */
8
+
9
+ import { validateApiKeyAgainstModelsEndpoint, validateOpenAICompatibleApiKey } from "./api-key-validation";
10
+ import type { OAuthController } from "./types";
11
+
12
+ type ChatCompletionsValidation = {
13
+ kind: "chat-completions";
14
+ provider: string;
15
+ baseUrl: string;
16
+ model: string;
17
+ };
18
+
19
+ type ModelsEndpointValidation = {
20
+ kind: "models-endpoint";
21
+ provider: string;
22
+ modelsUrl: string;
23
+ };
24
+
25
+ export type ApiKeyLoginConfig = {
26
+ /** Display name used in error messages, e.g. "Cerebras", "NanoGPT". */
27
+ providerLabel: string;
28
+ /** URL opened in browser for the user to grab their key. */
29
+ authUrl: string;
30
+ /** Instructions shown with the onAuth callback. */
31
+ instructions: string;
32
+ /** Prompt message shown when asking for the key paste. */
33
+ promptMessage: string;
34
+ /** Placeholder string for the prompt (e.g. "sk-...", "csk-..."). */
35
+ placeholder: string;
36
+ /** Validation strategy, or `null` to skip validation. */
37
+ validation: ChatCompletionsValidation | ModelsEndpointValidation | null;
38
+ };
39
+
40
+ export function createApiKeyLogin(config: ApiKeyLoginConfig): (options: OAuthController) => Promise<string> {
41
+ return async function login(options: OAuthController): Promise<string> {
42
+ if (!options.onPrompt) {
43
+ throw new Error(`${config.providerLabel} login requires onPrompt callback`);
44
+ }
45
+
46
+ options.onAuth?.({
47
+ url: config.authUrl,
48
+ instructions: config.instructions,
49
+ });
50
+
51
+ const apiKey = await options.onPrompt({
52
+ message: config.promptMessage,
53
+ placeholder: config.placeholder,
54
+ });
55
+
56
+ if (options.signal?.aborted) {
57
+ throw new Error("Login cancelled");
58
+ }
59
+
60
+ const trimmed = apiKey.trim();
61
+ if (!trimmed) {
62
+ throw new Error("API key is required");
63
+ }
64
+
65
+ if (config.validation) {
66
+ options.onProgress?.("Validating API key...");
67
+ if (config.validation.kind === "chat-completions") {
68
+ await validateOpenAICompatibleApiKey({
69
+ provider: config.validation.provider,
70
+ apiKey: trimmed,
71
+ baseUrl: config.validation.baseUrl,
72
+ model: config.validation.model,
73
+ signal: options.signal,
74
+ });
75
+ } else {
76
+ await validateApiKeyAgainstModelsEndpoint({
77
+ provider: config.validation.provider,
78
+ apiKey: trimmed,
79
+ modelsUrl: config.validation.modelsUrl,
80
+ signal: options.signal,
81
+ });
82
+ }
83
+ }
84
+
85
+ return trimmed;
86
+ };
87
+ }
@@ -0,0 +1,92 @@
1
+ type OpenAICompatibleValidationOptions = {
2
+ provider: string;
3
+ apiKey: string;
4
+ baseUrl: string;
5
+ model: string;
6
+ signal?: AbortSignal;
7
+ };
8
+
9
+ type ModelListValidationOptions = {
10
+ provider: string;
11
+ apiKey: string;
12
+ modelsUrl: string;
13
+ signal?: AbortSignal;
14
+ };
15
+
16
+ const VALIDATION_TIMEOUT_MS = 15_000;
17
+
18
+ /**
19
+ * Validate an API key against an OpenAI-compatible chat completions endpoint.
20
+ *
21
+ * Performs a minimal request to verify credentials and endpoint access.
22
+ */
23
+ export async function validateOpenAICompatibleApiKey(options: OpenAICompatibleValidationOptions): Promise<void> {
24
+ const timeoutSignal = AbortSignal.timeout(VALIDATION_TIMEOUT_MS);
25
+ const signal = options.signal ? AbortSignal.any([options.signal, timeoutSignal]) : timeoutSignal;
26
+
27
+ const response = await fetch(`${options.baseUrl}/chat/completions`, {
28
+ method: "POST",
29
+ headers: {
30
+ "Content-Type": "application/json",
31
+ Authorization: `Bearer ${options.apiKey}`,
32
+ },
33
+ body: JSON.stringify({
34
+ model: options.model,
35
+ messages: [{ role: "user", content: "ping" }],
36
+ max_tokens: 1,
37
+ temperature: 0,
38
+ }),
39
+ signal,
40
+ });
41
+
42
+ if (response.ok) {
43
+ return;
44
+ }
45
+
46
+ let details = "";
47
+ try {
48
+ details = (await response.text()).trim();
49
+ } catch {
50
+ // ignore body parse errors, status is enough
51
+ }
52
+
53
+ const message = details
54
+ ? `${options.provider} API key validation failed (${response.status}): ${details}`
55
+ : `${options.provider} API key validation failed (${response.status})`;
56
+ throw new Error(message);
57
+ }
58
+
59
+ /**
60
+ * Validate an API key against a provider models endpoint.
61
+ *
62
+ * Useful for providers where access to specific models may vary by plan and
63
+ * should not block key validation.
64
+ */
65
+ export async function validateApiKeyAgainstModelsEndpoint(options: ModelListValidationOptions): Promise<void> {
66
+ const timeoutSignal = AbortSignal.timeout(VALIDATION_TIMEOUT_MS);
67
+ const signal = options.signal ? AbortSignal.any([options.signal, timeoutSignal]) : timeoutSignal;
68
+
69
+ const response = await fetch(options.modelsUrl, {
70
+ method: "GET",
71
+ headers: {
72
+ Authorization: `Bearer ${options.apiKey}`,
73
+ },
74
+ signal,
75
+ });
76
+
77
+ if (response.ok) {
78
+ return;
79
+ }
80
+
81
+ let details = "";
82
+ try {
83
+ details = (await response.text()).trim();
84
+ } catch {
85
+ // ignore body parse errors, status is enough
86
+ }
87
+
88
+ const message = details
89
+ ? `${options.provider} API key validation failed (${response.status}): ${details}`
90
+ : `${options.provider} API key validation failed (${response.status})`;
91
+ throw new Error(message);
92
+ }