opencode-kilocode-auth 1.0.0 → 1.0.3
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 +28 -92
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.3",
|
|
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
|
@@ -1,28 +1,23 @@
|
|
|
1
1
|
import type { Hooks, PluginInput } from "@opencode-ai/plugin"
|
|
2
2
|
import {
|
|
3
3
|
KILOCODE_PROVIDER_ID,
|
|
4
|
-
KILOCODE_API_BASE_URL,
|
|
5
|
-
DEFAULT_HEADERS,
|
|
6
4
|
DEFAULT_MODEL_ID,
|
|
7
|
-
DEVICE_AUTH_POLL_INTERVAL_MS,
|
|
8
5
|
} from "./constants"
|
|
9
6
|
import {
|
|
10
|
-
initiateDeviceAuth,
|
|
11
|
-
pollDeviceAuth,
|
|
12
7
|
getKilocodeProfile,
|
|
13
8
|
getKilocodeDefaultModel,
|
|
14
9
|
getKilocodeModels,
|
|
15
|
-
openBrowserUrl,
|
|
16
10
|
getApiUrl,
|
|
17
11
|
} from "./kilocode/auth"
|
|
18
12
|
|
|
19
13
|
interface KilocodeAuth {
|
|
20
|
-
type: "oauth"
|
|
21
|
-
refresh
|
|
14
|
+
type: "oauth" | "api"
|
|
15
|
+
refresh?: string // token (for oauth)
|
|
22
16
|
access?: string
|
|
23
17
|
expires?: number
|
|
24
18
|
organizationId?: string
|
|
25
19
|
model?: string
|
|
20
|
+
apiKey?: string // for api type
|
|
26
21
|
}
|
|
27
22
|
|
|
28
23
|
/**
|
|
@@ -40,10 +35,13 @@ export async function KilocodeAuthPlugin(input: PluginInput): Promise<Hooks> {
|
|
|
40
35
|
|
|
41
36
|
async loader(getAuth, provider) {
|
|
42
37
|
const auth = await getAuth()
|
|
43
|
-
if (!auth
|
|
38
|
+
if (!auth) return {}
|
|
44
39
|
|
|
45
40
|
const kilocodeAuth = auth as KilocodeAuth
|
|
46
|
-
|
|
41
|
+
// Support both OAuth (refresh token) and API key authentication
|
|
42
|
+
const token = kilocodeAuth.type === "api"
|
|
43
|
+
? kilocodeAuth.apiKey
|
|
44
|
+
: kilocodeAuth.refresh
|
|
47
45
|
|
|
48
46
|
if (!token) return {}
|
|
49
47
|
|
|
@@ -64,7 +62,7 @@ export async function KilocodeAuthPlugin(input: PluginInput): Promise<Hooks> {
|
|
|
64
62
|
}
|
|
65
63
|
|
|
66
64
|
// Build base URL for OpenRouter-compatible API
|
|
67
|
-
const baseURL = getApiUrl("/api/openrouter
|
|
65
|
+
const baseURL = getApiUrl("/api/openrouter", token)
|
|
68
66
|
|
|
69
67
|
return {
|
|
70
68
|
baseURL,
|
|
@@ -72,12 +70,18 @@ export async function KilocodeAuthPlugin(input: PluginInput): Promise<Hooks> {
|
|
|
72
70
|
|
|
73
71
|
async fetch(requestInput: RequestInfo | URL, init?: RequestInit) {
|
|
74
72
|
const currentAuth = await getAuth()
|
|
75
|
-
if (!currentAuth
|
|
73
|
+
if (!currentAuth) {
|
|
76
74
|
return fetch(requestInput, init)
|
|
77
75
|
}
|
|
78
76
|
|
|
79
77
|
const currentKilocodeAuth = currentAuth as KilocodeAuth
|
|
80
|
-
const currentToken = currentKilocodeAuth.
|
|
78
|
+
const currentToken = currentKilocodeAuth.type === "api"
|
|
79
|
+
? currentKilocodeAuth.apiKey
|
|
80
|
+
: currentKilocodeAuth.refresh
|
|
81
|
+
|
|
82
|
+
if (!currentToken) {
|
|
83
|
+
return fetch(requestInput, init)
|
|
84
|
+
}
|
|
81
85
|
|
|
82
86
|
// Build headers
|
|
83
87
|
const headers = new Headers()
|
|
@@ -95,9 +99,13 @@ export async function KilocodeAuthPlugin(input: PluginInput): Promise<Hooks> {
|
|
|
95
99
|
}
|
|
96
100
|
}
|
|
97
101
|
|
|
98
|
-
// Set Kilo Code authorization
|
|
102
|
+
// Set Kilo Code authorization and required headers
|
|
99
103
|
headers.set("Authorization", `Bearer ${currentToken}`)
|
|
100
|
-
headers.set("
|
|
104
|
+
headers.set("HTTP-Referer", "https://kilocode.ai")
|
|
105
|
+
headers.set("X-Title", "Kilo Code")
|
|
106
|
+
headers.set("X-KiloCode-Version", "3.16.3")
|
|
107
|
+
headers.set("User-Agent", "Kilo-Code/3.16.3")
|
|
108
|
+
headers.set("X-KiloCode-EditorName", "Visual Studio Code 1.96.0")
|
|
101
109
|
|
|
102
110
|
// Add organization header if present
|
|
103
111
|
if (currentKilocodeAuth.organizationId) {
|
|
@@ -111,9 +119,10 @@ export async function KilocodeAuthPlugin(input: PluginInput): Promise<Hooks> {
|
|
|
111
119
|
: new URL(typeof requestInput === "string" ? requestInput : (requestInput as Request).url)
|
|
112
120
|
|
|
113
121
|
// Map to Kilo Code OpenRouter-compatible endpoint
|
|
122
|
+
// Kilo Code uses: https://api.kilo.ai/api/openrouter/chat/completions
|
|
114
123
|
let url: URL
|
|
115
|
-
if (parsed.pathname.includes("/chat/completions")
|
|
116
|
-
url = new URL(getApiUrl("/api/openrouter/
|
|
124
|
+
if (parsed.pathname.includes("/chat/completions")) {
|
|
125
|
+
url = new URL(getApiUrl("/api/openrouter/chat/completions", currentToken))
|
|
117
126
|
} else if (parsed.pathname.includes("/models")) {
|
|
118
127
|
url = new URL(getApiUrl("/api/openrouter/models", currentToken))
|
|
119
128
|
} else {
|
|
@@ -129,81 +138,10 @@ export async function KilocodeAuthPlugin(input: PluginInput): Promise<Hooks> {
|
|
|
129
138
|
},
|
|
130
139
|
|
|
131
140
|
methods: [
|
|
132
|
-
|
|
133
|
-
type: "oauth",
|
|
134
|
-
label: "Login with Kilo Code",
|
|
135
|
-
async authorize() {
|
|
136
|
-
// Initiate device auth flow
|
|
137
|
-
const authData = await initiateDeviceAuth()
|
|
138
|
-
const { code, verificationUrl, expiresIn } = authData
|
|
139
|
-
|
|
140
|
-
// Open browser for user
|
|
141
|
-
openBrowserUrl(verificationUrl)
|
|
142
|
-
|
|
143
|
-
return {
|
|
144
|
-
url: verificationUrl,
|
|
145
|
-
instructions: `Enter code: ${code}`,
|
|
146
|
-
method: "auto" as const,
|
|
147
|
-
|
|
148
|
-
async callback() {
|
|
149
|
-
// Poll for authorization
|
|
150
|
-
const maxAttempts = Math.ceil((expiresIn * 1000) / DEVICE_AUTH_POLL_INTERVAL_MS)
|
|
151
|
-
let attempt = 0
|
|
152
|
-
|
|
153
|
-
while (attempt < maxAttempts) {
|
|
154
|
-
await new Promise((resolve) => setTimeout(resolve, DEVICE_AUTH_POLL_INTERVAL_MS))
|
|
155
|
-
|
|
156
|
-
try {
|
|
157
|
-
const pollResult = await pollDeviceAuth(code)
|
|
158
|
-
|
|
159
|
-
if (pollResult.status === "approved" && pollResult.token) {
|
|
160
|
-
// Get profile for organization
|
|
161
|
-
let organizationId: string | undefined
|
|
162
|
-
try {
|
|
163
|
-
const profile = await getKilocodeProfile(pollResult.token)
|
|
164
|
-
if (profile.organizations && profile.organizations.length > 0) {
|
|
165
|
-
organizationId = profile.organizations[0].id
|
|
166
|
-
}
|
|
167
|
-
} catch {
|
|
168
|
-
// Continue without organization
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Get default model
|
|
172
|
-
const model = await getKilocodeDefaultModel(pollResult.token, organizationId)
|
|
173
|
-
|
|
174
|
-
return {
|
|
175
|
-
type: "success" as const,
|
|
176
|
-
refresh: pollResult.token,
|
|
177
|
-
access: pollResult.token,
|
|
178
|
-
expires: Date.now() + 365 * 24 * 60 * 60 * 1000, // 1 year (tokens don't expire normally)
|
|
179
|
-
// Store extra info in the auth
|
|
180
|
-
organizationId,
|
|
181
|
-
model,
|
|
182
|
-
} as any
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (pollResult.status === "denied") {
|
|
186
|
-
return { type: "failed" as const }
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
if (pollResult.status === "expired") {
|
|
190
|
-
return { type: "failed" as const }
|
|
191
|
-
}
|
|
192
|
-
} catch {
|
|
193
|
-
// Continue polling on error
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
attempt++
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
return { type: "failed" as const }
|
|
200
|
-
},
|
|
201
|
-
}
|
|
202
|
-
},
|
|
203
|
-
},
|
|
141
|
+
// API key is the primary method - get it from https://app.kilo.ai
|
|
204
142
|
{
|
|
205
143
|
type: "api",
|
|
206
|
-
label: "Enter
|
|
144
|
+
label: "Enter API Key (get from app.kilo.ai)",
|
|
207
145
|
},
|
|
208
146
|
],
|
|
209
147
|
},
|
|
@@ -220,8 +158,6 @@ export async function KilocodeAuthPlugin(input: PluginInput): Promise<Hooks> {
|
|
|
220
158
|
|
|
221
159
|
// Export utilities for external use
|
|
222
160
|
export {
|
|
223
|
-
initiateDeviceAuth,
|
|
224
|
-
pollDeviceAuth,
|
|
225
161
|
getKilocodeProfile,
|
|
226
162
|
getKilocodeDefaultModel,
|
|
227
163
|
getKilocodeModels,
|