opencode-kilocode-auth 1.0.4 → 1.0.6
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.
- package/package.json +1 -1
- package/src/plugin.ts +74 -4
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-kilocode-auth",
|
|
3
3
|
"module": "index.ts",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.6",
|
|
5
5
|
"author": "ported from Kilo Code",
|
|
6
6
|
"description": "OpenCode plugin for Kilo Code authentication with support for various models including Giga Potato",
|
|
7
7
|
"files": [
|
package/src/plugin.ts
CHANGED
|
@@ -2,11 +2,15 @@ import type { Hooks, PluginInput } from "@opencode-ai/plugin"
|
|
|
2
2
|
import {
|
|
3
3
|
KILOCODE_PROVIDER_ID,
|
|
4
4
|
DEFAULT_MODEL_ID,
|
|
5
|
+
DEVICE_AUTH_POLL_INTERVAL_MS,
|
|
5
6
|
} from "./constants"
|
|
6
7
|
import {
|
|
8
|
+
initiateDeviceAuth,
|
|
9
|
+
pollDeviceAuth,
|
|
7
10
|
getKilocodeProfile,
|
|
8
11
|
getKilocodeDefaultModel,
|
|
9
12
|
getKilocodeModels,
|
|
13
|
+
openBrowserUrl,
|
|
10
14
|
getApiUrl,
|
|
11
15
|
} from "./kilocode/auth"
|
|
12
16
|
|
|
@@ -76,7 +80,7 @@ export async function KilocodeAuthPlugin(input: PluginInput): Promise<Hooks> {
|
|
|
76
80
|
|
|
77
81
|
const currentKilocodeAuth = currentAuth as KilocodeAuth
|
|
78
82
|
const currentToken = currentKilocodeAuth.type === "api"
|
|
79
|
-
? currentKilocodeAuth.
|
|
83
|
+
? currentKilocodeAuth.key
|
|
80
84
|
: currentKilocodeAuth.refresh
|
|
81
85
|
|
|
82
86
|
if (!currentToken) {
|
|
@@ -101,10 +105,11 @@ export async function KilocodeAuthPlugin(input: PluginInput): Promise<Hooks> {
|
|
|
101
105
|
|
|
102
106
|
// Set Kilo Code authorization and required headers
|
|
103
107
|
headers.set("Authorization", `Bearer ${currentToken}`)
|
|
108
|
+
headers.set("x-api-key", currentToken) // Kilo Code uses both
|
|
104
109
|
headers.set("HTTP-Referer", "https://kilocode.ai")
|
|
105
110
|
headers.set("X-Title", "Kilo Code")
|
|
106
|
-
headers.set("X-KiloCode-Version", "
|
|
107
|
-
headers.set("User-Agent", "Kilo-Code/
|
|
111
|
+
headers.set("X-KiloCode-Version", "4.151.0")
|
|
112
|
+
headers.set("User-Agent", "Kilo-Code/4.151.0")
|
|
108
113
|
headers.set("X-KiloCode-EditorName", "Visual Studio Code 1.96.0")
|
|
109
114
|
|
|
110
115
|
// Add organization header if present
|
|
@@ -138,7 +143,72 @@ export async function KilocodeAuthPlugin(input: PluginInput): Promise<Hooks> {
|
|
|
138
143
|
},
|
|
139
144
|
|
|
140
145
|
methods: [
|
|
141
|
-
|
|
146
|
+
{
|
|
147
|
+
type: "oauth",
|
|
148
|
+
label: "Login with Kilo Code (Device Auth)",
|
|
149
|
+
async authorize() {
|
|
150
|
+
const authData = await initiateDeviceAuth()
|
|
151
|
+
const { code, verificationUrl, expiresIn } = authData
|
|
152
|
+
|
|
153
|
+
openBrowserUrl(verificationUrl)
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
url: verificationUrl,
|
|
157
|
+
instructions: `Enter code: ${code}`,
|
|
158
|
+
method: "auto" as const,
|
|
159
|
+
|
|
160
|
+
async callback() {
|
|
161
|
+
const maxAttempts = Math.ceil((expiresIn * 1000) / DEVICE_AUTH_POLL_INTERVAL_MS)
|
|
162
|
+
let attempt = 0
|
|
163
|
+
|
|
164
|
+
while (attempt < maxAttempts) {
|
|
165
|
+
await new Promise((resolve) => setTimeout(resolve, DEVICE_AUTH_POLL_INTERVAL_MS))
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
const pollResult = await pollDeviceAuth(code)
|
|
169
|
+
|
|
170
|
+
if (pollResult.status === "approved" && pollResult.token) {
|
|
171
|
+
let organizationId: string | undefined
|
|
172
|
+
try {
|
|
173
|
+
const profile = await getKilocodeProfile(pollResult.token)
|
|
174
|
+
if (profile.organizations && profile.organizations.length > 0) {
|
|
175
|
+
organizationId = profile.organizations[0].id
|
|
176
|
+
}
|
|
177
|
+
} catch {
|
|
178
|
+
// Continue without organization
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const model = await getKilocodeDefaultModel(pollResult.token, organizationId)
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
type: "success" as const,
|
|
185
|
+
refresh: pollResult.token,
|
|
186
|
+
access: pollResult.token,
|
|
187
|
+
expires: Date.now() + 365 * 24 * 60 * 60 * 1000,
|
|
188
|
+
organizationId,
|
|
189
|
+
model,
|
|
190
|
+
} as any
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (pollResult.status === "denied") {
|
|
194
|
+
return { type: "failed" as const }
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (pollResult.status === "expired") {
|
|
198
|
+
return { type: "failed" as const }
|
|
199
|
+
}
|
|
200
|
+
} catch {
|
|
201
|
+
// Continue polling on error
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
attempt++
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return { type: "failed" as const }
|
|
208
|
+
},
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
},
|
|
142
212
|
{
|
|
143
213
|
type: "api",
|
|
144
214
|
label: "Enter API Key (get from app.kilo.ai)",
|