opencode-kilocode-auth 1.0.9 → 1.0.11

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 +131 -16
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.11",
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,22 +209,68 @@ 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
- // Find system message and prepend Kilo Code role
225
+ // Find system message and prepend Kilo Code system prompt
150
226
  const systemIdx = payload.messages.findIndex((m: any) => m.role === "system")
151
- const kiloCodeRole = "You are Kilo Code, a highly skilled software engineer with extensive knowledge in many programming languages, frameworks, design patterns, and best practices."
227
+
228
+ // EXACT Kilo Code system prompt structure (without tool definitions - OpenCode handles those)
229
+ const kiloCodeSystemPrompt = `You are Kilo Code, a highly skilled software engineer with extensive knowledge in many programming languages, frameworks, design patterns, and best practices.
230
+
231
+ ====
232
+
233
+ MARKDOWN RULES
234
+
235
+ ALL responses MUST show ANY \`language construct\` OR filename reference as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses.
236
+
237
+ ====
238
+
239
+ SYSTEM INFORMATION
240
+
241
+ Operating System: ${process.platform === 'win32' ? 'Windows' : process.platform === 'darwin' ? 'MacOS' : 'Linux'}
242
+ Default Shell: ${process.env.SHELL || process.env.COMSPEC || '/bin/bash'}
243
+ Home Directory: ${process.env.HOME || process.env.USERPROFILE || '~'}
244
+
245
+ ====
246
+
247
+ OBJECTIVE
248
+
249
+ You accomplish a given task iteratively, breaking it down into clear steps and working through them methodically.
250
+
251
+ 1. Analyze the user's task and set clear, achievable goals to accomplish it. Prioritize these goals in a logical order.
252
+ 2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
253
+ 3. Once you've completed the user's task, present the result of the task to the user.
254
+ 4. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.
255
+
256
+ ====
257
+
258
+ RULES
259
+
260
+ - Be concise, direct, and to the point.
261
+ - Output text to communicate with the user; all text you output outside of tool use is displayed to the user.
262
+ - Only use emojis if the user explicitly requests it.
263
+ - When making changes to files, first understand the file's code conventions. Mimic code style, use existing libraries and utilities, and follow existing patterns.
264
+ - NEVER assume that a given library is available, even if it is well known. Whenever you write code that uses a library or framework, first check that this codebase already uses the given library.
265
+ - Always follow security best practices. Never introduce code that exposes or logs secrets and keys.
266
+ - NEVER commit changes unless the user explicitly asks you to.`
152
267
 
153
268
  if (systemIdx >= 0) {
154
- // Prepend Kilo Code role to existing system message
155
- payload.messages[systemIdx].content = kiloCodeRole + "\n\n" + payload.messages[systemIdx].content
269
+ // Prepend Kilo Code prompt to existing system message
270
+ payload.messages[systemIdx].content = kiloCodeSystemPrompt + "\n\n====\n\nADDITIONAL INSTRUCTIONS\n\n" + payload.messages[systemIdx].content
156
271
  } else {
157
272
  // Add system message at the beginning
158
- payload.messages.unshift({ role: "system", content: kiloCodeRole })
273
+ payload.messages.unshift({ role: "system", content: kiloCodeSystemPrompt })
159
274
  }
160
275
  }
161
276