refactor(cli/providers): flatten — Effect-native handlers end-to-end (#25537)

This commit is contained in:
Kit Langton
2026-05-03 15:42:57 +00:00
committed by GitHub
parent df7dd06a0f
commit 40dc2fa3c1
+50 -63
View File
@@ -6,8 +6,6 @@ import * as prompts from "@clack/prompts"
import { UI } from "../ui" import { UI } from "../ui"
import { ModelsDev } from "@/provider/models" import { ModelsDev } from "@/provider/models"
const getModels = () => AppRuntime.runPromise(ModelsDev.Service.use((s) => s.get()))
const refreshModels = () => AppRuntime.runPromise(ModelsDev.Service.use((s) => s.refresh(true)))
import { map, pipe, sortBy, values } from "remeda" import { map, pipe, sortBy, values } from "remeda"
import path from "path" import path from "path"
import os from "os" import os from "os"
@@ -241,14 +239,14 @@ export const ProvidersListCommand = effectCmd({
handler: Effect.fn("Cli.providers.list")(function* (_args) { handler: Effect.fn("Cli.providers.list")(function* (_args) {
const authSvc = yield* Auth.Service const authSvc = yield* Auth.Service
const modelsDev = yield* ModelsDev.Service const modelsDev = yield* ModelsDev.Service
yield* Effect.promise(async () => {
UI.empty() UI.empty()
const authPath = path.join(Global.Path.data, "auth.json") const authPath = path.join(Global.Path.data, "auth.json")
const homedir = os.homedir() const homedir = os.homedir()
const displayPath = authPath.startsWith(homedir) ? authPath.replace(homedir, "~") : authPath const displayPath = authPath.startsWith(homedir) ? authPath.replace(homedir, "~") : authPath
prompts.intro(`Credentials ${UI.Style.TEXT_DIM}${displayPath}`) prompts.intro(`Credentials ${UI.Style.TEXT_DIM}${displayPath}`)
const results = Object.entries(await Effect.runPromise(authSvc.all())) const results = Object.entries(yield* Effect.orDie(authSvc.all()))
const database = await Effect.runPromise(modelsDev.get()) const database = yield* modelsDev.get()
for (const [providerID, result] of results) { for (const [providerID, result] of results) {
const name = database[providerID]?.name || providerID const name = database[providerID]?.name || providerID
@@ -280,7 +278,6 @@ export const ProvidersListCommand = effectCmd({
prompts.outro(`${activeEnvVars.length} environment variable` + (activeEnvVars.length === 1 ? "" : "s")) prompts.outro(`${activeEnvVars.length} environment variable` + (activeEnvVars.length === 1 ? "" : "s"))
} }
})
}), }),
}) })
@@ -306,56 +303,47 @@ export const ProvidersLoginCommand = effectCmd({
handler: Effect.fn("Cli.providers.login")(function* (args) { handler: Effect.fn("Cli.providers.login")(function* (args) {
const cfgSvc = yield* Config.Service const cfgSvc = yield* Config.Service
const pluginSvc = yield* Plugin.Service const pluginSvc = yield* Plugin.Service
yield* Effect.promise(async () => { const modelsDev = yield* ModelsDev.Service
const authSvc = yield* Auth.Service
UI.empty() UI.empty()
prompts.intro("Add credential") prompts.intro("Add credential")
if (args.url) { if (args.url) {
const url = args.url.replace(/\/+$/, "") const url = args.url.replace(/\/+$/, "")
const wellknown = (await fetch(`${url}/.well-known/opencode`).then((x) => x.json())) as { const wellknown = (yield* Effect.promise(() =>
auth: { command: string[]; env: string } fetch(`${url}/.well-known/opencode`).then((x) => x.json()),
} )) as { auth: { command: string[]; env: string } }
prompts.log.info(`Running \`${wellknown.auth.command.join(" ")}\``) prompts.log.info(`Running \`${wellknown.auth.command.join(" ")}\``)
const proc = Process.spawn(wellknown.auth.command, { const proc = Process.spawn(wellknown.auth.command, { stdout: "pipe", stderr: "inherit" })
stdout: "pipe",
stderr: "inherit",
})
if (!proc.stdout) { if (!proc.stdout) {
prompts.log.error("Failed") prompts.log.error("Failed")
prompts.outro("Done") prompts.outro("Done")
return return
} }
const [exit, token] = await Promise.all([proc.exited, text(proc.stdout)]) const [exit, token] = yield* Effect.promise(() => Promise.all([proc.exited, text(proc.stdout!)]))
if (exit !== 0) { if (exit !== 0) {
prompts.log.error("Failed") prompts.log.error("Failed")
prompts.outro("Done") prompts.outro("Done")
return return
} }
await put(url, { yield* Effect.orDie(authSvc.set(url, { type: "wellknown", key: wellknown.auth.env, token: token.trim() }))
type: "wellknown",
key: wellknown.auth.env,
token: token.trim(),
})
prompts.log.success("Logged into " + url) prompts.log.success("Logged into " + url)
prompts.outro("Done") prompts.outro("Done")
return return
} }
await refreshModels().catch(() => {}) yield* Effect.ignore(modelsDev.refresh(true))
const config = await Effect.runPromise(cfgSvc.get()) const config = yield* cfgSvc.get()
const disabled = new Set(config.disabled_providers ?? []) const disabled = new Set(config.disabled_providers ?? [])
const enabled = config.enabled_providers ? new Set(config.enabled_providers) : undefined const enabled = config.enabled_providers ? new Set(config.enabled_providers) : undefined
const providers = await getModels().then((x) => { const allProviders = yield* modelsDev.get()
const filtered: Record<string, (typeof x)[string]> = {} const providers: Record<string, (typeof allProviders)[string]> = {}
for (const [key, value] of Object.entries(x)) { for (const [key, value] of Object.entries(allProviders)) {
if ((enabled ? enabled.has(key) : true) && !disabled.has(key)) { if ((enabled ? enabled.has(key) : true) && !disabled.has(key)) providers[key] = value
filtered[key] = value
} }
} const hooks = yield* pluginSvc.list()
return filtered
})
const hooks = await Effect.runPromise(pluginSvc.list())
const priority: Record<string, number> = { const priority: Record<string, number> = {
opencode: 0, opencode: 0,
@@ -409,38 +397,38 @@ export const ProvidersLoginCommand = effectCmd({
} }
provider = match.value provider = match.value
} else { } else {
const selected = await prompts.autocomplete({ const selected = yield* Effect.promise(() =>
prompts.autocomplete({
message: "Select provider", message: "Select provider",
maxItems: 8, maxItems: 8,
options: [ options: [...options, { value: "other", label: "Other" }],
...options, }),
{ )
value: "other", if (prompts.isCancel(selected)) yield* Effect.die(new UI.CancelledError())
label: "Other",
},
],
})
if (prompts.isCancel(selected)) throw new UI.CancelledError()
provider = selected as string provider = selected as string
} }
const plugin = hooks.findLast((x) => x.auth?.provider === provider) const plugin = hooks.findLast((x) => x.auth?.provider === provider)
if (plugin && plugin.auth) { if (plugin && plugin.auth) {
const handled = await handlePluginAuth({ auth: plugin.auth }, provider, args.method) const handled = yield* Effect.promise(() => handlePluginAuth({ auth: plugin.auth! }, provider, args.method))
if (handled) return if (handled) return
} }
if (provider === "other") { if (provider === "other") {
const custom = await prompts.text({ const custom = yield* Effect.promise(() =>
prompts.text({
message: "Enter provider id", message: "Enter provider id",
validate: (x) => (x && x.match(/^[0-9a-z-]+$/) ? undefined : "a-z, 0-9 and hyphens only"), validate: (x) => (x && x.match(/^[0-9a-z-]+$/) ? undefined : "a-z, 0-9 and hyphens only"),
}) }),
if (prompts.isCancel(custom)) throw new UI.CancelledError() )
provider = custom.replace(/^@ai-sdk\//, "") if (prompts.isCancel(custom)) yield* Effect.die(new UI.CancelledError())
provider = (custom as string).replace(/^@ai-sdk\//, "")
const customPlugin = hooks.findLast((x) => x.auth?.provider === provider) const customPlugin = hooks.findLast((x) => x.auth?.provider === provider)
if (customPlugin && customPlugin.auth) { if (customPlugin && customPlugin.auth) {
const handled = await handlePluginAuth({ auth: customPlugin.auth }, provider, args.method) const handled = yield* Effect.promise(() =>
handlePluginAuth({ auth: customPlugin.auth! }, provider, args.method),
)
if (handled) return if (handled) return
} }
@@ -473,18 +461,16 @@ export const ProvidersLoginCommand = effectCmd({
) )
} }
const key = await prompts.password({ const key = yield* Effect.promise(() =>
prompts.password({
message: "Enter your API key", message: "Enter your API key",
validate: (x) => (x && x.length > 0 ? undefined : "Required"), validate: (x) => (x && x.length > 0 ? undefined : "Required"),
}) }),
if (prompts.isCancel(key)) throw new UI.CancelledError() )
await put(provider, { if (prompts.isCancel(key)) yield* Effect.die(new UI.CancelledError())
type: "api", yield* Effect.orDie(authSvc.set(provider, { type: "api", key: key as string }))
key,
})
prompts.outro("Done") prompts.outro("Done")
})
}), }),
}) })
@@ -496,26 +482,27 @@ export const ProvidersLogoutCommand = effectCmd({
handler: Effect.fn("Cli.providers.logout")(function* (_args) { handler: Effect.fn("Cli.providers.logout")(function* (_args) {
const authSvc = yield* Auth.Service const authSvc = yield* Auth.Service
const modelsDev = yield* ModelsDev.Service const modelsDev = yield* ModelsDev.Service
yield* Effect.promise(async () => {
UI.empty() UI.empty()
const credentials: Array<[string, Auth.Info]> = Object.entries(await Effect.runPromise(authSvc.all())) const credentials: Array<[string, Auth.Info]> = Object.entries(yield* Effect.orDie(authSvc.all()))
prompts.intro("Remove credential") prompts.intro("Remove credential")
if (credentials.length === 0) { if (credentials.length === 0) {
prompts.log.error("No credentials found") prompts.log.error("No credentials found")
return return
} }
const database = await Effect.runPromise(modelsDev.get()) const database = yield* modelsDev.get()
const selected = await prompts.select({ const selected = yield* Effect.promise(() =>
prompts.select({
message: "Select provider", message: "Select provider",
options: credentials.map(([key, value]) => ({ options: credentials.map(([key, value]) => ({
label: (database[key]?.name || key) + UI.Style.TEXT_DIM + " (" + value.type + ")", label: (database[key]?.name || key) + UI.Style.TEXT_DIM + " (" + value.type + ")",
value: key, value: key,
})), })),
}) }),
if (prompts.isCancel(selected)) throw new UI.CancelledError() )
if (prompts.isCancel(selected)) yield* Effect.die(new UI.CancelledError())
const providerID = selected as string const providerID = selected as string
await Effect.runPromise(authSvc.remove(providerID)) yield* Effect.orDie(authSvc.remove(providerID))
prompts.outro("Logout successful") prompts.outro("Logout successful")
})
}), }),
}) })