opencode-kilocode-auth 1.0.9 → 1.0.10

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/plugin.ts +87 -11
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.9",
4
+ "version": "1.0.10",
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
@@ -3,6 +3,7 @@ import {
3
3
  KILOCODE_PROVIDER_ID,
4
4
  DEFAULT_MODEL_ID,
5
5
  DEVICE_AUTH_POLL_INTERVAL_MS,
6
+ KILOCODE_VERSION,
6
7
  } from "./constants"
7
8
  import {
8
9
  initiateDeviceAuth,
@@ -24,6 +25,59 @@ interface KilocodeAuth {
24
25
  key?: string // for api type (OpenCode uses "key" field)
25
26
  }
26
27
 
28
+ /**
29
+ * OpenAI SDK version used by Kilo Code VSCode extension
30
+ * From: kilocode/src/package.json -> "openai": "^5.12.2"
31
+ */
32
+ const OPENAI_SDK_VERSION = "0.51.0"
33
+
34
+ /**
35
+ * Get X-Stainless-* headers (EXACT match from OpenAI SDK)
36
+ * These are automatically added by the OpenAI SDK and MUST be included
37
+ */
38
+ function getStainlessHeaders(): Record<string, string> {
39
+ const platform = process.platform
40
+ const arch = process.arch
41
+ const nodeVersion = process.version
42
+
43
+ // Map platform to OS name (EXACT from OpenAI SDK)
44
+ const osMap: Record<string, string> = {
45
+ darwin: "MacOS",
46
+ win32: "Windows",
47
+ linux: "Linux",
48
+ freebsd: "FreeBSD",
49
+ openbsd: "OpenBSD",
50
+ }
51
+ const os = osMap[platform] || `Other:${platform}`
52
+
53
+ // Map arch (EXACT from OpenAI SDK)
54
+ const archMap: Record<string, string> = {
55
+ x32: "x32",
56
+ x64: "x64",
57
+ arm: "arm",
58
+ arm64: "arm64",
59
+ }
60
+ const archStr = archMap[arch] || `other:${arch}`
61
+
62
+ return {
63
+ "X-Stainless-Lang": "js",
64
+ "X-Stainless-Package-Version": OPENAI_SDK_VERSION,
65
+ "X-Stainless-OS": os,
66
+ "X-Stainless-Arch": archStr,
67
+ "X-Stainless-Runtime": "node",
68
+ "X-Stainless-Runtime-Version": nodeVersion,
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Get editor name header (EXACT match from Kilo Code VSCode extension)
74
+ * From: kilocode/src/core/kilocode/wrapper.ts -> getEditorNameHeader()
75
+ */
76
+ function getEditorNameHeader(): string {
77
+ // Exact format: [appName, version].join(" ")
78
+ return "Visual Studio Code 1.96.0"
79
+ }
80
+
27
81
  /**
28
82
  * Kilo Code Authentication Plugin for OpenCode
29
83
  *
@@ -87,8 +141,10 @@ export async function KilocodeAuthPlugin(input: PluginInput): Promise<Hooks> {
87
141
  return fetch(requestInput, init)
88
142
  }
89
143
 
90
- // Build headers
144
+ // Build headers - EXACT match from Kilo Code VSCode extension
91
145
  const headers = new Headers()
146
+
147
+ // First, copy any existing headers from the request
92
148
  if (init?.headers) {
93
149
  if (init.headers instanceof Headers) {
94
150
  init.headers.forEach((value, key) => headers.set(key, value))
@@ -103,24 +159,38 @@ export async function KilocodeAuthPlugin(input: PluginInput): Promise<Hooks> {
103
159
  }
104
160
  }
105
161
 
106
- // EXACT headers from Kilo Code VSCode extension (DEFAULT_HEADERS + customRequestOptions)
107
- // Authorization is set by OpenAI SDK internally
162
+ // ============================================================
163
+ // EXACT HEADERS FROM KILO CODE VSCODE EXTENSION (decompiled)
164
+ // ============================================================
165
+
166
+ // 1. OpenAI SDK standard headers
108
167
  headers.set("Authorization", `Bearer ${currentToken}`)
168
+ headers.set("Content-Type", "application/json")
109
169
 
110
- // DEFAULT_HEADERS from kilocode/src/api/providers/constants.ts
170
+ // 2. DEFAULT_HEADERS from kilocode/src/api/providers/constants.ts
171
+ // EXACT: vl = {"HTTP-Referer":"https://kilocode.ai","X-Title":"Kilo Code",[sFa]:Ca.version,"User-Agent":`Kilo-Code/${Ca.version}`}
111
172
  headers.set("HTTP-Referer", "https://kilocode.ai")
112
173
  headers.set("X-Title", "Kilo Code")
113
- headers.set("X-KiloCode-Version", "4.151.0")
114
- headers.set("User-Agent", "Kilo-Code/4.151.0")
174
+ headers.set("X-KiloCode-Version", KILOCODE_VERSION)
175
+ headers.set("User-Agent", `Kilo-Code/${KILOCODE_VERSION}`)
115
176
 
116
- // customRequestOptions from KilocodeOpenrouterHandler
117
- headers.set("X-KiloCode-EditorName", "Visual Studio Code 1.96.0")
177
+ // 3. customRequestOptions headers from KilocodeOpenrouterHandler
178
+ // EXACT: lFa = "X-KiloCode-EditorName"
179
+ headers.set("X-KiloCode-EditorName", getEditorNameHeader())
118
180
 
119
- // Organization header (exact casing from headers.ts)
181
+ // 4. Organization header (if present)
182
+ // EXACT: dAe = "X-KiloCode-OrganizationId"
120
183
  if (currentKilocodeAuth.organizationId) {
121
184
  headers.set("X-KiloCode-OrganizationId", currentKilocodeAuth.organizationId)
122
185
  }
123
186
 
187
+ // 5. X-Stainless-* headers (AUTOMATICALLY added by OpenAI SDK)
188
+ // These are CRITICAL - the server may check for these
189
+ const stainlessHeaders = getStainlessHeaders()
190
+ for (const [key, value] of Object.entries(stainlessHeaders)) {
191
+ headers.set(key, value)
192
+ }
193
+
124
194
  // Rewrite URL to Kilo Code endpoint
125
195
  const parsed =
126
196
  requestInput instanceof URL
@@ -128,7 +198,6 @@ export async function KilocodeAuthPlugin(input: PluginInput): Promise<Hooks> {
128
198
  : new URL(typeof requestInput === "string" ? requestInput : (requestInput as Request).url)
129
199
 
130
200
  // Map to Kilo Code OpenRouter-compatible endpoint
131
- // Kilo Code uses: https://api.kilo.ai/api/openrouter/chat/completions
132
201
  let url: URL
133
202
  let body = init?.body
134
203
 
@@ -140,11 +209,18 @@ export async function KilocodeAuthPlugin(input: PluginInput): Promise<Hooks> {
140
209
  try {
141
210
  const payload = JSON.parse(body)
142
211
 
143
- // Add stream_options like Kilo Code does (ALWAYS included)
212
+ // Add stream_options like Kilo Code does
213
+ // EXACT: stream_options:{include_usage:!0}
144
214
  if (payload.stream !== false) {
145
215
  payload.stream_options = { include_usage: true }
146
216
  }
147
217
 
218
+ // 6. For Anthropic models, add x-anthropic-beta header
219
+ // EXACT: o.startsWith("anthropic/")&&(v.headers["x-anthropic-beta"]="fine-grained-tool-streaming-2025-05-14")
220
+ if (payload.model && payload.model.startsWith("anthropic/")) {
221
+ headers.set("x-anthropic-beta", "fine-grained-tool-streaming-2025-05-14")
222
+ }
223
+
148
224
  if (payload.messages && Array.isArray(payload.messages)) {
149
225
  // Find system message and prepend Kilo Code role
150
226
  const systemIdx = payload.messages.findIndex((m: any) => m.role === "system")