Skip to content

Commit 4d3d632

Browse files
committed
externalize github copilot code
1 parent 6bc61cb commit 4d3d632

File tree

3 files changed

+54
-18
lines changed

3 files changed

+54
-18
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { Global } from "../global"
2+
import { lazy } from "../util/lazy"
3+
import path from "path"
4+
5+
export const AuthCopilot = lazy(async () => {
6+
const file = Bun.file(path.join(Global.Path.cache, "copilot.ts"))
7+
const response = fetch(
8+
"https://raw.githubusercontent.com/sst/opencode-github-copilot/refs/heads/main/auth.ts",
9+
)
10+
.then((x) => Bun.write(file, x))
11+
.catch(() => {})
12+
13+
if (!file.exists()) {
14+
const worked = await response
15+
if (!worked) return
16+
}
17+
const result = await import(file.name!).catch(() => {})
18+
if (!result) return
19+
return result.AuthCopilot
20+
})

packages/opencode/src/cli/cmd/auth.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { AuthAnthropic } from "../../auth/anthropic"
2-
import { AuthGithubCopilot } from "../../auth/github-copilot"
2+
import { AuthCopilot } from "../../auth/copilot"
33
import { Auth } from "../../auth"
44
import { cmd } from "./cmd"
55
import * as prompts from "@clack/prompts"
@@ -17,7 +17,7 @@ export const AuthCommand = cmd({
1717
.command(AuthLogoutCommand)
1818
.command(AuthListCommand)
1919
.demandCommand(),
20-
async handler() { },
20+
async handler() {},
2121
})
2222

2323
export const AuthListCommand = cmd({
@@ -148,9 +148,10 @@ export const AuthLoginCommand = cmd({
148148
}
149149
}
150150

151-
if (provider === "github-copilot") {
151+
const copilot = await AuthCopilot()
152+
if (provider === "github-copilot" && copilot) {
152153
await new Promise((resolve) => setTimeout(resolve, 10))
153-
const deviceInfo = await AuthGithubCopilot.authorize()
154+
const deviceInfo = await copilot.authorize()
154155

155156
prompts.note(
156157
`Please visit: ${deviceInfo.verification}\nEnter code: ${deviceInfo.user}`,
@@ -163,13 +164,19 @@ export const AuthLoginCommand = cmd({
163164
await new Promise((resolve) =>
164165
setTimeout(resolve, deviceInfo.interval * 1000),
165166
)
166-
const status = await AuthGithubCopilot.poll(deviceInfo.device)
167-
if (status === "pending") continue
168-
if (status === "complete") {
167+
const response = await copilot.poll(deviceInfo.device)
168+
if (response.status === "pending") continue
169+
if (response.status === "success") {
170+
await Auth.set("github-copilot", {
171+
type: "oauth",
172+
refresh: response.refresh,
173+
access: response.access,
174+
expires: response.expires,
175+
})
169176
spinner.stop("Login successful")
170177
break
171178
}
172-
if (status === "failed") {
179+
if (response.status === "failed") {
173180
spinner.stop("Failed to authorize", 1)
174181
break
175182
}

packages/opencode/src/provider/provider.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import type { Tool } from "../tool/tool"
1919
import { WriteTool } from "../tool/write"
2020
import { TodoReadTool, TodoWriteTool } from "../tool/todo"
2121
import { AuthAnthropic } from "../auth/anthropic"
22-
import { AuthGithubCopilot } from "../auth/github-copilot"
22+
import { AuthCopilot } from "../auth/copilot"
2323
import { ModelsDev } from "./models"
2424
import { NamedError } from "../util/error"
2525
import { Auth } from "../auth"
@@ -68,8 +68,10 @@ export namespace Provider {
6868
}
6969
},
7070
"github-copilot": async (provider) => {
71-
const info = await AuthGithubCopilot.access()
72-
if (!info) return false
71+
const copilot = await AuthCopilot()
72+
if (!copilot) return false
73+
let info = await Auth.get("github-copilot")
74+
if (!info || info.type !== "oauth") return false
7375

7476
if (provider && provider.models) {
7577
for (const model of Object.values(provider.models)) {
@@ -84,15 +86,22 @@ export namespace Provider {
8486
options: {
8587
apiKey: "",
8688
async fetch(input: any, init: any) {
87-
const token = await AuthGithubCopilot.access()
88-
if (!token) throw new Error("GitHub Copilot authentication expired")
89+
let info = await Auth.get("github-copilot")
90+
if (!info || info.type !== "oauth") return
91+
if (!info.access || info.expires < Date.now()) {
92+
const tokens = await copilot.access(info.refresh)
93+
if (!tokens)
94+
throw new Error("GitHub Copilot authentication expired")
95+
info = {
96+
type: "oauth",
97+
...tokens,
98+
}
99+
await Auth.set("github-copilot", info)
100+
}
89101
const headers = {
90102
...init.headers,
91-
Authorization: `Bearer ${token}`,
92-
"User-Agent": "GitHubCopilotChat/0.26.7",
93-
"Editor-Version": "vscode/1.99.3",
94-
"Editor-Plugin-Version": "copilot-chat/0.26.7",
95-
"Copilot-Integration-Id": "vscode-chat",
103+
...copilot.HEADERS,
104+
Authorization: `Bearer ${info.access}`,
96105
"Openai-Intent": "conversation-edits",
97106
}
98107
delete headers["x-api-key"]

0 commit comments

Comments
 (0)