opencode-gemini-auth 1.0.6 → 1.0.8
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/README.md +25 -2
- package/package.json +1 -1
- package/src/plugin/request.ts +3 -2
- package/src/plugin/server.ts +116 -5
package/README.md
CHANGED
|
@@ -1,17 +1,40 @@
|
|
|
1
1
|
# Gemini OAuth Plugin for Opencode
|
|
2
2
|
|
|
3
|
-
Authenticate the Opencode CLI with your Google account so you can use your
|
|
3
|
+
Authenticate the Opencode CLI with your Google account so you can use your
|
|
4
|
+
existing Gemini plan and its included quota instead of API billing.
|
|
4
5
|
|
|
5
6
|
## Setup
|
|
6
7
|
|
|
7
8
|
1. Add the plugin to your [Opencode config](https://opencode.ai/docs/config/):
|
|
9
|
+
|
|
8
10
|
```json
|
|
9
11
|
{
|
|
10
12
|
"$schema": "https://opencode.ai/config.json",
|
|
11
13
|
"plugin": ["opencode-gemini-auth"]
|
|
12
14
|
}
|
|
13
15
|
```
|
|
16
|
+
|
|
14
17
|
2. Run `opencode auth login`.
|
|
15
18
|
3. Choose the Google provider and select **OAuth with Google (Gemini CLI)**.
|
|
16
19
|
|
|
17
|
-
The plugin spins up a local callback listener, so after approving in the
|
|
20
|
+
The plugin spins up a local callback listener, so after approving in the
|
|
21
|
+
browser you'll land on an "Authentication complete" page with no URL
|
|
22
|
+
copy/paste required. If that port is already taken, the CLI automatically
|
|
23
|
+
falls back to the classic copy/paste flow and explains what to do.
|
|
24
|
+
|
|
25
|
+
## Updating
|
|
26
|
+
|
|
27
|
+
> [!WARNING]
|
|
28
|
+
> OpenCode does NOT auto-update plugins
|
|
29
|
+
|
|
30
|
+
To get the latest version:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
(cd ~ && sed -i.bak '/"opencode-gemini-auth"/d' .cache/opencode/package.json && \
|
|
34
|
+
rm -rf .cache/opencode/node_modules/opencode-gemini-auth && \
|
|
35
|
+
echo "Plugin update script finished successfully.")
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
opencode # Reinstalls latest
|
|
40
|
+
```
|
package/package.json
CHANGED
package/src/plugin/request.ts
CHANGED
|
@@ -39,8 +39,6 @@ export function prepareGeminiRequest(
|
|
|
39
39
|
): { request: RequestInfo; init: RequestInit; streaming: boolean } {
|
|
40
40
|
const baseInit: RequestInit = { ...init };
|
|
41
41
|
const headers = new Headers(init?.headers ?? {});
|
|
42
|
-
headers.set("Authorization", `Bearer ${accessToken}`);
|
|
43
|
-
headers.delete("x-api-key");
|
|
44
42
|
|
|
45
43
|
if (!isGenerativeLanguageRequest(input)) {
|
|
46
44
|
return {
|
|
@@ -50,6 +48,9 @@ export function prepareGeminiRequest(
|
|
|
50
48
|
};
|
|
51
49
|
}
|
|
52
50
|
|
|
51
|
+
headers.set("Authorization", `Bearer ${accessToken}`);
|
|
52
|
+
headers.delete("x-api-key");
|
|
53
|
+
|
|
53
54
|
const match = input.match(/\/models\/([^:]+):(\w+)/);
|
|
54
55
|
if (!match) {
|
|
55
56
|
return {
|
package/src/plugin/server.ts
CHANGED
|
@@ -55,19 +55,130 @@ export async function startOAuthListener(
|
|
|
55
55
|
};
|
|
56
56
|
});
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
const successResponse = `<!DOCTYPE html>
|
|
59
59
|
<html lang="en">
|
|
60
60
|
<head>
|
|
61
61
|
<meta charset="utf-8" />
|
|
62
62
|
<title>Opencode Gemini OAuth</title>
|
|
63
63
|
<style>
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
:root { color-scheme: light dark; }
|
|
65
|
+
body {
|
|
66
|
+
margin: 0;
|
|
67
|
+
min-height: 100vh;
|
|
68
|
+
display: flex;
|
|
69
|
+
align-items: center;
|
|
70
|
+
justify-content: center;
|
|
71
|
+
font-family: "Roboto", "Google Sans", arial, sans-serif;
|
|
72
|
+
background: #f1f3f4;
|
|
73
|
+
color: #202124;
|
|
74
|
+
}
|
|
75
|
+
main {
|
|
76
|
+
width: min(448px, calc(100% - 3rem));
|
|
77
|
+
background: #ffffff;
|
|
78
|
+
border-radius: 28px;
|
|
79
|
+
padding: 2.5rem 2.75rem;
|
|
80
|
+
box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 2px 6px rgba(60, 64, 67, 0.15);
|
|
81
|
+
}
|
|
82
|
+
header {
|
|
83
|
+
display: flex;
|
|
84
|
+
align-items: center;
|
|
85
|
+
gap: 0.75rem;
|
|
86
|
+
margin-bottom: 1.5rem;
|
|
87
|
+
}
|
|
88
|
+
.logo {
|
|
89
|
+
width: 40px;
|
|
90
|
+
height: 40px;
|
|
91
|
+
display: inline-flex;
|
|
92
|
+
}
|
|
93
|
+
.logo svg {
|
|
94
|
+
width: 100%;
|
|
95
|
+
height: 100%;
|
|
96
|
+
}
|
|
97
|
+
.brand {
|
|
98
|
+
font-size: 1.1rem;
|
|
99
|
+
font-weight: 500;
|
|
100
|
+
letter-spacing: 0.01em;
|
|
101
|
+
}
|
|
102
|
+
h1 {
|
|
103
|
+
margin: 0 0 0.75rem;
|
|
104
|
+
font-size: 1.75rem;
|
|
105
|
+
font-weight: 500;
|
|
106
|
+
letter-spacing: -0.01em;
|
|
107
|
+
}
|
|
108
|
+
p {
|
|
109
|
+
margin: 0 0 1.75rem;
|
|
110
|
+
font-size: 1.05rem;
|
|
111
|
+
line-height: 1.6;
|
|
112
|
+
color: #3c4043;
|
|
113
|
+
}
|
|
114
|
+
.note {
|
|
115
|
+
margin: 1.5rem 0 0;
|
|
116
|
+
font-size: 0.92rem;
|
|
117
|
+
color: #5f6368;
|
|
118
|
+
}
|
|
119
|
+
.action {
|
|
120
|
+
display: inline-flex;
|
|
121
|
+
align-items: center;
|
|
122
|
+
justify-content: center;
|
|
123
|
+
padding: 0.65rem 1.85rem;
|
|
124
|
+
border-radius: 999px;
|
|
125
|
+
background: #1a73e8;
|
|
126
|
+
color: #ffffff;
|
|
127
|
+
font-weight: 500;
|
|
128
|
+
font-size: 0.95rem;
|
|
129
|
+
letter-spacing: 0.02em;
|
|
130
|
+
text-decoration: none;
|
|
131
|
+
transition: box-shadow 0.2s ease, transform 0.2s ease;
|
|
132
|
+
}
|
|
133
|
+
.action:hover {
|
|
134
|
+
transform: translateY(-1px);
|
|
135
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 1px 3px rgba(60, 64, 67, 0.15);
|
|
136
|
+
}
|
|
137
|
+
.action:focus-visible {
|
|
138
|
+
outline: none;
|
|
139
|
+
box-shadow: 0 0 0 3px rgba(26, 115, 232, 0.3);
|
|
140
|
+
}
|
|
141
|
+
@media (prefers-color-scheme: dark) {
|
|
142
|
+
body {
|
|
143
|
+
background: #131314;
|
|
144
|
+
color: #e8eaed;
|
|
145
|
+
}
|
|
146
|
+
main {
|
|
147
|
+
background: #202124;
|
|
148
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5), 0 2px 6px rgba(0, 0, 0, 0.4);
|
|
149
|
+
}
|
|
150
|
+
p {
|
|
151
|
+
color: #e8eaed;
|
|
152
|
+
}
|
|
153
|
+
.note {
|
|
154
|
+
color: #bdc1c6;
|
|
155
|
+
}
|
|
156
|
+
.action {
|
|
157
|
+
background: #8ab4f8;
|
|
158
|
+
color: #202124;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
66
161
|
</style>
|
|
67
162
|
</head>
|
|
68
163
|
<body>
|
|
69
|
-
<
|
|
70
|
-
|
|
164
|
+
<main>
|
|
165
|
+
<header>
|
|
166
|
+
<span class="logo" aria-hidden="true">
|
|
167
|
+
<svg viewBox="0 0 46 46" xmlns="http://www.w3.org/2000/svg" role="img">
|
|
168
|
+
<title>Gemini linked to Opencode</title>
|
|
169
|
+
<path fill="#4285F4" d="M43.6 23.5c0-1.5-.1-3-.4-4.4H23v8.3h11.6c-.5 2.8-2 5.1-4.2 6.7v5.5h6.8c4-3.7 6.4-9.1 6.4-16.1z"/>
|
|
170
|
+
<path fill="#34A853" d="M23 45c5.8 0 10.6-1.9 14.1-5.2l-6.8-5.5c-1.9 1.3-4.3 2-7.3 2-5.6 0-10.4-3.7-12.1-8.7H3.8v5.6C7.3 39.9 14.6 45 23 45z"/>
|
|
171
|
+
<path fill="#FBBC04" d="M10.9 28.6c-.5-1.3-.8-2.7-.8-4.1 0-1.5.3-2.8.8-4.1v-5.6H3.8C2.3 17.7 1.5 20.2 1.5 24s.8 6.3 2.3 9.2l6.9-5.6z"/>
|
|
172
|
+
<path fill="#EA4335" d="M23 9.5c3.2 0 6 .9 8.3 2.7l6.2-6.2C33.6 2.2 28.8 0 23 0 14.6 0 7.3 5.1 3.8 12.4l7.1 5.6c1.7-5 6.5-8.5 12.1-8.5z"/>
|
|
173
|
+
</svg>
|
|
174
|
+
</span>
|
|
175
|
+
<span class="brand">Gemini linked to Opencode</span>
|
|
176
|
+
</header>
|
|
177
|
+
<h1>You're connected to Opencode</h1>
|
|
178
|
+
<p>Your Google account is now linked to Opencode. You can close this window and continue in the CLI.</p>
|
|
179
|
+
<a class="action" href="javascript:window.close()">Close window</a>
|
|
180
|
+
<p class="note">Need to reconnect later? Re-run the authentication command in Opencode.</p>
|
|
181
|
+
</main>
|
|
71
182
|
</body>
|
|
72
183
|
</html>`;
|
|
73
184
|
|