opencode-gemini-cli-oauth 1.2.1 → 1.2.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/dist/plugin.d.ts +2 -2
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +57 -117
- package/dist/plugin.js.map +1 -1
- package/package.json +1 -1
package/dist/plugin.d.ts
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
*
|
|
6
6
|
* OpenCode Gemini CLI OAuth Plugin
|
|
7
7
|
*
|
|
8
|
-
* This plugin
|
|
9
|
-
*
|
|
8
|
+
* This plugin intercepts requests to Google's Generative AI API
|
|
9
|
+
* and injects the OAuth token from the Gemini CLI.
|
|
10
10
|
*/
|
|
11
11
|
import type { Plugin } from "@opencode-ai/plugin";
|
|
12
12
|
/**
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAsB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAsB,MAAM,qBAAqB,CAAC;AAUtE;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAuIlC,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
|
package/dist/plugin.js
CHANGED
|
@@ -5,137 +5,97 @@
|
|
|
5
5
|
*
|
|
6
6
|
* OpenCode Gemini CLI OAuth Plugin
|
|
7
7
|
*
|
|
8
|
-
* This plugin
|
|
9
|
-
*
|
|
8
|
+
* This plugin intercepts requests to Google's Generative AI API
|
|
9
|
+
* and injects the OAuth token from the Gemini CLI.
|
|
10
10
|
*/
|
|
11
11
|
import { getAccessToken, verifyCredentials, getUserInfo, hasCredentials, } from "./oauth.js";
|
|
12
12
|
import { PROVIDER_ID } from "./constants.js";
|
|
13
|
-
// CloudCode endpoint used by Gemini CLI
|
|
14
|
-
const CLOUDCODE_ENDPOINT = "https://cloudcode-pa.googleapis.com";
|
|
15
|
-
const CLOUDCODE_API_VERSION = "v1internal";
|
|
16
|
-
/**
|
|
17
|
-
* Transform generativelanguage.googleapis.com request to cloudcode-pa.googleapis.com format
|
|
18
|
-
*/
|
|
19
|
-
function transformToCloudCodeRequest(urlStr, bodyStr, model, action, streaming) {
|
|
20
|
-
// Parse the original body
|
|
21
|
-
let originalBody = {};
|
|
22
|
-
if (bodyStr) {
|
|
23
|
-
try {
|
|
24
|
-
originalBody = JSON.parse(bodyStr);
|
|
25
|
-
}
|
|
26
|
-
catch {
|
|
27
|
-
// If body is not JSON, use as-is
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
// Build CloudCode API URL
|
|
31
|
-
// Format: https://cloudcode-pa.googleapis.com/v1internal:streamGenerateContent?alt=sse
|
|
32
|
-
const cloudCodeUrl = `${CLOUDCODE_ENDPOINT}/${CLOUDCODE_API_VERSION}:${action}${streaming ? "?alt=sse" : ""}`;
|
|
33
|
-
// Wrap the request body in CloudCode format
|
|
34
|
-
// The request format needs: { model: "...", request: { contents: [...], ... } }
|
|
35
|
-
const cloudCodeBody = {
|
|
36
|
-
model: model,
|
|
37
|
-
request: originalBody,
|
|
38
|
-
};
|
|
39
|
-
return {
|
|
40
|
-
url: cloudCodeUrl,
|
|
41
|
-
body: JSON.stringify(cloudCodeBody),
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
13
|
/**
|
|
45
14
|
* Create the Gemini CLI OAuth plugin
|
|
46
15
|
*/
|
|
47
16
|
export const GeminiCliOAuthPlugin = async (input) => {
|
|
48
|
-
console.
|
|
17
|
+
console.log("[gemini-cli-oauth] Plugin v1.2.2 initialized");
|
|
49
18
|
const { client } = input;
|
|
50
19
|
// Get the original fetch function
|
|
51
20
|
const originalFetch = globalThis.fetch;
|
|
52
21
|
/**
|
|
53
|
-
* Custom fetch that
|
|
22
|
+
* Custom fetch that injects OAuth token
|
|
54
23
|
*/
|
|
55
24
|
const authenticatedFetch = async (url, init) => {
|
|
56
|
-
const urlStr = typeof url === "string" ? url : url instanceof URL ? url.href : url.url;
|
|
57
|
-
// Only intercept requests to Google's generative language API
|
|
58
|
-
const isGenerativeLanguageApi = urlStr.includes("generativelanguage.googleapis.com");
|
|
59
|
-
const isCloudCodeApi = urlStr.includes("cloudcode-pa.googleapis.com");
|
|
60
|
-
if (!isGenerativeLanguageApi && !isCloudCodeApi) {
|
|
61
|
-
return originalFetch(url, init);
|
|
62
|
-
}
|
|
63
25
|
try {
|
|
26
|
+
// Normalize URL to string for checking
|
|
27
|
+
const urlStr = typeof url === "string" ? url : url instanceof URL ? url.href : url.url;
|
|
28
|
+
// Only intercept requests to Google's generative language API
|
|
29
|
+
if (!urlStr.includes("googleapis.com")) {
|
|
30
|
+
return originalFetch(url, init);
|
|
31
|
+
}
|
|
32
|
+
console.log(`[gemini-cli-oauth] Intercepting: ${urlStr}`);
|
|
64
33
|
// Get valid access token (refreshes if needed)
|
|
65
34
|
const token = await getAccessToken();
|
|
66
|
-
//
|
|
67
|
-
|
|
35
|
+
// Prepare new headers
|
|
36
|
+
// If 'url' is a Request object, we need to be careful not to consume it or lose its body.
|
|
37
|
+
// Easiest way is to fall back to the (url, init) signature if possible, or clone the request.
|
|
38
|
+
let finalUrl = url;
|
|
39
|
+
let finalInit = { ...init };
|
|
40
|
+
// If it's a Request object, we should probably construct a new init from it
|
|
41
|
+
if (url instanceof Request) {
|
|
42
|
+
finalInit = {
|
|
43
|
+
...finalInit,
|
|
44
|
+
method: url.method,
|
|
45
|
+
headers: new Headers(url.headers),
|
|
46
|
+
body: url.body, // This might be used already? Fetch handling of Request body is tricky.
|
|
47
|
+
// Note: @ai-sdk/google usually uses (url string, init object)
|
|
48
|
+
};
|
|
49
|
+
// Reset finalUrl to string to avoid dual-init issues
|
|
50
|
+
finalUrl = url.url;
|
|
51
|
+
}
|
|
52
|
+
const headers = new Headers(finalInit.headers);
|
|
68
53
|
headers.set("Authorization", `Bearer ${token}`);
|
|
54
|
+
// Remove API key from headers if present
|
|
69
55
|
headers.delete("x-goog-api-key");
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
56
|
+
// Update init
|
|
57
|
+
finalInit.headers = headers;
|
|
58
|
+
// Clean URL params (remove ?key=...)
|
|
59
|
+
let cleanUrl = typeof finalUrl === 'string' ? finalUrl : finalUrl.toString();
|
|
60
|
+
if (cleanUrl.includes("key=")) {
|
|
61
|
+
const u = new URL(cleanUrl);
|
|
62
|
+
u.searchParams.delete("key");
|
|
63
|
+
cleanUrl = u.toString();
|
|
76
64
|
}
|
|
77
|
-
|
|
78
|
-
// Extract model and action from URL: /models/{model}:{action}
|
|
79
|
-
const match = urlStr.match(/\/models\/([^:]+):(\w+)/);
|
|
80
|
-
if (!match) {
|
|
81
|
-
console.error("[gemini-cli-oauth] Could not parse model/action from URL:", urlStr);
|
|
82
|
-
// Fall back to original request with auth
|
|
83
|
-
return originalFetch(url, { ...init, headers });
|
|
84
|
-
}
|
|
85
|
-
const [, model, action] = match;
|
|
86
|
-
const streaming = urlStr.includes("alt=sse") || action === "streamGenerateContent";
|
|
87
|
-
// Get the original body
|
|
88
|
-
const bodyStr = typeof init?.body === "string" ? init.body : null;
|
|
89
|
-
// Transform to CloudCode format
|
|
90
|
-
const transformed = transformToCloudCodeRequest(urlStr, bodyStr, model, action, streaming);
|
|
91
|
-
console.error("[gemini-cli-oauth] Transformed URL:", transformed.url);
|
|
92
|
-
return originalFetch(transformed.url, {
|
|
93
|
-
...init,
|
|
94
|
-
method: "POST",
|
|
95
|
-
headers,
|
|
96
|
-
body: transformed.body,
|
|
97
|
-
});
|
|
65
|
+
return originalFetch(cleanUrl, finalInit);
|
|
98
66
|
}
|
|
99
67
|
catch (error) {
|
|
100
68
|
console.error("[gemini-cli-oauth] OAuth error:", error);
|
|
101
|
-
|
|
69
|
+
// Fallback: try request without auth injection (might work if key is valid)
|
|
70
|
+
return originalFetch(url, init);
|
|
102
71
|
}
|
|
103
72
|
};
|
|
104
73
|
/**
|
|
105
|
-
* Auth hook
|
|
74
|
+
* Auth hook
|
|
106
75
|
*/
|
|
107
76
|
const authHook = {
|
|
108
77
|
provider: PROVIDER_ID,
|
|
109
|
-
/**
|
|
110
|
-
* Loader function - called when the provider is used
|
|
111
|
-
* Returns the auth configuration with custom fetch
|
|
112
|
-
*/
|
|
113
78
|
loader: async (_getAuth, _provider) => {
|
|
114
|
-
console.
|
|
115
|
-
// Check
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (client?.tui?.showToast) {
|
|
120
|
-
await client.tui.showToast({
|
|
79
|
+
console.log("[gemini-cli-oauth] Loader called");
|
|
80
|
+
// Check credentials silently
|
|
81
|
+
hasCredentials().then(has => {
|
|
82
|
+
if (!has && client?.tui?.showToast) {
|
|
83
|
+
client.tui.showToast({
|
|
121
84
|
body: {
|
|
122
85
|
title: "Gemini CLI OAuth",
|
|
123
|
-
message: "No credentials
|
|
86
|
+
message: "No credentials. Run 'gemini auth login'.",
|
|
124
87
|
variant: "warning",
|
|
125
88
|
},
|
|
126
89
|
}).catch(() => { });
|
|
127
90
|
}
|
|
128
|
-
}
|
|
91
|
+
});
|
|
129
92
|
return {
|
|
130
|
-
//
|
|
131
|
-
apiKey: "",
|
|
93
|
+
// Dummy API key to satisfy OpenCode/SDK validation
|
|
94
|
+
apiKey: "AIzaSyDummyTokenForGeminiCliOAuthBypassValidation",
|
|
132
95
|
// Custom fetch that injects OAuth token
|
|
133
96
|
fetch: authenticatedFetch,
|
|
134
97
|
};
|
|
135
98
|
},
|
|
136
|
-
/**
|
|
137
|
-
* Auth methods shown in the OpenCode auth menu
|
|
138
|
-
*/
|
|
139
99
|
methods: [
|
|
140
100
|
{
|
|
141
101
|
type: "oauth",
|
|
@@ -143,34 +103,15 @@ export const GeminiCliOAuthPlugin = async (input) => {
|
|
|
143
103
|
authorize: async () => {
|
|
144
104
|
return {
|
|
145
105
|
url: "",
|
|
146
|
-
instructions: "
|
|
147
|
-
"To authenticate:\n" +
|
|
148
|
-
"1. Open a terminal\n" +
|
|
149
|
-
"2. Run: gemini auth login\n" +
|
|
150
|
-
"3. Complete the Google sign-in in your browser\n" +
|
|
151
|
-
"4. Return here and click 'I've completed sign-in'\n\n" +
|
|
152
|
-
"Your credentials will be shared between Gemini CLI and OpenCode.",
|
|
106
|
+
instructions: "Run 'gemini auth login' in your terminal.",
|
|
153
107
|
method: "auto",
|
|
154
108
|
callback: async () => {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
const userInfo = await getUserInfo();
|
|
160
|
-
return {
|
|
161
|
-
type: "success",
|
|
162
|
-
key: `GEMINI_CLI_OAUTH_${userInfo.email}`,
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
return {
|
|
166
|
-
type: "failed",
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
catch {
|
|
170
|
-
return {
|
|
171
|
-
type: "failed",
|
|
172
|
-
};
|
|
109
|
+
const isValid = await verifyCredentials();
|
|
110
|
+
if (isValid) {
|
|
111
|
+
const userInfo = await getUserInfo();
|
|
112
|
+
return { type: "success", key: `GEMINI_CLI_OAUTH_${userInfo.email}` };
|
|
173
113
|
}
|
|
114
|
+
return { type: "failed" };
|
|
174
115
|
},
|
|
175
116
|
};
|
|
176
117
|
},
|
|
@@ -181,6 +122,5 @@ export const GeminiCliOAuthPlugin = async (input) => {
|
|
|
181
122
|
auth: authHook,
|
|
182
123
|
};
|
|
183
124
|
};
|
|
184
|
-
// Default export for OpenCode plugin system
|
|
185
125
|
export default GeminiCliOAuthPlugin;
|
|
186
126
|
//# sourceMappingURL=plugin.js.map
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,WAAW,EACX,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED