provider.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import { App } from "../../app/app"
  2. import { AuthAnthropic } from "../../auth/anthropic"
  3. import { AuthKeys } from "../../auth/keys"
  4. import { cmd } from "./cmd"
  5. import * as prompts from "@clack/prompts"
  6. import open from "open"
  7. import { VERSION } from "../version"
  8. import { Provider } from "../../provider/provider"
  9. export const ProviderCommand = cmd({
  10. command: "provider",
  11. builder: (yargs) =>
  12. yargs
  13. .command(ProviderAddCommand)
  14. .command(ProviderListCommand)
  15. .demandCommand(),
  16. describe: "initialize opencode",
  17. async handler() {},
  18. })
  19. export const ProviderListCommand = cmd({
  20. command: "list",
  21. aliases: ["ls"],
  22. describe: "list providers",
  23. async handler() {
  24. await App.provide({ cwd: process.cwd(), version: VERSION }, async () => {
  25. prompts.intro("Providers")
  26. const providers = await Provider.list().then((x) => Object.values(x))
  27. for (const value of providers) {
  28. prompts.log.success(value.info.name + " (" + value.source + ")")
  29. }
  30. prompts.outro(`${providers.length} configured`)
  31. })
  32. },
  33. })
  34. export const ProviderAddCommand = cmd({
  35. command: "add",
  36. describe: "add credentials for various providers",
  37. async handler() {
  38. await App.provide({ cwd: process.cwd(), version: VERSION }, async () => {
  39. const providers = await Provider.list()
  40. prompts.intro("Add provider")
  41. const provider = await prompts.select({
  42. message: "Select",
  43. maxItems: 2,
  44. options: [
  45. {
  46. label: "Anthropic",
  47. value: "anthropic",
  48. hint: providers["anthropic"] ? "configured" : "",
  49. },
  50. {
  51. label: "OpenAI",
  52. value: "openai",
  53. hint: providers["openai"] ? "configured" : "",
  54. },
  55. {
  56. label: "Google",
  57. value: "google",
  58. hint: providers["google"] ? "configured" : "",
  59. },
  60. ],
  61. })
  62. if (prompts.isCancel(provider)) return
  63. if (provider === "anthropic") {
  64. const method = await prompts.select({
  65. message: "Login method",
  66. options: [
  67. {
  68. label: "Claude Pro/Max",
  69. value: "oauth",
  70. },
  71. {
  72. label: "API Key",
  73. value: "api",
  74. },
  75. ],
  76. })
  77. if (prompts.isCancel(method)) return
  78. if (method === "oauth") {
  79. // some weird bug where program exits without this
  80. await new Promise((resolve) => setTimeout(resolve, 10))
  81. const { url, verifier } = await AuthAnthropic.authorize()
  82. prompts.note("Opening browser...")
  83. await open(url)
  84. prompts.log.info(url)
  85. const code = await prompts.text({
  86. message: "Paste the authorization code here: ",
  87. validate: (x) => (x.length > 0 ? undefined : "Required"),
  88. })
  89. if (prompts.isCancel(code)) return
  90. await AuthAnthropic.exchange(code, verifier)
  91. .then(() => {
  92. prompts.log.success("Login successful")
  93. })
  94. .catch(() => {
  95. prompts.log.error("Invalid code")
  96. })
  97. prompts.outro("Done")
  98. return
  99. }
  100. }
  101. const key = await prompts.password({
  102. message: "Enter your API key",
  103. validate: (x) => (x.length > 0 ? undefined : "Required"),
  104. })
  105. if (prompts.isCancel(key)) return
  106. await AuthKeys.set(provider, key)
  107. prompts.outro("Done")
  108. })
  109. },
  110. })