mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-19 16:54:22 +01:00
feat(provider): add GitHub Enterprise support for Copilot (#2522)
Co-authored-by: Jon-Mikkel Korsvik <48263282+jkorsvik@users.noreply.github.com> Co-authored-by: GitHub Action <action@github.com> Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
This commit is contained in:
@@ -10,6 +10,7 @@ export namespace Auth {
|
|||||||
refresh: z.string(),
|
refresh: z.string(),
|
||||||
access: z.string(),
|
access: z.string(),
|
||||||
expires: z.number(),
|
expires: z.number(),
|
||||||
|
enterpriseUrl: z.string().optional(),
|
||||||
})
|
})
|
||||||
.meta({ ref: "OAuth" })
|
.meta({ ref: "OAuth" })
|
||||||
|
|
||||||
|
|||||||
@@ -102,178 +102,223 @@ export const AuthLoginCommand = cmd({
|
|||||||
prompts.outro("Done")
|
prompts.outro("Done")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
await ModelsDev.refresh().catch(() => {})
|
await ModelsDev.refresh().catch(() => {})
|
||||||
const providers = await ModelsDev.get()
|
const providers = await ModelsDev.get()
|
||||||
const priority: Record<string, number> = {
|
const priority: Record<string, number> = {
|
||||||
opencode: 0,
|
opencode: 0,
|
||||||
anthropic: 1,
|
anthropic: 1,
|
||||||
"github-copilot": 2,
|
"github-copilot": 2,
|
||||||
openai: 3,
|
openai: 3,
|
||||||
google: 4,
|
google: 4,
|
||||||
openrouter: 5,
|
openrouter: 5,
|
||||||
vercel: 6,
|
vercel: 6,
|
||||||
}
|
}
|
||||||
let provider = await prompts.autocomplete({
|
let provider = await prompts.autocomplete({
|
||||||
message: "Select provider",
|
message: "Select provider",
|
||||||
maxItems: 8,
|
maxItems: 8,
|
||||||
options: [
|
options: [
|
||||||
...pipe(
|
...pipe(
|
||||||
providers,
|
providers,
|
||||||
values(),
|
values(),
|
||||||
sortBy(
|
sortBy(
|
||||||
(x) => priority[x.id] ?? 99,
|
(x) => priority[x.id] ?? 99,
|
||||||
(x) => x.name ?? x.id,
|
(x) => x.name ?? x.id,
|
||||||
),
|
|
||||||
map((x) => ({
|
|
||||||
label: x.name,
|
|
||||||
value: x.id,
|
|
||||||
hint: priority[x.id] <= 1 ? "recommended" : undefined,
|
|
||||||
})),
|
|
||||||
),
|
),
|
||||||
{
|
map((x) => ({
|
||||||
value: "other",
|
label: x.name,
|
||||||
label: "Other",
|
value: x.id,
|
||||||
},
|
hint: priority[x.id] <= 1 ? "recommended" : undefined,
|
||||||
],
|
})),
|
||||||
})
|
),
|
||||||
|
{
|
||||||
|
value: "other",
|
||||||
|
label: "Other",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
if (prompts.isCancel(provider)) throw new UI.CancelledError()
|
if (prompts.isCancel(provider)) throw new UI.CancelledError()
|
||||||
|
|
||||||
const plugin = await Plugin.list().then((x) => x.find((x) => x.auth?.provider === provider))
|
const plugin = await Plugin.list().then((x) => x.find((x) => x.auth?.provider === provider))
|
||||||
if (plugin && plugin.auth) {
|
if (plugin && plugin.auth) {
|
||||||
let index = 0
|
let index = 0
|
||||||
if (plugin.auth.methods.length > 1) {
|
if (plugin.auth.methods.length > 1) {
|
||||||
const method = await prompts.select({
|
const method = await prompts.select({
|
||||||
message: "Login method",
|
message: "Login method",
|
||||||
options: [
|
options: [
|
||||||
...plugin.auth.methods.map((x, index) => ({
|
...plugin.auth.methods.map((x, index) => ({
|
||||||
label: x.label,
|
label: x.label,
|
||||||
value: index.toString(),
|
value: index.toString(),
|
||||||
})),
|
})),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
if (prompts.isCancel(method)) throw new UI.CancelledError()
|
if (prompts.isCancel(method)) throw new UI.CancelledError()
|
||||||
index = parseInt(method)
|
index = parseInt(method)
|
||||||
}
|
}
|
||||||
const method = plugin.auth.methods[index]
|
const method = plugin.auth.methods[index]
|
||||||
if (method.type === "oauth") {
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 10))
|
|
||||||
const authorize = await method.authorize()
|
|
||||||
|
|
||||||
if (authorize.url) {
|
// Handle prompts for all auth types
|
||||||
prompts.log.info("Go to: " + authorize.url)
|
await new Promise((resolve) => setTimeout(resolve, 10))
|
||||||
|
const inputs: Record<string, string> = {}
|
||||||
|
if (method.prompts) {
|
||||||
|
for (const prompt of method.prompts) {
|
||||||
|
if (prompt.condition && !prompt.condition(inputs)) {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
if (prompt.type === "select") {
|
||||||
if (authorize.method === "auto") {
|
const value = await prompts.select({
|
||||||
if (authorize.instructions) {
|
message: prompt.message,
|
||||||
prompts.log.info(authorize.instructions)
|
options: prompt.options,
|
||||||
}
|
|
||||||
const spinner = prompts.spinner()
|
|
||||||
spinner.start("Waiting for authorization...")
|
|
||||||
const result = await authorize.callback()
|
|
||||||
if (result.type === "failed") {
|
|
||||||
spinner.stop("Failed to authorize", 1)
|
|
||||||
}
|
|
||||||
if (result.type === "success") {
|
|
||||||
if ("refresh" in result) {
|
|
||||||
await Auth.set(provider, {
|
|
||||||
type: "oauth",
|
|
||||||
refresh: result.refresh,
|
|
||||||
access: result.access,
|
|
||||||
expires: result.expires,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if ("key" in result) {
|
|
||||||
await Auth.set(provider, {
|
|
||||||
type: "api",
|
|
||||||
key: result.key,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
spinner.stop("Login successful")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (authorize.method === "code") {
|
|
||||||
const code = await prompts.text({
|
|
||||||
message: "Paste the authorization code here: ",
|
|
||||||
validate: (x) => (x && x.length > 0 ? undefined : "Required"),
|
|
||||||
})
|
})
|
||||||
if (prompts.isCancel(code)) throw new UI.CancelledError()
|
if (prompts.isCancel(value)) throw new UI.CancelledError()
|
||||||
const result = await authorize.callback(code)
|
inputs[prompt.key] = value
|
||||||
if (result.type === "failed") {
|
} else {
|
||||||
prompts.log.error("Failed to authorize")
|
const value = await prompts.text({
|
||||||
|
message: prompt.message,
|
||||||
|
placeholder: prompt.placeholder,
|
||||||
|
validate: prompt.validate ? (v) => prompt.validate!(v ?? "") : undefined,
|
||||||
|
})
|
||||||
|
if (prompts.isCancel(value)) throw new UI.CancelledError()
|
||||||
|
inputs[prompt.key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method.type === "oauth") {
|
||||||
|
const authorize = await method.authorize(inputs)
|
||||||
|
|
||||||
|
if (authorize.url) {
|
||||||
|
prompts.log.info("Go to: " + authorize.url)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authorize.method === "auto") {
|
||||||
|
if (authorize.instructions) {
|
||||||
|
prompts.log.info(authorize.instructions)
|
||||||
|
}
|
||||||
|
const spinner = prompts.spinner()
|
||||||
|
spinner.start("Waiting for authorization...")
|
||||||
|
const result = await authorize.callback()
|
||||||
|
if (result.type === "failed") {
|
||||||
|
spinner.stop("Failed to authorize", 1)
|
||||||
|
}
|
||||||
|
if (result.type === "success") {
|
||||||
|
const saveProvider = result.provider ?? provider
|
||||||
|
if ("refresh" in result) {
|
||||||
|
const { type: _, provider: __, refresh, access, expires, ...extraFields } = result
|
||||||
|
await Auth.set(saveProvider, {
|
||||||
|
type: "oauth",
|
||||||
|
refresh,
|
||||||
|
access,
|
||||||
|
expires,
|
||||||
|
...extraFields,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
if (result.type === "success") {
|
if ("key" in result) {
|
||||||
if ("refresh" in result) {
|
await Auth.set(saveProvider, {
|
||||||
await Auth.set(provider, {
|
type: "api",
|
||||||
type: "oauth",
|
key: result.key,
|
||||||
refresh: result.refresh,
|
})
|
||||||
access: result.access,
|
|
||||||
expires: result.expires,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if ("key" in result) {
|
|
||||||
await Auth.set(provider, {
|
|
||||||
type: "api",
|
|
||||||
key: result.key,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
prompts.log.success("Login successful")
|
|
||||||
}
|
}
|
||||||
|
spinner.stop("Login successful")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authorize.method === "code") {
|
||||||
|
const code = await prompts.text({
|
||||||
|
message: "Paste the authorization code here: ",
|
||||||
|
validate: (x) => (x && x.length > 0 ? undefined : "Required"),
|
||||||
|
})
|
||||||
|
if (prompts.isCancel(code)) throw new UI.CancelledError()
|
||||||
|
const result = await authorize.callback(code)
|
||||||
|
if (result.type === "failed") {
|
||||||
|
prompts.log.error("Failed to authorize")
|
||||||
|
}
|
||||||
|
if (result.type === "success") {
|
||||||
|
const saveProvider = result.provider ?? provider
|
||||||
|
if ("refresh" in result) {
|
||||||
|
const { type: _, provider: __, refresh, access, expires, ...extraFields } = result
|
||||||
|
await Auth.set(saveProvider, {
|
||||||
|
type: "oauth",
|
||||||
|
refresh,
|
||||||
|
access,
|
||||||
|
expires,
|
||||||
|
...extraFields,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if ("key" in result) {
|
||||||
|
await Auth.set(saveProvider, {
|
||||||
|
type: "api",
|
||||||
|
key: result.key,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
prompts.log.success("Login successful")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prompts.outro("Done")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method.type === "api") {
|
||||||
|
if (method.authorize) {
|
||||||
|
const result = await method.authorize(inputs)
|
||||||
|
if (result.type === "failed") {
|
||||||
|
prompts.log.error("Failed to authorize")
|
||||||
|
}
|
||||||
|
if (result.type === "success") {
|
||||||
|
const saveProvider = result.provider ?? provider
|
||||||
|
await Auth.set(saveProvider, {
|
||||||
|
type: "api",
|
||||||
|
key: result.key,
|
||||||
|
})
|
||||||
|
prompts.log.success("Login successful")
|
||||||
}
|
}
|
||||||
prompts.outro("Done")
|
prompts.outro("Done")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (provider === "other") {
|
if (provider === "other") {
|
||||||
provider = await prompts.text({
|
provider = await 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(provider)) throw new UI.CancelledError()
|
|
||||||
provider = provider.replace(/^@ai-sdk\//, "")
|
|
||||||
if (prompts.isCancel(provider)) throw new UI.CancelledError()
|
|
||||||
prompts.log.warn(
|
|
||||||
`This only stores a credential for ${provider} - you will need configure it in opencode.json, check the docs for examples.`,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (provider === "amazon-bedrock") {
|
|
||||||
prompts.log.info(
|
|
||||||
"Amazon bedrock can be configured with standard AWS environment variables like AWS_BEARER_TOKEN_BEDROCK, AWS_PROFILE or AWS_ACCESS_KEY_ID",
|
|
||||||
)
|
|
||||||
prompts.outro("Done")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (provider === "google-vertex") {
|
|
||||||
prompts.log.info(
|
|
||||||
"Google Cloud Vertex AI uses Application Default Credentials. Set GOOGLE_APPLICATION_CREDENTIALS or run 'gcloud auth application-default login'. Optionally set GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION (or VERTEX_LOCATION)",
|
|
||||||
)
|
|
||||||
prompts.outro("Done")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (provider === "opencode") {
|
|
||||||
prompts.log.info("Create an api key at https://opencode.ai/auth")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (provider === "vercel") {
|
|
||||||
prompts.log.info("You can create an api key at https://vercel.link/ai-gateway-token")
|
|
||||||
}
|
|
||||||
|
|
||||||
const key = await prompts.password({
|
|
||||||
message: "Enter your API key",
|
|
||||||
validate: (x) => (x && x.length > 0 ? undefined : "Required"),
|
|
||||||
})
|
|
||||||
if (prompts.isCancel(key)) throw new UI.CancelledError()
|
|
||||||
await Auth.set(provider, {
|
|
||||||
type: "api",
|
|
||||||
key,
|
|
||||||
})
|
})
|
||||||
|
if (prompts.isCancel(provider)) throw new UI.CancelledError()
|
||||||
|
provider = provider.replace(/^@ai-sdk\//, "")
|
||||||
|
if (prompts.isCancel(provider)) throw new UI.CancelledError()
|
||||||
|
prompts.log.warn(
|
||||||
|
`This only stores a credential for ${provider} - you will need configure it in opencode.json, check the docs for examples.`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (provider === "amazon-bedrock") {
|
||||||
|
prompts.log.info(
|
||||||
|
"Amazon bedrock can be configured with standard AWS environment variables like AWS_BEARER_TOKEN_BEDROCK, AWS_PROFILE or AWS_ACCESS_KEY_ID",
|
||||||
|
)
|
||||||
prompts.outro("Done")
|
prompts.outro("Done")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (provider === "opencode") {
|
||||||
|
prompts.log.info("Create an api key at https://opencode.ai/auth")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (provider === "vercel") {
|
||||||
|
prompts.log.info("You can create an api key at https://vercel.link/ai-gateway-token")
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = await prompts.password({
|
||||||
|
message: "Enter your API key",
|
||||||
|
validate: (x) => (x && x.length > 0 ? undefined : "Required"),
|
||||||
|
})
|
||||||
|
if (prompts.isCancel(key)) throw new UI.CancelledError()
|
||||||
|
await Auth.set(provider, {
|
||||||
|
type: "api",
|
||||||
|
key,
|
||||||
|
})
|
||||||
|
|
||||||
|
prompts.outro("Done")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -574,6 +574,7 @@ export namespace Config {
|
|||||||
.object({
|
.object({
|
||||||
apiKey: z.string().optional(),
|
apiKey: z.string().optional(),
|
||||||
baseURL: z.string().optional(),
|
baseURL: z.string().optional(),
|
||||||
|
enterpriseUrl: z.string().optional().describe("GitHub Enterprise URL for copilot authentication"),
|
||||||
timeout: z
|
timeout: z
|
||||||
.union([
|
.union([
|
||||||
z
|
z
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export namespace Plugin {
|
|||||||
}
|
}
|
||||||
const plugins = [...(config.plugin ?? [])]
|
const plugins = [...(config.plugin ?? [])]
|
||||||
if (!Flag.OPENCODE_DISABLE_DEFAULT_PLUGINS) {
|
if (!Flag.OPENCODE_DISABLE_DEFAULT_PLUGINS) {
|
||||||
plugins.push("opencode-copilot-auth@0.0.3")
|
plugins.push("opencode-copilot-auth@0.0.4")
|
||||||
plugins.push("opencode-anthropic-auth@0.0.2")
|
plugins.push("opencode-anthropic-auth@0.0.2")
|
||||||
}
|
}
|
||||||
for (let plugin of plugins) {
|
for (let plugin of plugins) {
|
||||||
|
|||||||
@@ -283,6 +283,18 @@ export namespace Provider {
|
|||||||
|
|
||||||
const configProviders = Object.entries(config.provider ?? {})
|
const configProviders = Object.entries(config.provider ?? {})
|
||||||
|
|
||||||
|
// Add GitHub Copilot Enterprise provider that inherits from GitHub Copilot
|
||||||
|
if (database["github-copilot"]) {
|
||||||
|
const githubCopilot = database["github-copilot"]
|
||||||
|
database["github-copilot-enterprise"] = {
|
||||||
|
...githubCopilot,
|
||||||
|
id: "github-copilot-enterprise",
|
||||||
|
name: "GitHub Copilot Enterprise",
|
||||||
|
// Enterprise uses a different API endpoint - will be set dynamically based on auth
|
||||||
|
api: undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const [providerID, provider] of configProviders) {
|
for (const [providerID, provider] of configProviders) {
|
||||||
const existing = database[providerID]
|
const existing = database[providerID]
|
||||||
const parsed: ModelsDev.Provider = {
|
const parsed: ModelsDev.Provider = {
|
||||||
@@ -378,14 +390,44 @@ export namespace Provider {
|
|||||||
if (!plugin.auth) continue
|
if (!plugin.auth) continue
|
||||||
const providerID = plugin.auth.provider
|
const providerID = plugin.auth.provider
|
||||||
if (disabled.has(providerID)) continue
|
if (disabled.has(providerID)) continue
|
||||||
|
|
||||||
|
// For github-copilot plugin, check if auth exists for either github-copilot or github-copilot-enterprise
|
||||||
|
let hasAuth = false
|
||||||
const auth = await Auth.get(providerID)
|
const auth = await Auth.get(providerID)
|
||||||
if (!auth) continue
|
if (auth) hasAuth = true
|
||||||
|
|
||||||
|
// Special handling for github-copilot: also check for enterprise auth
|
||||||
|
if (providerID === "github-copilot" && !hasAuth) {
|
||||||
|
const enterpriseAuth = await Auth.get("github-copilot-enterprise")
|
||||||
|
if (enterpriseAuth) hasAuth = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasAuth) continue
|
||||||
if (!plugin.auth.loader) continue
|
if (!plugin.auth.loader) continue
|
||||||
const options = await plugin.auth.loader(
|
|
||||||
() => Auth.get(providerID) as any,
|
// Load for the main provider if auth exists
|
||||||
database[plugin.auth.provider],
|
if (auth) {
|
||||||
)
|
const options = await plugin.auth.loader(
|
||||||
mergeProvider(plugin.auth.provider, options ?? {}, "custom")
|
() => Auth.get(providerID) as any,
|
||||||
|
database[plugin.auth.provider],
|
||||||
|
)
|
||||||
|
mergeProvider(plugin.auth.provider, options ?? {}, "custom")
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is github-copilot plugin, also register for github-copilot-enterprise if auth exists
|
||||||
|
if (providerID === "github-copilot") {
|
||||||
|
const enterpriseProviderID = "github-copilot-enterprise"
|
||||||
|
if (!disabled.has(enterpriseProviderID)) {
|
||||||
|
const enterpriseAuth = await Auth.get(enterpriseProviderID)
|
||||||
|
if (enterpriseAuth) {
|
||||||
|
const enterpriseOptions = await plugin.auth.loader(
|
||||||
|
() => Auth.get(enterpriseProviderID) as any,
|
||||||
|
database[enterpriseProviderID],
|
||||||
|
)
|
||||||
|
mergeProvider(enterpriseProviderID, enterpriseOptions ?? {}, "custom")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// load config
|
// load config
|
||||||
@@ -458,7 +500,8 @@ export namespace Provider {
|
|||||||
: installedPath
|
: installedPath
|
||||||
const mod = await import(modPath)
|
const mod = await import(modPath)
|
||||||
if (options["timeout"] !== undefined && options["timeout"] !== null) {
|
if (options["timeout"] !== undefined && options["timeout"] !== null) {
|
||||||
// Only override fetch if user explicitly sets timeout
|
// Preserve custom fetch if it exists, wrap it with timeout logic
|
||||||
|
const customFetch = options["fetch"]
|
||||||
options["fetch"] = async (input: any, init?: BunFetchRequestInit) => {
|
options["fetch"] = async (input: any, init?: BunFetchRequestInit) => {
|
||||||
const { signal, ...rest } = init ?? {}
|
const { signal, ...rest } = init ?? {}
|
||||||
|
|
||||||
@@ -468,7 +511,8 @@ export namespace Provider {
|
|||||||
|
|
||||||
const combined = signals.length > 1 ? AbortSignal.any(signals) : signals[0]
|
const combined = signals.length > 1 ? AbortSignal.any(signals) : signals[0]
|
||||||
|
|
||||||
return fetch(input, {
|
const fetchFn = customFetch ?? fetch
|
||||||
|
return fetchFn(input, {
|
||||||
...rest,
|
...rest,
|
||||||
signal: combined,
|
signal: combined,
|
||||||
// @ts-ignore see here: https://github.com/oven-sh/bun/issues/16682
|
// @ts-ignore see here: https://github.com/oven-sh/bun/issues/16682
|
||||||
|
|||||||
@@ -39,13 +39,35 @@ export interface Hooks {
|
|||||||
| {
|
| {
|
||||||
type: "oauth"
|
type: "oauth"
|
||||||
label: string
|
label: string
|
||||||
authorize(): Promise<
|
prompts?: Array<
|
||||||
|
| {
|
||||||
|
type: "text"
|
||||||
|
key: string
|
||||||
|
message: string
|
||||||
|
placeholder?: string
|
||||||
|
validate?: (value: string) => string | undefined
|
||||||
|
condition?: (inputs: Record<string, string>) => boolean
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: "select"
|
||||||
|
key: string
|
||||||
|
message: string
|
||||||
|
options: Array<{
|
||||||
|
label: string
|
||||||
|
value: string
|
||||||
|
hint?: string
|
||||||
|
}>
|
||||||
|
condition?: (inputs: Record<string, string>) => boolean
|
||||||
|
}
|
||||||
|
>
|
||||||
|
authorize(inputs?: Record<string, string>): Promise<
|
||||||
{ url: string; instructions: string } & (
|
{ url: string; instructions: string } & (
|
||||||
| {
|
| {
|
||||||
method: "auto"
|
method: "auto"
|
||||||
callback(): Promise<
|
callback(): Promise<
|
||||||
| ({
|
| ({
|
||||||
type: "success"
|
type: "success"
|
||||||
|
provider?: string
|
||||||
} & (
|
} & (
|
||||||
| {
|
| {
|
||||||
refresh: string
|
refresh: string
|
||||||
@@ -64,6 +86,7 @@ export interface Hooks {
|
|||||||
callback(code: string): Promise<
|
callback(code: string): Promise<
|
||||||
| ({
|
| ({
|
||||||
type: "success"
|
type: "success"
|
||||||
|
provider?: string
|
||||||
} & (
|
} & (
|
||||||
| {
|
| {
|
||||||
refresh: string
|
refresh: string
|
||||||
@@ -80,7 +103,41 @@ export interface Hooks {
|
|||||||
)
|
)
|
||||||
>
|
>
|
||||||
}
|
}
|
||||||
| { type: "api"; label: string }
|
| {
|
||||||
|
type: "api"
|
||||||
|
label: string
|
||||||
|
prompts?: Array<
|
||||||
|
| {
|
||||||
|
type: "text"
|
||||||
|
key: string
|
||||||
|
message: string
|
||||||
|
placeholder?: string
|
||||||
|
validate?: (value: string) => string | undefined
|
||||||
|
condition?: (inputs: Record<string, string>) => boolean
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: "select"
|
||||||
|
key: string
|
||||||
|
message: string
|
||||||
|
options: Array<{
|
||||||
|
label: string
|
||||||
|
value: string
|
||||||
|
hint?: string
|
||||||
|
}>
|
||||||
|
condition?: (inputs: Record<string, string>) => boolean
|
||||||
|
}
|
||||||
|
>
|
||||||
|
authorize?(inputs?: Record<string, string>): Promise<
|
||||||
|
| {
|
||||||
|
type: "success"
|
||||||
|
key: string
|
||||||
|
provider?: string
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: "failed"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
}
|
||||||
)[]
|
)[]
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -405,6 +405,10 @@ export type Config = {
|
|||||||
options?: {
|
options?: {
|
||||||
apiKey?: string
|
apiKey?: string
|
||||||
baseURL?: string
|
baseURL?: string
|
||||||
|
/**
|
||||||
|
* GitHub Enterprise URL for copilot authentication
|
||||||
|
*/
|
||||||
|
enterpriseUrl?: string
|
||||||
/**
|
/**
|
||||||
* Timeout in milliseconds for requests to this provider. Default is 300000 (5 minutes). Set to false to disable timeout.
|
* Timeout in milliseconds for requests to this provider. Default is 300000 (5 minutes). Set to false to disable timeout.
|
||||||
*/
|
*/
|
||||||
@@ -1135,6 +1139,7 @@ export type OAuth = {
|
|||||||
refresh: string
|
refresh: string
|
||||||
access: string
|
access: string
|
||||||
expires: number
|
expires: number
|
||||||
|
enterpriseUrl?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ApiAuth = {
|
export type ApiAuth = {
|
||||||
|
|||||||
Reference in New Issue
Block a user