opencodekit 0.15.11 → 0.15.12
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/dist/index.js
CHANGED
|
@@ -750,7 +750,7 @@ var cac = (name = "") => new CAC(name);
|
|
|
750
750
|
// package.json
|
|
751
751
|
var package_default = {
|
|
752
752
|
name: "opencodekit",
|
|
753
|
-
version: "0.15.
|
|
753
|
+
version: "0.15.12",
|
|
754
754
|
description: "CLI tool for bootstrapping and managing OpenCodeKit projects",
|
|
755
755
|
keywords: ["agents", "cli", "mcp", "opencode", "opencodekit", "template"],
|
|
756
756
|
license: "MIT",
|
|
@@ -5,7 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
import type { Plugin } from "@opencode-ai/plugin";
|
|
7
7
|
|
|
8
|
-
const CLIENT_ID = "
|
|
8
|
+
const CLIENT_ID = "Ov23li8tweQw6odWQebz";
|
|
9
|
+
|
|
10
|
+
// Add a small safety buffer when polling to avoid hitting the server
|
|
11
|
+
// slightly too early due to clock skew / timer drift.
|
|
12
|
+
const OAUTH_POLLING_SAFETY_MARGIN_MS = 3000; // 3 seconds
|
|
9
13
|
|
|
10
14
|
const HEADERS = {
|
|
11
15
|
"User-Agent": "GitHubCopilotChat/0.35.0",
|
|
@@ -40,11 +44,12 @@ function getUrls(domain: string) {
|
|
|
40
44
|
return {
|
|
41
45
|
DEVICE_CODE_URL: `https://${domain}/login/device/code`,
|
|
42
46
|
ACCESS_TOKEN_URL: `https://${domain}/login/oauth/access_token`,
|
|
43
|
-
COPILOT_API_KEY_URL: `https://api.github.com/copilot_internal/v2/token`,
|
|
44
47
|
};
|
|
45
48
|
}
|
|
46
49
|
|
|
47
|
-
|
|
50
|
+
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
51
|
+
|
|
52
|
+
export const CopilotAuthPlugin: Plugin = async ({ client: _client }) => {
|
|
48
53
|
return {
|
|
49
54
|
auth: {
|
|
50
55
|
provider: "github-copilot",
|
|
@@ -52,6 +57,11 @@ export const CopilotAuthPlugin: Plugin = async ({ client }) => {
|
|
|
52
57
|
const info = await getAuth();
|
|
53
58
|
if (!info || info.type !== "oauth") return {};
|
|
54
59
|
|
|
60
|
+
const enterpriseUrl = info.enterpriseUrl;
|
|
61
|
+
const baseURL = enterpriseUrl
|
|
62
|
+
? `https://copilot-api.${normalizeDomain(enterpriseUrl)}`
|
|
63
|
+
: undefined;
|
|
64
|
+
|
|
55
65
|
if (provider && provider.models) {
|
|
56
66
|
for (const model of Object.values(provider.models)) {
|
|
57
67
|
model.cost = {
|
|
@@ -62,71 +72,47 @@ export const CopilotAuthPlugin: Plugin = async ({ client }) => {
|
|
|
62
72
|
write: 0,
|
|
63
73
|
},
|
|
64
74
|
};
|
|
75
|
+
|
|
76
|
+
// Sync with official: Handle Claude routing and SDK mapping
|
|
77
|
+
const base =
|
|
78
|
+
baseURL ?? model.api.url ?? "https://api.githubcopilot.com";
|
|
79
|
+
const isClaude = model.id.includes("claude");
|
|
80
|
+
|
|
81
|
+
let url = base;
|
|
82
|
+
if (isClaude) {
|
|
83
|
+
if (!url.endsWith("/v1")) {
|
|
84
|
+
url = url.endsWith("/") ? `${url}v1` : `${url}/v1`;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
model.api.url = url;
|
|
89
|
+
model.api.npm = isClaude
|
|
90
|
+
? "@ai-sdk/anthropic"
|
|
91
|
+
: "@ai-sdk/github-copilot";
|
|
65
92
|
}
|
|
66
93
|
}
|
|
67
94
|
|
|
68
|
-
const enterpriseUrl = info.enterpriseUrl;
|
|
69
|
-
const baseURL = enterpriseUrl
|
|
70
|
-
? `https://copilot-api.${normalizeDomain(enterpriseUrl)}`
|
|
71
|
-
: "https://api.githubcopilot.com";
|
|
72
|
-
|
|
73
95
|
return {
|
|
74
|
-
baseURL,
|
|
75
96
|
apiKey: "",
|
|
76
97
|
async fetch(input, init) {
|
|
77
98
|
const info = await getAuth();
|
|
78
|
-
if (info.type !== "oauth") return
|
|
79
|
-
if (!info.access) {
|
|
80
|
-
const domain = info.enterpriseUrl
|
|
81
|
-
? normalizeDomain(info.enterpriseUrl)
|
|
82
|
-
: "github.com";
|
|
83
|
-
const urls = getUrls(domain);
|
|
84
|
-
|
|
85
|
-
const response = await fetch(urls.COPILOT_API_KEY_URL, {
|
|
86
|
-
headers: {
|
|
87
|
-
Accept: "application/json",
|
|
88
|
-
Authorization: `Bearer ${info.refresh}`,
|
|
89
|
-
...HEADERS,
|
|
90
|
-
},
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
if (!response.ok) {
|
|
94
|
-
throw new Error(`Token refresh failed: ${response.status}`);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const tokenData = await response.json();
|
|
98
|
-
|
|
99
|
-
const saveProviderID = info.enterpriseUrl
|
|
100
|
-
? "github-copilot-enterprise"
|
|
101
|
-
: "github-copilot";
|
|
102
|
-
await client.auth.set({
|
|
103
|
-
path: {
|
|
104
|
-
id: saveProviderID,
|
|
105
|
-
},
|
|
106
|
-
body: {
|
|
107
|
-
type: "oauth",
|
|
108
|
-
refresh: info.refresh,
|
|
109
|
-
access: tokenData.token,
|
|
110
|
-
expires: tokenData.expires_at * 1000 - 5 * 60 * 1000,
|
|
111
|
-
...(info.enterpriseUrl && {
|
|
112
|
-
enterpriseUrl: info.enterpriseUrl,
|
|
113
|
-
}),
|
|
114
|
-
},
|
|
115
|
-
});
|
|
116
|
-
info.access = tokenData.token;
|
|
117
|
-
}
|
|
99
|
+
if (info.type !== "oauth") return fetch(input, init);
|
|
118
100
|
|
|
119
101
|
let isAgentCall = false;
|
|
120
102
|
let isVisionRequest = false;
|
|
121
103
|
try {
|
|
122
104
|
const body =
|
|
123
|
-
typeof init
|
|
105
|
+
typeof init?.body === "string"
|
|
124
106
|
? JSON.parse(init.body)
|
|
125
|
-
: init
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
107
|
+
: init?.body;
|
|
108
|
+
|
|
109
|
+
const url = input.toString();
|
|
110
|
+
|
|
111
|
+
// Completions API
|
|
112
|
+
if (body?.messages && url.includes("completions")) {
|
|
113
|
+
// Keep local logic: detect if any message is assistant/tool
|
|
114
|
+
isAgentCall = body.messages.some((msg: any) =>
|
|
115
|
+
["tool", "assistant"].includes(msg.role),
|
|
130
116
|
);
|
|
131
117
|
isVisionRequest = body.messages.some(
|
|
132
118
|
(msg: any) =>
|
|
@@ -135,34 +121,58 @@ export const CopilotAuthPlugin: Plugin = async ({ client }) => {
|
|
|
135
121
|
);
|
|
136
122
|
}
|
|
137
123
|
|
|
124
|
+
// Responses API
|
|
138
125
|
if (body?.input) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
126
|
+
isAgentCall = body.input.some(
|
|
127
|
+
(item: any) =>
|
|
128
|
+
item?.role === "assistant" ||
|
|
129
|
+
(item?.type &&
|
|
130
|
+
RESPONSES_API_ALTERNATE_INPUT_TYPES.includes(item.type)),
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
isVisionRequest = body.input.some(
|
|
134
|
+
(item: any) =>
|
|
135
|
+
Array.isArray(item?.content) &&
|
|
136
|
+
item.content.some(
|
|
137
|
+
(part: any) => part.type === "input_image",
|
|
138
|
+
),
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Messages API (Anthropic style)
|
|
143
|
+
if (body?.messages && !url.includes("completions")) {
|
|
144
|
+
isAgentCall = body.messages.some((msg: any) =>
|
|
145
|
+
["tool", "assistant"].includes(msg.role),
|
|
146
|
+
);
|
|
147
|
+
isVisionRequest = body.messages.some(
|
|
148
|
+
(item: any) =>
|
|
149
|
+
Array.isArray(item?.content) &&
|
|
150
|
+
item.content.some(
|
|
151
|
+
(part: any) =>
|
|
152
|
+
part?.type === "image" ||
|
|
153
|
+
(part?.type === "tool_result" &&
|
|
154
|
+
Array.isArray(part?.content) &&
|
|
155
|
+
part.content.some(
|
|
156
|
+
(nested: any) => nested?.type === "image",
|
|
157
|
+
)),
|
|
158
|
+
),
|
|
159
|
+
);
|
|
152
160
|
}
|
|
153
161
|
} catch {}
|
|
154
162
|
|
|
155
|
-
const headers = {
|
|
156
|
-
|
|
163
|
+
const headers: Record<string, string> = {
|
|
164
|
+
"x-initiator": isAgentCall ? "agent" : "user",
|
|
165
|
+
...(init?.headers as Record<string, string>),
|
|
157
166
|
...HEADERS,
|
|
158
|
-
Authorization: `Bearer ${info.
|
|
167
|
+
Authorization: `Bearer ${info.refresh}`,
|
|
159
168
|
"Openai-Intent": "conversation-edits",
|
|
160
|
-
"X-Initiator": isAgentCall ? "agent" : "user",
|
|
161
169
|
};
|
|
170
|
+
|
|
162
171
|
if (isVisionRequest) {
|
|
163
172
|
headers["Copilot-Vision-Request"] = "true";
|
|
164
173
|
}
|
|
165
174
|
|
|
175
|
+
// Official only deletes lowercase "authorization"
|
|
166
176
|
delete headers["x-api-key"];
|
|
167
177
|
delete headers["authorization"];
|
|
168
178
|
|
|
@@ -286,7 +296,7 @@ export const CopilotAuthPlugin: Plugin = async ({ client }) => {
|
|
|
286
296
|
} = {
|
|
287
297
|
type: "success",
|
|
288
298
|
refresh: data.access_token,
|
|
289
|
-
access:
|
|
299
|
+
access: data.access_token,
|
|
290
300
|
expires: 0,
|
|
291
301
|
};
|
|
292
302
|
|
|
@@ -299,16 +309,33 @@ export const CopilotAuthPlugin: Plugin = async ({ client }) => {
|
|
|
299
309
|
}
|
|
300
310
|
|
|
301
311
|
if (data.error === "authorization_pending") {
|
|
302
|
-
await
|
|
303
|
-
|
|
312
|
+
await sleep(
|
|
313
|
+
deviceData.interval * 1000 +
|
|
314
|
+
OAUTH_POLLING_SAFETY_MARGIN_MS,
|
|
304
315
|
);
|
|
305
316
|
continue;
|
|
306
317
|
}
|
|
307
318
|
|
|
319
|
+
if (data.error === "slow_down") {
|
|
320
|
+
// Based on the RFC spec, we must add 5 seconds to our current polling interval.
|
|
321
|
+
let newInterval = (deviceData.interval + 5) * 1000;
|
|
322
|
+
|
|
323
|
+
if (
|
|
324
|
+
data.interval &&
|
|
325
|
+
typeof data.interval === "number" &&
|
|
326
|
+
data.interval > 0
|
|
327
|
+
) {
|
|
328
|
+
newInterval = data.interval * 1000;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
await sleep(newInterval + OAUTH_POLLING_SAFETY_MARGIN_MS);
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
|
|
308
335
|
if (data.error) return { type: "failed" };
|
|
309
336
|
|
|
310
|
-
await
|
|
311
|
-
|
|
337
|
+
await sleep(
|
|
338
|
+
deviceData.interval * 1000 + OAUTH_POLLING_SAFETY_MARGIN_MS,
|
|
312
339
|
);
|
|
313
340
|
continue;
|
|
314
341
|
}
|
package/package.json
CHANGED