@gajae-code/ai 0.1.1

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 (349) hide show
  1. package/CHANGELOG.md +2644 -0
  2. package/README.md +1181 -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 +641 -0
  16. package/dist/types/cli.d.ts +2 -0
  17. package/dist/types/index.d.ts +49 -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 +71 -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 +237 -0
  29. package/dist/types/provider-models/special.d.ts +16 -0
  30. package/dist/types/providers/amazon-bedrock.d.ts +36 -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 +188 -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/cursor/gen/agent_pb.d.ts +13022 -0
  39. package/dist/types/providers/cursor.d.ts +42 -0
  40. package/dist/types/providers/error-message.d.ts +27 -0
  41. package/dist/types/providers/github-copilot-headers.d.ts +40 -0
  42. package/dist/types/providers/gitlab-duo.d.ts +27 -0
  43. package/dist/types/providers/google-auth.d.ts +24 -0
  44. package/dist/types/providers/google-gemini-cli.d.ts +72 -0
  45. package/dist/types/providers/google-gemini-headers.d.ts +18 -0
  46. package/dist/types/providers/google-shared.d.ts +163 -0
  47. package/dist/types/providers/google-types.d.ts +138 -0
  48. package/dist/types/providers/google-vertex.d.ts +7 -0
  49. package/dist/types/providers/google.d.ts +4 -0
  50. package/dist/types/providers/grammar.d.ts +1 -0
  51. package/dist/types/providers/kimi.d.ts +27 -0
  52. package/dist/types/providers/mock.d.ts +175 -0
  53. package/dist/types/providers/ollama.d.ts +6 -0
  54. package/dist/types/providers/openai-anthropic-shim.d.ts +31 -0
  55. package/dist/types/providers/openai-chat-server-schema.d.ts +814 -0
  56. package/dist/types/providers/openai-chat-server.d.ts +16 -0
  57. package/dist/types/providers/openai-codex/constants.d.ts +26 -0
  58. package/dist/types/providers/openai-codex/request-transformer.d.ts +49 -0
  59. package/dist/types/providers/openai-codex/response-handler.d.ts +17 -0
  60. package/dist/types/providers/openai-codex-responses.d.ts +67 -0
  61. package/dist/types/providers/openai-completions-compat.d.ts +25 -0
  62. package/dist/types/providers/openai-completions.d.ts +33 -0
  63. package/dist/types/providers/openai-responses-server-schema.d.ts +392 -0
  64. package/dist/types/providers/openai-responses-server.d.ts +17 -0
  65. package/dist/types/providers/openai-responses-shared.d.ts +89 -0
  66. package/dist/types/providers/openai-responses.d.ts +32 -0
  67. package/dist/types/providers/pi-native-client.d.ts +13 -0
  68. package/dist/types/providers/pi-native-server.d.ts +68 -0
  69. package/dist/types/providers/register-builtins.d.ts +31 -0
  70. package/dist/types/providers/synthetic.d.ts +26 -0
  71. package/dist/types/providers/transform-messages.d.ts +12 -0
  72. package/dist/types/providers/vision-guard.d.ts +8 -0
  73. package/dist/types/rate-limit-utils.d.ts +19 -0
  74. package/dist/types/stream.d.ts +24 -0
  75. package/dist/types/types.d.ts +746 -0
  76. package/dist/types/usage/claude.d.ts +3 -0
  77. package/dist/types/usage/gemini.d.ts +2 -0
  78. package/dist/types/usage/github-copilot.d.ts +7 -0
  79. package/dist/types/usage/google-antigravity.d.ts +2 -0
  80. package/dist/types/usage/kimi.d.ts +2 -0
  81. package/dist/types/usage/minimax-code.d.ts +2 -0
  82. package/dist/types/usage/openai-codex.d.ts +3 -0
  83. package/dist/types/usage/shared.d.ts +1 -0
  84. package/dist/types/usage/zai.d.ts +2 -0
  85. package/dist/types/usage.d.ts +258 -0
  86. package/dist/types/utils/abort.d.ts +19 -0
  87. package/dist/types/utils/anthropic-auth.d.ts +31 -0
  88. package/dist/types/utils/discovery/antigravity.d.ts +61 -0
  89. package/dist/types/utils/discovery/codex.d.ts +38 -0
  90. package/dist/types/utils/discovery/cursor.d.ts +23 -0
  91. package/dist/types/utils/discovery/gemini.d.ts +25 -0
  92. package/dist/types/utils/discovery/index.d.ts +4 -0
  93. package/dist/types/utils/discovery/openai-compatible.d.ts +72 -0
  94. package/dist/types/utils/event-stream.d.ts +28 -0
  95. package/dist/types/utils/fireworks-model-id.d.ts +10 -0
  96. package/dist/types/utils/foundry.d.ts +1 -0
  97. package/dist/types/utils/h2-fetch.d.ts +22 -0
  98. package/dist/types/utils/http-inspector.d.ts +31 -0
  99. package/dist/types/utils/idle-iterator.d.ts +67 -0
  100. package/dist/types/utils/json-parse.d.ts +10 -0
  101. package/dist/types/utils/oauth/alibaba-coding-plan.d.ts +18 -0
  102. package/dist/types/utils/oauth/anthropic.d.ts +22 -0
  103. package/dist/types/utils/oauth/api-key-login.d.ts +35 -0
  104. package/dist/types/utils/oauth/api-key-validation.d.ts +27 -0
  105. package/dist/types/utils/oauth/callback-server.d.ts +57 -0
  106. package/dist/types/utils/oauth/cerebras.d.ts +1 -0
  107. package/dist/types/utils/oauth/cloudflare-ai-gateway.d.ts +18 -0
  108. package/dist/types/utils/oauth/cursor.d.ts +15 -0
  109. package/dist/types/utils/oauth/deepseek.d.ts +10 -0
  110. package/dist/types/utils/oauth/firepass.d.ts +1 -0
  111. package/dist/types/utils/oauth/fireworks.d.ts +1 -0
  112. package/dist/types/utils/oauth/github-copilot.d.ts +38 -0
  113. package/dist/types/utils/oauth/gitlab-duo.d.ts +3 -0
  114. package/dist/types/utils/oauth/google-antigravity.d.ts +11 -0
  115. package/dist/types/utils/oauth/google-gemini-cli.d.ts +10 -0
  116. package/dist/types/utils/oauth/google-oauth-shared.d.ts +28 -0
  117. package/dist/types/utils/oauth/huggingface.d.ts +19 -0
  118. package/dist/types/utils/oauth/index.d.ts +38 -0
  119. package/dist/types/utils/oauth/kagi.d.ts +17 -0
  120. package/dist/types/utils/oauth/kilo.d.ts +5 -0
  121. package/dist/types/utils/oauth/kimi.d.ts +21 -0
  122. package/dist/types/utils/oauth/litellm.d.ts +18 -0
  123. package/dist/types/utils/oauth/lm-studio.d.ts +17 -0
  124. package/dist/types/utils/oauth/minimax-code.d.ts +28 -0
  125. package/dist/types/utils/oauth/moonshot.d.ts +1 -0
  126. package/dist/types/utils/oauth/nanogpt.d.ts +1 -0
  127. package/dist/types/utils/oauth/nvidia.d.ts +18 -0
  128. package/dist/types/utils/oauth/ollama-cloud.d.ts +2 -0
  129. package/dist/types/utils/oauth/ollama.d.ts +18 -0
  130. package/dist/types/utils/oauth/openai-codex.d.ts +21 -0
  131. package/dist/types/utils/oauth/opencode.d.ts +18 -0
  132. package/dist/types/utils/oauth/parallel.d.ts +17 -0
  133. package/dist/types/utils/oauth/perplexity.d.ts +9 -0
  134. package/dist/types/utils/oauth/pkce.d.ts +8 -0
  135. package/dist/types/utils/oauth/qianfan.d.ts +17 -0
  136. package/dist/types/utils/oauth/qwen-portal.d.ts +19 -0
  137. package/dist/types/utils/oauth/synthetic.d.ts +1 -0
  138. package/dist/types/utils/oauth/tavily.d.ts +17 -0
  139. package/dist/types/utils/oauth/together.d.ts +1 -0
  140. package/dist/types/utils/oauth/types.d.ts +44 -0
  141. package/dist/types/utils/oauth/venice.d.ts +18 -0
  142. package/dist/types/utils/oauth/vercel-ai-gateway.d.ts +18 -0
  143. package/dist/types/utils/oauth/vllm.d.ts +16 -0
  144. package/dist/types/utils/oauth/xiaomi.d.ts +19 -0
  145. package/dist/types/utils/oauth/zai.d.ts +18 -0
  146. package/dist/types/utils/oauth/zenmux.d.ts +1 -0
  147. package/dist/types/utils/overflow.d.ts +54 -0
  148. package/dist/types/utils/parse-bind.d.ts +23 -0
  149. package/dist/types/utils/provider-response.d.ts +3 -0
  150. package/dist/types/utils/retry-after.d.ts +3 -0
  151. package/dist/types/utils/retry.d.ts +26 -0
  152. package/dist/types/utils/schema/adapt.d.ts +24 -0
  153. package/dist/types/utils/schema/compatibility.d.ts +30 -0
  154. package/dist/types/utils/schema/dereference.d.ts +11 -0
  155. package/dist/types/utils/schema/draft.d.ts +10 -0
  156. package/dist/types/utils/schema/equality.d.ts +4 -0
  157. package/dist/types/utils/schema/fields.d.ts +49 -0
  158. package/dist/types/utils/schema/index.d.ts +13 -0
  159. package/dist/types/utils/schema/json-schema-validator.d.ts +12 -0
  160. package/dist/types/utils/schema/meta-validator.d.ts +2 -0
  161. package/dist/types/utils/schema/normalize.d.ts +93 -0
  162. package/dist/types/utils/schema/spill.d.ts +8 -0
  163. package/dist/types/utils/schema/stamps.d.ts +25 -0
  164. package/dist/types/utils/schema/types.d.ts +4 -0
  165. package/dist/types/utils/schema/wire.d.ts +54 -0
  166. package/dist/types/utils/schema/zod-decontaminate.d.ts +31 -0
  167. package/dist/types/utils/sse-debug.d.ts +10 -0
  168. package/dist/types/utils/tool-call-healing.d.ts +71 -0
  169. package/dist/types/utils/tool-choice.d.ts +50 -0
  170. package/dist/types/utils/validation.d.ts +17 -0
  171. package/dist/types/utils.d.ts +28 -0
  172. package/package.json +146 -0
  173. package/src/api-registry.ts +96 -0
  174. package/src/auth-broker/client.ts +358 -0
  175. package/src/auth-broker/index.ts +5 -0
  176. package/src/auth-broker/refresher.ts +127 -0
  177. package/src/auth-broker/remote-store.ts +623 -0
  178. package/src/auth-broker/server.ts +644 -0
  179. package/src/auth-broker/types.ts +127 -0
  180. package/src/auth-broker/wire-schemas.ts +200 -0
  181. package/src/auth-gateway/http.ts +194 -0
  182. package/src/auth-gateway/index.ts +3 -0
  183. package/src/auth-gateway/server.ts +717 -0
  184. package/src/auth-gateway/types.ts +134 -0
  185. package/src/auth-storage.ts +4104 -0
  186. package/src/cli.ts +262 -0
  187. package/src/index.ts +54 -0
  188. package/src/model-cache.ts +129 -0
  189. package/src/model-manager.ts +450 -0
  190. package/src/model-thinking.ts +691 -0
  191. package/src/models.json +73853 -0
  192. package/src/models.json.d.ts +9 -0
  193. package/src/models.ts +56 -0
  194. package/src/prompts/turn-aborted-guidance.md +4 -0
  195. package/src/provider-details.ts +90 -0
  196. package/src/provider-models/bundled-references.ts +38 -0
  197. package/src/provider-models/descriptors.ts +308 -0
  198. package/src/provider-models/google.ts +91 -0
  199. package/src/provider-models/index.ts +5 -0
  200. package/src/provider-models/ollama.ts +153 -0
  201. package/src/provider-models/openai-compat.ts +2275 -0
  202. package/src/provider-models/special.ts +67 -0
  203. package/src/providers/amazon-bedrock.ts +849 -0
  204. package/src/providers/anthropic-messages-server-schema.ts +229 -0
  205. package/src/providers/anthropic-messages-server.ts +677 -0
  206. package/src/providers/anthropic.ts +2696 -0
  207. package/src/providers/aws-credentials.ts +501 -0
  208. package/src/providers/aws-eventstream.ts +185 -0
  209. package/src/providers/aws-sigv4.ts +218 -0
  210. package/src/providers/azure-openai-responses.ts +337 -0
  211. package/src/providers/cursor/gen/agent_pb.ts +15274 -0
  212. package/src/providers/cursor/proto/agent.proto +3526 -0
  213. package/src/providers/cursor/proto/buf.gen.yaml +6 -0
  214. package/src/providers/cursor/proto/buf.yaml +17 -0
  215. package/src/providers/cursor.ts +2561 -0
  216. package/src/providers/error-message.ts +21 -0
  217. package/src/providers/github-copilot-headers.ts +140 -0
  218. package/src/providers/gitlab-duo.ts +372 -0
  219. package/src/providers/google-auth.ts +252 -0
  220. package/src/providers/google-gemini-cli.ts +795 -0
  221. package/src/providers/google-gemini-headers.ts +41 -0
  222. package/src/providers/google-shared.ts +902 -0
  223. package/src/providers/google-types.ts +167 -0
  224. package/src/providers/google-vertex.ts +88 -0
  225. package/src/providers/google.ts +41 -0
  226. package/src/providers/grammar.ts +70 -0
  227. package/src/providers/kimi.ts +52 -0
  228. package/src/providers/mock.ts +500 -0
  229. package/src/providers/ollama.ts +544 -0
  230. package/src/providers/openai-anthropic-shim.ts +138 -0
  231. package/src/providers/openai-chat-server-schema.ts +243 -0
  232. package/src/providers/openai-chat-server.ts +628 -0
  233. package/src/providers/openai-codex/constants.ts +43 -0
  234. package/src/providers/openai-codex/request-transformer.ts +161 -0
  235. package/src/providers/openai-codex/response-handler.ts +81 -0
  236. package/src/providers/openai-codex-responses.ts +2598 -0
  237. package/src/providers/openai-completions-compat.ts +279 -0
  238. package/src/providers/openai-completions.ts +1853 -0
  239. package/src/providers/openai-responses-server-schema.ts +290 -0
  240. package/src/providers/openai-responses-server.ts +1183 -0
  241. package/src/providers/openai-responses-shared.ts +800 -0
  242. package/src/providers/openai-responses.ts +621 -0
  243. package/src/providers/pi-native-client.ts +228 -0
  244. package/src/providers/pi-native-server.ts +210 -0
  245. package/src/providers/register-builtins.ts +412 -0
  246. package/src/providers/synthetic.ts +50 -0
  247. package/src/providers/transform-messages.ts +309 -0
  248. package/src/providers/vision-guard.ts +31 -0
  249. package/src/rate-limit-utils.ts +84 -0
  250. package/src/stream.ts +895 -0
  251. package/src/types.ts +884 -0
  252. package/src/usage/claude.ts +431 -0
  253. package/src/usage/gemini.ts +250 -0
  254. package/src/usage/github-copilot.ts +421 -0
  255. package/src/usage/google-antigravity.ts +201 -0
  256. package/src/usage/kimi.ts +271 -0
  257. package/src/usage/minimax-code.ts +31 -0
  258. package/src/usage/openai-codex.ts +503 -0
  259. package/src/usage/shared.ts +10 -0
  260. package/src/usage/zai.ts +247 -0
  261. package/src/usage.ts +183 -0
  262. package/src/utils/abort.ts +51 -0
  263. package/src/utils/anthropic-auth.ts +87 -0
  264. package/src/utils/discovery/antigravity.ts +261 -0
  265. package/src/utils/discovery/codex.ts +371 -0
  266. package/src/utils/discovery/cursor.ts +306 -0
  267. package/src/utils/discovery/gemini.ts +248 -0
  268. package/src/utils/discovery/index.ts +4 -0
  269. package/src/utils/discovery/openai-compatible.ts +224 -0
  270. package/src/utils/event-stream.ts +142 -0
  271. package/src/utils/fireworks-model-id.ts +30 -0
  272. package/src/utils/foundry.ts +8 -0
  273. package/src/utils/h2-fetch.ts +60 -0
  274. package/src/utils/http-inspector.ts +176 -0
  275. package/src/utils/idle-iterator.ts +250 -0
  276. package/src/utils/json-parse.ts +148 -0
  277. package/src/utils/oauth/alibaba-coding-plan.ts +59 -0
  278. package/src/utils/oauth/anthropic.ts +200 -0
  279. package/src/utils/oauth/api-key-login.ts +87 -0
  280. package/src/utils/oauth/api-key-validation.ts +92 -0
  281. package/src/utils/oauth/callback-server.ts +276 -0
  282. package/src/utils/oauth/cerebras.ts +16 -0
  283. package/src/utils/oauth/cloudflare-ai-gateway.ts +48 -0
  284. package/src/utils/oauth/cursor.ts +157 -0
  285. package/src/utils/oauth/deepseek.ts +53 -0
  286. package/src/utils/oauth/firepass.ts +24 -0
  287. package/src/utils/oauth/fireworks.ts +15 -0
  288. package/src/utils/oauth/github-copilot.ts +362 -0
  289. package/src/utils/oauth/gitlab-duo.ts +123 -0
  290. package/src/utils/oauth/google-antigravity.ts +200 -0
  291. package/src/utils/oauth/google-gemini-cli.ts +256 -0
  292. package/src/utils/oauth/google-oauth-shared.ts +110 -0
  293. package/src/utils/oauth/huggingface.ts +62 -0
  294. package/src/utils/oauth/index.ts +444 -0
  295. package/src/utils/oauth/kagi.ts +47 -0
  296. package/src/utils/oauth/kilo.ts +87 -0
  297. package/src/utils/oauth/kimi.ts +254 -0
  298. package/src/utils/oauth/litellm.ts +47 -0
  299. package/src/utils/oauth/lm-studio.ts +38 -0
  300. package/src/utils/oauth/minimax-code.ts +78 -0
  301. package/src/utils/oauth/moonshot.ts +16 -0
  302. package/src/utils/oauth/nanogpt.ts +15 -0
  303. package/src/utils/oauth/nvidia.ts +70 -0
  304. package/src/utils/oauth/oauth.html +199 -0
  305. package/src/utils/oauth/ollama-cloud.ts +28 -0
  306. package/src/utils/oauth/ollama.ts +47 -0
  307. package/src/utils/oauth/openai-codex.ts +299 -0
  308. package/src/utils/oauth/opencode.ts +49 -0
  309. package/src/utils/oauth/parallel.ts +46 -0
  310. package/src/utils/oauth/perplexity.ts +206 -0
  311. package/src/utils/oauth/pkce.ts +18 -0
  312. package/src/utils/oauth/qianfan.ts +58 -0
  313. package/src/utils/oauth/qwen-portal.ts +60 -0
  314. package/src/utils/oauth/synthetic.ts +16 -0
  315. package/src/utils/oauth/tavily.ts +46 -0
  316. package/src/utils/oauth/together.ts +16 -0
  317. package/src/utils/oauth/types.ts +94 -0
  318. package/src/utils/oauth/venice.ts +59 -0
  319. package/src/utils/oauth/vercel-ai-gateway.ts +47 -0
  320. package/src/utils/oauth/vllm.ts +40 -0
  321. package/src/utils/oauth/xiaomi.ts +137 -0
  322. package/src/utils/oauth/zai.ts +60 -0
  323. package/src/utils/oauth/zenmux.ts +15 -0
  324. package/src/utils/overflow.ts +137 -0
  325. package/src/utils/parse-bind.ts +54 -0
  326. package/src/utils/provider-response.ts +30 -0
  327. package/src/utils/retry-after.ts +110 -0
  328. package/src/utils/retry.ts +54 -0
  329. package/src/utils/schema/CONSTRAINTS.md +164 -0
  330. package/src/utils/schema/adapt.ts +36 -0
  331. package/src/utils/schema/compatibility.ts +435 -0
  332. package/src/utils/schema/dereference.ts +98 -0
  333. package/src/utils/schema/draft.ts +341 -0
  334. package/src/utils/schema/equality.ts +97 -0
  335. package/src/utils/schema/fields.ts +190 -0
  336. package/src/utils/schema/index.ts +13 -0
  337. package/src/utils/schema/json-schema-validator.ts +577 -0
  338. package/src/utils/schema/meta-validator.ts +167 -0
  339. package/src/utils/schema/normalize.ts +1588 -0
  340. package/src/utils/schema/spill.ts +43 -0
  341. package/src/utils/schema/stamps.ts +97 -0
  342. package/src/utils/schema/types.ts +11 -0
  343. package/src/utils/schema/wire.ts +213 -0
  344. package/src/utils/schema/zod-decontaminate.ts +331 -0
  345. package/src/utils/sse-debug.ts +289 -0
  346. package/src/utils/tool-call-healing.ts +271 -0
  347. package/src/utils/tool-choice.ts +99 -0
  348. package/src/utils/validation.ts +1019 -0
  349. package/src/utils.ts +166 -0
