opencode-kilocode-auth 1.0.7 → 1.0.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "opencode-kilocode-auth",
3
3
  "module": "index.ts",
4
- "version": "1.0.7",
4
+ "version": "1.0.9",
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/constants.ts CHANGED
@@ -17,21 +17,31 @@ export const KILOCODE_API_BASE_URL = "https://api.kilo.ai";
17
17
  */
18
18
  export const KILOCODE_PROVIDER_ID = "kilocode";
19
19
 
20
+ /**
21
+ * Kilo Code extension version (must match official extension)
22
+ */
23
+ export const KILOCODE_VERSION = "4.151.0";
24
+
20
25
  /**
21
26
  * Default headers for Kilo Code API requests
27
+ * EXACT match from kilocode/src/api/providers/constants.ts DEFAULT_HEADERS
22
28
  */
23
29
  export const DEFAULT_HEADERS = {
24
30
  "Content-Type": "application/json",
25
- "User-Agent": "opencode-kilocode-auth/1.0.0",
31
+ "HTTP-Referer": "https://kilocode.ai",
32
+ "X-Title": "Kilo Code",
33
+ "X-KiloCode-Version": KILOCODE_VERSION,
34
+ "User-Agent": `Kilo-Code/${KILOCODE_VERSION}`,
26
35
  } as const;
27
36
 
28
37
  /**
29
- * Kilo Code custom headers
38
+ * Kilo Code custom headers (EXACT casing from kilocode/src/shared/kilocode/headers.ts)
30
39
  */
31
- export const X_KILOCODE_ORGANIZATIONID = "X-KILOCODE-ORGANIZATIONID";
32
- export const X_KILOCODE_TASKID = "X-KILOCODE-TASKID";
33
- export const X_KILOCODE_PROJECTID = "X-KILOCODE-PROJECTID";
34
- export const X_KILOCODE_EDITORNAME = "X-KILOCODE-EDITORNAME";
40
+ export const X_KILOCODE_VERSION = "X-KiloCode-Version";
41
+ export const X_KILOCODE_ORGANIZATIONID = "X-KiloCode-OrganizationId";
42
+ export const X_KILOCODE_TASKID = "X-KiloCode-TaskId";
43
+ export const X_KILOCODE_PROJECTID = "X-KiloCode-ProjectId";
44
+ export const X_KILOCODE_EDITORNAME = "X-KiloCode-EditorName";
35
45
 
36
46
  /**
37
47
  * Default model ID if none is specified
@@ -4,6 +4,7 @@ import {
4
4
  DEFAULT_HEADERS,
5
5
  DEVICE_AUTH_POLL_INTERVAL_MS,
6
6
  DEFAULT_MODEL_ID,
7
+ X_KILOCODE_EDITORNAME,
7
8
  } from "../constants";
8
9
  import type {
9
10
  DeviceAuthInitiateResponse,
@@ -82,6 +83,13 @@ export async function pollDeviceAuth(code: string): Promise<DeviceAuthPollRespon
82
83
  return (await response.json()) as DeviceAuthPollResponse;
83
84
  }
84
85
 
86
+ /**
87
+ * Get editor name header value (matches Kilo Code VSCode extension)
88
+ */
89
+ function getEditorNameHeader(): string {
90
+ return "Visual Studio Code 1.96.0";
91
+ }
92
+
85
93
  /**
86
94
  * Fetch user profile from Kilo Code API
87
95
  */
@@ -90,6 +98,7 @@ export async function getKilocodeProfile(token: string): Promise<KilocodeProfile
90
98
  headers: {
91
99
  ...DEFAULT_HEADERS,
92
100
  Authorization: `Bearer ${token}`,
101
+ [X_KILOCODE_EDITORNAME]: getEditorNameHeader(),
93
102
  },
94
103
  });
95
104
 
@@ -119,6 +128,7 @@ export async function getKilocodeDefaultModel(
119
128
  headers: {
120
129
  ...DEFAULT_HEADERS,
121
130
  Authorization: `Bearer ${token}`,
131
+ [X_KILOCODE_EDITORNAME]: getEditorNameHeader(),
122
132
  },
123
133
  });
124
134
 
@@ -146,10 +156,11 @@ export async function getKilocodeModels(
146
156
  const headers: Record<string, string> = {
147
157
  ...DEFAULT_HEADERS,
148
158
  Authorization: `Bearer ${token}`,
159
+ [X_KILOCODE_EDITORNAME]: getEditorNameHeader(),
149
160
  };
150
161
 
151
162
  if (organizationId) {
152
- headers["X-KILOCODE-ORGANIZATIONID"] = organizationId;
163
+ headers["X-KiloCode-OrganizationId"] = organizationId;
153
164
  }
154
165
 
155
166
  const response = await fetch(baseUrl, { headers });
package/src/plugin.ts CHANGED
@@ -130,8 +130,40 @@ export async function KilocodeAuthPlugin(input: PluginInput): Promise<Hooks> {
130
130
  // Map to Kilo Code OpenRouter-compatible endpoint
131
131
  // Kilo Code uses: https://api.kilo.ai/api/openrouter/chat/completions
132
132
  let url: URL
133
+ let body = init?.body
134
+
133
135
  if (parsed.pathname.includes("/chat/completions")) {
134
136
  url = new URL(getApiUrl("/api/openrouter/chat/completions", currentToken))
137
+
138
+ // Modify request body to match Kilo Code format EXACTLY
139
+ if (body && typeof body === "string") {
140
+ try {
141
+ const payload = JSON.parse(body)
142
+
143
+ // Add stream_options like Kilo Code does (ALWAYS included)
144
+ if (payload.stream !== false) {
145
+ payload.stream_options = { include_usage: true }
146
+ }
147
+
148
+ if (payload.messages && Array.isArray(payload.messages)) {
149
+ // Find system message and prepend Kilo Code role
150
+ 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."
152
+
153
+ if (systemIdx >= 0) {
154
+ // Prepend Kilo Code role to existing system message
155
+ payload.messages[systemIdx].content = kiloCodeRole + "\n\n" + payload.messages[systemIdx].content
156
+ } else {
157
+ // Add system message at the beginning
158
+ payload.messages.unshift({ role: "system", content: kiloCodeRole })
159
+ }
160
+ }
161
+
162
+ body = JSON.stringify(payload)
163
+ } catch {
164
+ // Keep original body if parsing fails
165
+ }
166
+ }
135
167
  } else if (parsed.pathname.includes("/models")) {
136
168
  url = new URL(getApiUrl("/api/openrouter/models", currentToken))
137
169
  } else {
@@ -141,6 +173,7 @@ export async function KilocodeAuthPlugin(input: PluginInput): Promise<Hooks> {
141
173
  return fetch(url, {
142
174
  ...init,
143
175
  headers,
176
+ body,
144
177
  })
145
178
  },
146
179
  }