@@ -0,0 +1,53 @@
1
+ /**
2
+ * DeepSeek login flow (API key paste against https://api.deepseek.com).
3
+ *
4
+ * Validation hits `GET /v1/models` so it authenticates the key without
5
+ * depending on a specific model being enabled on the account. The previous
6
+ * implementation issued a chat-completion against `deepseek-v4-pro`, which
7
+ * 404s for accounts without that preview model even when the key is valid.
8
+ */
9
+ import { createApiKeyLogin } from "./api-key-login";
10
+ import type { OAuthController, OAuthPrompt } from "./types";
11
+
12
+ const innerLogin = createApiKeyLogin({
13
+ providerLabel: "DeepSeek",
14
+ authUrl: "https://platform.deepseek.com/api_keys",
15
+ instructions: "Create or copy your API key from the DeepSeek dashboard",
16
+ promptMessage: "Paste your DeepSeek API key",
17
+ placeholder: "sk-...",
18
+ validation: {
19
+ kind: "models-endpoint",
20
+ provider: "deepseek",
21
+ modelsUrl: "https://api.deepseek.com/v1/models",
22
+ },
23
+ });
24
+
25
+ /**
26
+ * Normalize a pasted DeepSeek API key.
27
+ *
28
+ * Users frequently copy keys out of `curl` snippets that include the
29
+ * `Authorization: Bearer …` prefix. Strip it so validation does not fail
30
+ * with a confusing 401, and reject obviously empty input early.
31
+ */
32
+ export function normalizeDeepSeekApiKey(raw: string): string {
33
+ const trimmed = raw.trim();
34
+ if (!trimmed) {
35
+ return trimmed; // let the shared factory throw the canonical "API key is required"
36
+ }
37
+ const stripped = trimmed.replace(/^bearer\b\s*/i, "");
38
+ if (!stripped) {
39
+ throw new Error("DeepSeek API key is empty after stripping Bearer prefix");
40
+ }
41
+ return stripped;
42
+ }
43
+
44
+ export const loginDeepSeek = async (options: OAuthController): Promise<string> => {
45
+ const userOnPrompt = options.onPrompt;
46
+ const wrapped: OAuthController = userOnPrompt
47
+ ? {
48
+ ...options,
49
+ onPrompt: async (prompt: OAuthPrompt) => normalizeDeepSeekApiKey(await userOnPrompt(prompt)),
50
+ }
51
+ : options;
52
+ return innerLogin(wrapped);
53
+ };
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Fire Pass login flow.
3
+ *
4
+ * Fire Pass is a Fireworks subscription product whose dedicated `fpk_…` API
5
+ * keys are scoped to the `accounts/fireworks/routers/kimi-k2p6-turbo` router
6
+ * (Kimi K2.6 Turbo). The key does NOT authorize `/v1/models`, so validation
7
+ * pings the chat completions endpoint with the router id directly.
8
+ * See https://docs.fireworks.ai/firepass.
9
+ */
10
+ import { createApiKeyLogin } from "./api-key-login";
11
+
12
+ export const loginFirepass = createApiKeyLogin({
13
+ providerLabel: "Fire Pass",
14
+ authUrl: "https://app.fireworks.ai/settings/users/api-keys",
15
+ instructions: "Create a dedicated Fire Pass API key in the Fireworks dashboard",
16
+ promptMessage: "Paste your Fire Pass API key",
17
+ placeholder: "fpk_...",
18
+ validation: {
19
+ kind: "chat-completions",
20
+ provider: "Fire Pass",
21
+ baseUrl: "https://api.fireworks.ai/inference/v1",
22
+ model: "accounts/fireworks/routers/kimi-k2p6-turbo",
23
+ },
24
+ });
@@ -0,0 +1,15 @@
1
+ /** Fireworks login flow (API key paste against https://api.fireworks.ai/inference/v1). */
2
+ import { createApiKeyLogin } from "./api-key-login";
3
+
4
+ export const loginFireworks = createApiKeyLogin({
5
+ providerLabel: "Fireworks",
6
+ authUrl: "https://app.fireworks.ai/settings/users/api-keys",
7
+ instructions: "Create or copy your Fireworks API key",
8
+ promptMessage: "Paste your Fireworks API key",
9
+ placeholder: "fw_...",
10
+ validation: {
11
+ kind: "models-endpoint",
12
+ provider: "Fireworks",
13
+ modelsUrl: "https://api.fireworks.ai/inference/v1/models",
14
+ },
15
+ });
@@ -0,0 +1,362 @@
1
+ /**
2
+ * GitHub Copilot OAuth flow (opencode OAuth app)
3
+ */
4
+ import { scheduler } from "node:timers/promises";
5
+ import { getBundledModels } from "../../models";
6
+ import type { OAuthCredentials } from "./types";
7
+
8
+ const CLIENT_ID = "Ov23li8tweQw6odWQebz";
9
+
10
+ export const COPILOT_USER_AGENT = "opencode/1.3.15" as const;
11
+
12
+ export const OPENCODE_HEADERS = {
13
+ "User-Agent": COPILOT_USER_AGENT,
14
+ } as const;
15
+
16
+ const INITIAL_POLL_INTERVAL_MULTIPLIER = 1.2;
17
+ const SLOW_DOWN_POLL_INTERVAL_MULTIPLIER = 1.4;
18
+ type DeviceCodeResponse = {
19
+ device_code: string;
20
+ user_code: string;
21
+ verification_uri: string;
22
+ interval: number;
23
+ expires_in: number;
24
+ };
25
+
26
+ type DeviceTokenSuccessResponse = {
27
+ access_token: string;
28
+ token_type?: string;
29
+ scope?: string;
30
+ };
31
+
32
+ type DeviceTokenErrorResponse = {
33
+ error: string;
34
+ error_description?: string;
35
+ interval?: number;
36
+ };
37
+
38
+ type GitHubCopilotApiKeyPayload = {
39
+ token?: unknown;
40
+ enterpriseUrl?: unknown;
41
+ };
42
+
43
+ export type ParsedGitHubCopilotApiKey = {
44
+ accessToken: string;
45
+ enterpriseUrl?: string;
46
+ };
47
+
48
+ const PUBLIC_GITHUB_HOSTS = new Set(["api.github.com", "github.com", "www.github.com"]);
49
+
50
+ function isPublicGitHubHost(host: string): boolean {
51
+ return PUBLIC_GITHUB_HOSTS.has(host.trim().toLowerCase());
52
+ }
53
+
54
+ export function normalizeGitHubCopilotEnterpriseDomain(input: string | undefined): string | undefined {
55
+ const trimmed = input?.trim();
56
+ if (!trimmed) return undefined;
57
+ const normalized = normalizeDomain(trimmed) ?? trimmed.toLowerCase();
58
+ if (!normalized || isPublicGitHubHost(normalized)) return undefined;
59
+ return normalized;
60
+ }
61
+
62
+ export function parseGitHubCopilotApiKey(apiKeyRaw: string): ParsedGitHubCopilotApiKey {
63
+ try {
64
+ const parsed = JSON.parse(apiKeyRaw) as GitHubCopilotApiKeyPayload;
65
+ if (typeof parsed.token === "string") {
66
+ return {
67
+ accessToken: parsed.token,
68
+ enterpriseUrl:
69
+ typeof parsed.enterpriseUrl === "string"
70
+ ? normalizeGitHubCopilotEnterpriseDomain(parsed.enterpriseUrl)
71
+ : undefined,
72
+ };
73
+ }
74
+ } catch {}
75
+
76
+ return { accessToken: apiKeyRaw };
77
+ }
78
+
79
+ export function normalizeDomain(input: string): string | null {
80
+ const trimmed = input.trim();
81
+ if (!trimmed) return null;
82
+ try {
83
+ const url = trimmed.includes("://") ? new URL(trimmed) : new URL(`https://${trimmed}`);
84
+ return url.hostname;
85
+ } catch {
86
+ return null;
87
+ }
88
+ }
89
+
90
+ function getUrls(domain: string): {
91
+ deviceCodeUrl: string;
92
+ accessTokenUrl: string;
93
+ } {
94
+ return {
95
+ deviceCodeUrl: `https://${domain}/login/device/code`,
96
+ accessTokenUrl: `https://${domain}/login/oauth/access_token`,
97
+ };
98
+ }
99
+
100
+ export function getGitHubCopilotBaseUrl(enterpriseDomain?: string): string {
101
+ const normalizedEnterpriseDomain = normalizeGitHubCopilotEnterpriseDomain(enterpriseDomain);
102
+ if (!normalizedEnterpriseDomain) return "https://api.githubcopilot.com";
103
+ const host = normalizedEnterpriseDomain.startsWith("copilot-api.")
104
+ ? normalizedEnterpriseDomain
105
+ : `copilot-api.${normalizedEnterpriseDomain}`;
106
+ return `https://${host}`;
107
+ }
108
+
109
+ async function fetchJson(url: string, init: RequestInit): Promise<unknown> {
110
+ const response = await fetch(url, init);
111
+ if (!response.ok) {
112
+ const text = await response.text();
113
+ throw new Error(`${response.status} ${response.statusText}: ${text}`);
114
+ }
115
+ return response.json();
116
+ }
117
+
118
+ async function startDeviceFlow(domain: string): Promise<DeviceCodeResponse> {
119
+ const urls = getUrls(domain);
120
+ const data = await fetchJson(urls.deviceCodeUrl, {
121
+ method: "POST",
122
+ headers: {
123
+ Accept: "application/json",
124
+ "Content-Type": "application/json",
125
+ ...OPENCODE_HEADERS,
126
+ },
127
+ body: JSON.stringify({
128
+ client_id: CLIENT_ID,
129
+ scope: "read:user",
130
+ }),
131
+ });
132
+
133
+ if (!data || typeof data !== "object") {
134
+ throw new Error("Invalid device code response");
135
+ }
136
+
137
+ const deviceCode = (data as Record<string, unknown>).device_code;
138
+ const userCode = (data as Record<string, unknown>).user_code;
139
+ const verificationUri = (data as Record<string, unknown>).verification_uri;
140
+ const interval = (data as Record<string, unknown>).interval;
141
+ const expiresIn = (data as Record<string, unknown>).expires_in;
142
+
143
+ if (
144
+ typeof deviceCode !== "string" ||
145
+ typeof userCode !== "string" ||
146
+ typeof verificationUri !== "string" ||
147
+ typeof interval !== "number" ||
148
+ typeof expiresIn !== "number"
149
+ ) {
150
+ throw new Error("Invalid device code response fields");
151
+ }
152
+
153
+ return {
154
+ device_code: deviceCode,
155
+ user_code: userCode,
156
+ verification_uri: verificationUri,
157
+ interval,
158
+ expires_in: expiresIn,
159
+ };
160
+ }
161
+
162
+ async function pollForGitHubAccessToken(
163
+ domain: string,
164
+ deviceCode: string,
165
+ intervalSeconds: number,
166
+ expiresIn: number,
167
+ signal?: AbortSignal,
168
+ pollIntervalFloorMs = 1000,
169
+ pollIntervalScaleMs = 1000,
170
+ ) {
171
+ const urls = getUrls(domain);
172
+ const deadline = Date.now() + expiresIn * 1000;
173
+ let intervalMs = Math.max(pollIntervalFloorMs, Math.floor(intervalSeconds * pollIntervalScaleMs));
174
+ let intervalMultiplier = INITIAL_POLL_INTERVAL_MULTIPLIER;
175
+ let slowDownResponses = 0;
176
+
177
+ while (Date.now() < deadline) {
178
+ if (signal?.aborted) {
179
+ throw new Error("Login cancelled");
180
+ }
181
+
182
+ const remainingMs = deadline - Date.now();
183
+ const waitMs = Math.min(Math.ceil(intervalMs * intervalMultiplier), remainingMs);
184
+ try {
185
+ await scheduler.wait(waitMs, { signal });
186
+ } catch {
187
+ throw new Error("Login cancelled");
188
+ }
189
+
190
+ const raw = await fetchJson(urls.accessTokenUrl, {
191
+ method: "POST",
192
+ headers: {
193
+ Accept: "application/json",
194
+ "Content-Type": "application/json",
195
+ ...OPENCODE_HEADERS,
196
+ },
197
+ body: JSON.stringify({
198
+ client_id: CLIENT_ID,
199
+ device_code: deviceCode,
200
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
201
+ }),
202
+ });
203
+
204
+ if (raw && typeof raw === "object" && typeof (raw as DeviceTokenSuccessResponse).access_token === "string") {
205
+ return (raw as DeviceTokenSuccessResponse).access_token;
206
+ }
207
+
208
+ if (raw && typeof raw === "object" && typeof (raw as DeviceTokenErrorResponse).error === "string") {
209
+ const { error, error_description: description, interval } = raw as DeviceTokenErrorResponse;
210
+ if (error === "authorization_pending") {
211
+ continue;
212
+ }
213
+
214
+ if (error === "slow_down") {
215
+ slowDownResponses += 1;
216
+ intervalMs =
217
+ typeof interval === "number" && interval > 0
218
+ ? Math.max(pollIntervalFloorMs, interval * pollIntervalScaleMs)
219
+ : Math.max(pollIntervalFloorMs, intervalMs + 5 * pollIntervalScaleMs);
220
+ intervalMultiplier = SLOW_DOWN_POLL_INTERVAL_MULTIPLIER;
221
+ continue;
222
+ }
223
+
224
+ const descriptionSuffix = description ? `: ${description}` : "";
225
+ throw new Error(`Device flow failed: ${error}${descriptionSuffix}`);
226
+ }
227
+ }
228
+
229
+ if (slowDownResponses > 0) {
230
+ throw new Error(
231
+ "Device flow timed out after one or more slow_down responses. This is often caused by clock drift in WSL or VM environments. Please sync or restart the VM clock and try again.",
232
+ );
233
+ }
234
+
235
+ throw new Error("Device flow timed out");
236
+ }
237
+
238
+ /** Far-future expiry (10 years). GitHub OAuth tokens are long-lived; no JWT exchange needed. */
239
+ const FAR_FUTURE_MS = Date.now() + 10 * 365.25 * 24 * 60 * 60 * 1000;
240
+
241
+ /**
242
+ * Refresh GitHub Copilot token.
243
+ * With the opencode OAuth flow, the GitHub token is used directly — no JWT exchange needed.
244
+ */
245
+ export function refreshGitHubCopilotToken(refreshToken: string, enterpriseDomain?: string): OAuthCredentials {
246
+ return {
247
+ refresh: refreshToken,
248
+ access: refreshToken,
249
+ expires: FAR_FUTURE_MS,
250
+ enterpriseUrl: enterpriseDomain,
251
+ };
252
+ }
253
+
254
+ /**
255
+ * Enable a model for the user's GitHub Copilot account.
256
+ * This is required for some models (like Anthropic model, Grok) before they can be used.
257
+ */
258
+ async function enableGitHubCopilotModel(token: string, modelId: string, enterpriseDomain?: string): Promise<boolean> {
259
+ const baseUrl = getGitHubCopilotBaseUrl(enterpriseDomain);
260
+ const url = `${baseUrl}/models/${modelId}/policy`;
261
+
262
+ try {
263
+ const response = await fetch(url, {
264
+ method: "POST",
265
+ headers: {
266
+ "Content-Type": "application/json",
267
+ Authorization: `Bearer ${token}`,
268
+ ...OPENCODE_HEADERS,
269
+ "openai-intent": "chat-policy",
270
+ "x-interaction-type": "chat-policy",
271
+ },
272
+ body: JSON.stringify({ state: "enabled" }),
273
+ });
274
+ return response.ok;
275
+ } catch {
276
+ return false;
277
+ }
278
+ }
279
+
280
+ /**
281
+ * Enable all known GitHub Copilot models that may require policy acceptance.
282
+ * Called after successful login to ensure all models are available.
283
+ */
284
+ async function enableAllGitHubCopilotModels(
285
+ token: string,
286
+ enterpriseDomain?: string,
287
+ onProgress?: (model: string, success: boolean) => void,
288
+ ): Promise<void> {
289
+ const models = getBundledModels("github-copilot");
290
+ const BATCH_SIZE = 5;
291
+ for (let i = 0; i < models.length; i += BATCH_SIZE) {
292
+ const batch = models.slice(i, i + BATCH_SIZE);
293
+ await Promise.all(
294
+ batch.map(async model => {
295
+ const success = await enableGitHubCopilotModel(token, model.id, enterpriseDomain);
296
+ onProgress?.(model.id, success);
297
+ }),
298
+ );
299
+ }
300
+ }
301
+
302
+ /**
303
+ * Login with GitHub Copilot OAuth (device code flow)
304
+ *
305
+ * @param options.onAuth - Callback with URL and optional instructions (user code)
306
+ * @param options.onPrompt - Callback to prompt user for input
307
+ * @param options.onProgress - Optional progress callback
308
+ * @param options.signal - Optional AbortSignal for cancellation
309
+ */
310
+ export async function loginGitHubCopilot(options: {
311
+ onAuth: (url: string, instructions?: string) => void;
312
+ onPrompt: (prompt: { message: string; placeholder?: string; allowEmpty?: boolean }) => Promise<string>;
313
+ onProgress?: (message: string) => void;
314
+ signal?: AbortSignal;
315
+ pollIntervalFloorMs?: number;
316
+ pollIntervalScaleMs?: number;
317
+ }): Promise<OAuthCredentials> {
318
+ const input = await options.onPrompt({
319
+ message: "GitHub Enterprise URL/domain (blank for github.com)",
320
+ placeholder: "company.ghe.com",
321
+ allowEmpty: true,
322
+ });
323
+
324
+ if (options.signal?.aborted) {
325
+ throw new Error("Login cancelled");
326
+ }
327
+
328
+ const trimmed = input.trim();
329
+ const normalizedDomain = normalizeDomain(input);
330
+ if (trimmed && !normalizedDomain) {
331
+ throw new Error("Invalid GitHub Enterprise URL/domain");
332
+ }
333
+ const enterpriseDomain = normalizeGitHubCopilotEnterpriseDomain(normalizedDomain ?? undefined);
334
+ const domain =
335
+ normalizedDomain && isPublicGitHubHost(normalizedDomain) ? "github.com" : (normalizedDomain ?? "github.com");
336
+
337
+ const device = await startDeviceFlow(domain);
338
+ options.onAuth(device.verification_uri, `Enter code: ${device.user_code}`);
339
+
340
+ const githubAccessToken = await pollForGitHubAccessToken(
341
+ domain,
342
+ device.device_code,
343
+ device.interval,
344
+ device.expires_in,
345
+ options.signal,
346
+ options.pollIntervalFloorMs,
347
+ options.pollIntervalScaleMs,
348
+ );
349
+
350
+ // With opencode OAuth, the GitHub token is used directly for all API requests
351
+ const credentials: OAuthCredentials = {
352
+ refresh: githubAccessToken,
353
+ access: githubAccessToken,
354
+ expires: FAR_FUTURE_MS,
355
+ enterpriseUrl: enterpriseDomain ?? undefined,
356
+ };
357
+
358
+ // Enable all models after successful login
359
+ options.onProgress?.("Enabling models...");
360
+ await enableAllGitHubCopilotModels(githubAccessToken, enterpriseDomain ?? undefined);
361
+ return credentials;
362
+ }
@@ -0,0 +1,123 @@
1
+ import { clearGitLabDuoDirectAccessCache } from "../../providers/gitlab-duo";
2
+ import { OAuthCallbackFlow } from "./callback-server";
3
+ import { generatePKCE } from "./pkce";
4
+ import type { OAuthCredentials, OAuthLoginCallbacks } from "./types";
5
+
6
+ const GITLAB_COM_URL = "https://gitlab.com";
7
+ const BUNDLED_CLIENT_ID = "da4edff2e6ebd2bc3208611e2768bc1c1dd7be791dc5ff26ca34ca9ee44f7d4b";
8
+ const OAUTH_SCOPES = ["api"];
9
+ const CALLBACK_PORT = 8080;
10
+ const CALLBACK_PATH = "/callback";
11
+
12
+ interface PKCEPair {
13
+ verifier: string;
14
+ challenge: string;
15
+ }
16
+
17
+ function mapTokenResponse(payload: {
18
+ access_token?: string;
19
+ refresh_token?: string;
20
+ expires_in?: number;
21
+ created_at?: number;
22
+ }): OAuthCredentials {
23
+ if (!payload.access_token || !payload.refresh_token || typeof payload.expires_in !== "number") {
24
+ throw new Error("GitLab OAuth token response missing required fields");
25
+ }
26
+
27
+ const createdAtMs =
28
+ typeof payload.created_at === "number" && Number.isFinite(payload.created_at)
29
+ ? payload.created_at * 1000
30
+ : Date.now();
31
+
32
+ return {
33
+ access: payload.access_token,
34
+ refresh: payload.refresh_token,
35
+ expires: createdAtMs + payload.expires_in * 1000 - 5 * 60 * 1000,
36
+ };
37
+ }
38
+
39
+ class GitLabDuoOAuthFlow extends OAuthCallbackFlow {
40
+ #pkce: PKCEPair;
41
+
42
+ constructor(ctrl: OAuthLoginCallbacks, pkce: PKCEPair) {
43
+ super(ctrl, CALLBACK_PORT, CALLBACK_PATH);
44
+ this.#pkce = pkce;
45
+ }
46
+
47
+ override async generateAuthUrl(state: string, redirectUri: string): Promise<{ url: string; instructions?: string }> {
48
+ const authParams = new URLSearchParams({
49
+ client_id: BUNDLED_CLIENT_ID,
50
+ redirect_uri: redirectUri,
51
+ response_type: "code",
52
+ scope: OAUTH_SCOPES.join(" "),
53
+ code_challenge: this.#pkce.challenge,
54
+ code_challenge_method: "S256",
55
+ state,
56
+ });
57
+
58
+ return {
59
+ url: `${GITLAB_COM_URL}/oauth/authorize?${authParams.toString()}`,
60
+ instructions: "Complete GitLab login in browser. Authentication will finish automatically.",
61
+ };
62
+ }
63
+
64
+ override async exchangeToken(code: string, _state: string, redirectUri: string): Promise<OAuthCredentials> {
65
+ const response = await fetch(`${GITLAB_COM_URL}/oauth/token`, {
66
+ method: "POST",
67
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
68
+ body: new URLSearchParams({
69
+ client_id: BUNDLED_CLIENT_ID,
70
+ grant_type: "authorization_code",
71
+ code,
72
+ code_verifier: this.#pkce.verifier,
73
+ redirect_uri: redirectUri,
74
+ }).toString(),
75
+ });
76
+
77
+ if (!response.ok) {
78
+ throw new Error(`GitLab OAuth token exchange failed: ${response.status} ${await response.text()}`);
79
+ }
80
+
81
+ clearGitLabDuoDirectAccessCache();
82
+ return mapTokenResponse(
83
+ (await response.json()) as {
84
+ access_token?: string;
85
+ refresh_token?: string;
86
+ expires_in?: number;
87
+ created_at?: number;
88
+ },
89
+ );
90
+ }
91
+ }
92
+
93
+ export async function loginGitLabDuo(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {
94
+ const pkce = await generatePKCE();
95
+ const flow = new GitLabDuoOAuthFlow(callbacks, pkce);
96
+ return flow.login();
97
+ }
98
+
99
+ export async function refreshGitLabDuoToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {
100
+ const response = await fetch(`${GITLAB_COM_URL}/oauth/token`, {
101
+ method: "POST",
102
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
103
+ body: new URLSearchParams({
104
+ client_id: BUNDLED_CLIENT_ID,
105
+ grant_type: "refresh_token",
106
+ refresh_token: credentials.refresh,
107
+ }).toString(),
108
+ });
109
+
110
+ if (!response.ok) {
111
+ throw new Error(`GitLab OAuth refresh failed: ${response.status} ${await response.text()}`);
112
+ }
113
+
114
+ clearGitLabDuoDirectAccessCache();
115
+ return mapTokenResponse(
116
+ (await response.json()) as {
117
+ access_token?: string;
118
+ refresh_token?: string;
119
+ expires_in?: number;
120
+ created_at?: number;
121
+ },
122
+ );
123
+ }