opencode-gemini-auth 1.4.4 → 1.4.5

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-gemini-auth",
3
3
  "module": "index.ts",
4
- "version": "1.4.4",
4
+ "version": "1.4.5",
5
5
  "author": "jenslys",
6
6
  "repository": "https://github.com/jenslys/opencode-gemini-auth",
7
7
  "files": [
@@ -11,7 +11,9 @@
11
11
  "license": "MIT",
12
12
  "type": "module",
13
13
  "scripts": {
14
- "update:gemini-cli": "git -C .local/gemini-cli pull --ff-only"
14
+ "update:gemini-cli": "git -C .local/gemini-cli pull --ff-only",
15
+ "update:gemini-cli-version": "node commands/sync-gemini-cli-version.mjs",
16
+ "update:gemini-cli-sync": "npm run update:gemini-cli && npm run update:gemini-cli-version"
15
17
  },
16
18
  "devDependencies": {
17
19
  "@types/bun": "latest"
package/src/constants.ts CHANGED
@@ -28,7 +28,6 @@ export const GEMINI_REDIRECT_URI = "http://localhost:8085/oauth2callback";
28
28
  export const GEMINI_CODE_ASSIST_ENDPOINT = "https://cloudcode-pa.googleapis.com";
29
29
 
30
30
  export const CODE_ASSIST_HEADERS = {
31
- "User-Agent": "google-api-nodejs-client/9.15.1",
32
31
  "X-Goog-Api-Client": "gl-node/22.17.0",
33
32
  "Client-Metadata": "ideType=IDE_UNSPECIFIED,platform=PLATFORM_UNSPECIFIED,pluginType=GEMINI",
34
33
  } as const;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Synced from `.local/gemini-cli/packages/cli/package.json`.
3
+ * Update with: `npm run update:gemini-cli-version`
4
+ */
5
+ export const GEMINI_CLI_VERSION = "0.30.0-nightly.20260210.a2174751d";
@@ -1,5 +1,6 @@
1
1
  import { CODE_ASSIST_HEADERS, GEMINI_CODE_ASSIST_ENDPOINT } from "../../constants";
2
2
  import { logGeminiDebugResponse, startGeminiDebugRequest } from "../debug";
3
+ import { buildGeminiCliUserAgent } from "../user-agent";
3
4
  import {
4
5
  FREE_TIER_ID,
5
6
  type LoadCodeAssistPayload,
@@ -27,6 +28,7 @@ export async function loadManagedProject(
27
28
  const headers = {
28
29
  "Content-Type": "application/json",
29
30
  Authorization: `Bearer ${accessToken}`,
31
+ "User-Agent": buildGeminiCliUserAgent(),
30
32
  ...CODE_ASSIST_HEADERS,
31
33
  };
32
34
  const debugContext = startGeminiDebugRequest({
@@ -92,6 +94,7 @@ export async function onboardManagedProject(
92
94
  const headers = {
93
95
  "Content-Type": "application/json",
94
96
  Authorization: `Bearer ${accessToken}`,
97
+ "User-Agent": buildGeminiCliUserAgent(),
95
98
  ...CODE_ASSIST_HEADERS,
96
99
  };
97
100
 
@@ -143,6 +146,7 @@ export async function retrieveUserQuota(
143
146
  const headers = {
144
147
  "Content-Type": "application/json",
145
148
  Authorization: `Bearer ${accessToken}`,
149
+ "User-Agent": buildGeminiCliUserAgent(),
146
150
  ...CODE_ASSIST_HEADERS,
147
151
  };
148
152
 
@@ -2,6 +2,7 @@ import { randomUUID } from "node:crypto";
2
2
 
3
3
  import { CODE_ASSIST_HEADERS, GEMINI_CODE_ASSIST_ENDPOINT } from "../../constants";
4
4
  import { normalizeThinkingConfig } from "../request-helpers";
5
+ import { buildGeminiCliUserAgent } from "../user-agent";
5
6
  import { normalizeRequestPayloadIdentifiers, normalizeWrappedIdentifiers } from "./identifiers";
6
7
  import { addThoughtSignaturesToFunctionCalls, transformOpenAIToolCalls } from "./openai";
7
8
  import { isGenerativeLanguageRequest, toRequestUrlString } from "./shared";
@@ -38,6 +39,7 @@ export function prepareGeminiRequest(
38
39
 
39
40
  headers.set("Authorization", `Bearer ${accessToken}`);
40
41
  headers.delete("x-api-key");
42
+ headers.delete("x-goog-api-key");
41
43
 
42
44
  const match = toRequestUrlString(input).match(/\/models\/([^:]+):(\w+)/);
43
45
  if (!match) {
@@ -70,7 +72,7 @@ export function prepareGeminiRequest(
70
72
  headers.set("Accept", "text/event-stream");
71
73
  }
72
74
 
73
- headers.set("User-Agent", CODE_ASSIST_HEADERS["User-Agent"]);
75
+ headers.set("User-Agent", buildGeminiCliUserAgent(effectiveModel));
74
76
  headers.set("X-Goog-Api-Client", CODE_ASSIST_HEADERS["X-Goog-Api-Client"]);
75
77
  headers.set("Client-Metadata", CODE_ASSIST_HEADERS["Client-Metadata"]);
76
78
  /**
@@ -25,6 +25,7 @@ describe("request helpers", () => {
25
25
  headers: {
26
26
  "Content-Type": "application/json",
27
27
  "x-api-key": "should-be-removed",
28
+ "x-goog-api-key": "should-also-be-removed",
28
29
  },
29
30
  body: JSON.stringify({
30
31
  contents: [{ role: "user", parts: [{ text: "hi" }] }],
@@ -43,6 +44,9 @@ describe("request helpers", () => {
43
44
  const headers = new Headers(result.init.headers);
44
45
  expect(headers.get("Authorization")).toBe("Bearer token-123");
45
46
  expect(headers.get("x-api-key")).toBeNull();
47
+ expect(headers.get("x-goog-api-key")).toBeNull();
48
+ expect(headers.get("User-Agent")).toContain("GeminiCLI/");
49
+ expect(headers.get("User-Agent")).toContain("/gemini-3-flash-preview ");
46
50
  expect(headers.get("Accept")).toBe("text/event-stream");
47
51
  expect(headers.get("x-activity-request-id")).toBeTruthy();
48
52
 
@@ -0,0 +1,50 @@
1
+ import { afterEach, describe, expect, it } from "bun:test";
2
+
3
+ import { GEMINI_CLI_VERSION } from "./gemini-cli-version";
4
+ import { buildGeminiCliUserAgent, getGeminiCliVersion, userAgentInternals } from "./user-agent";
5
+
6
+ const originalNpmPackageVersion = process.env.npm_package_version;
7
+ const originalExplicitVersion = process.env.OPENCODE_GEMINI_CLI_VERSION;
8
+
9
+ describe("user-agent", () => {
10
+ afterEach(() => {
11
+ if (originalNpmPackageVersion === undefined) {
12
+ delete process.env.npm_package_version;
13
+ } else {
14
+ process.env.npm_package_version = originalNpmPackageVersion;
15
+ }
16
+ if (originalExplicitVersion === undefined) {
17
+ delete process.env.OPENCODE_GEMINI_CLI_VERSION;
18
+ } else {
19
+ process.env.OPENCODE_GEMINI_CLI_VERSION = originalExplicitVersion;
20
+ }
21
+ userAgentInternals.resetCache();
22
+ });
23
+
24
+ it("prefers OPENCODE_GEMINI_CLI_VERSION when available", () => {
25
+ process.env.OPENCODE_GEMINI_CLI_VERSION = "8.8.8-explicit";
26
+ process.env.npm_package_version = "9.9.9-test";
27
+ userAgentInternals.resetCache();
28
+
29
+ expect(getGeminiCliVersion()).toBe("8.8.8-explicit");
30
+ expect(buildGeminiCliUserAgent("gemini-3-flash-preview")).toContain("/8.8.8-explicit/");
31
+ });
32
+
33
+ it("prefers synced GEMINI_CLI_VERSION over npm_package_version", () => {
34
+ delete process.env.OPENCODE_GEMINI_CLI_VERSION;
35
+ process.env.npm_package_version = "9.9.9-test";
36
+ userAgentInternals.resetCache();
37
+
38
+ expect(getGeminiCliVersion()).toBe(GEMINI_CLI_VERSION);
39
+ });
40
+
41
+ it("builds a GeminiCLI-style user agent", () => {
42
+ delete process.env.OPENCODE_GEMINI_CLI_VERSION;
43
+ delete process.env.npm_package_version;
44
+ userAgentInternals.resetCache();
45
+
46
+ const userAgent = buildGeminiCliUserAgent("gemini-3-flash-preview");
47
+ expect(userAgent).toContain("GeminiCLI/");
48
+ expect(userAgent).toContain(`/gemini-3-flash-preview `);
49
+ });
50
+ });
@@ -0,0 +1,76 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { GEMINI_CLI_VERSION } from "./gemini-cli-version";
5
+
6
+ const GEMINI_CLI_UA_NAME = "GeminiCLI";
7
+ const GEMINI_CLI_DEFAULT_MODEL = "gemini-code-assist";
8
+
9
+ let cachedGeminiCliVersion: string | undefined;
10
+
11
+ /**
12
+ * Resolves plugin version for User-Agent:
13
+ * 1) explicit override (`OPENCODE_GEMINI_CLI_VERSION`)
14
+ * 2) synced Gemini CLI version file (`src/plugin/gemini-cli-version.ts`)
15
+ * 3) package-manager runtime env (`npm_package_version`)
16
+ * 4) local package.json next to the plugin sources
17
+ * 5) cwd package.json as final fallback
18
+ */
19
+ export function getGeminiCliVersion(): string {
20
+ if (cachedGeminiCliVersion) {
21
+ return cachedGeminiCliVersion;
22
+ }
23
+
24
+ const explicitVersion = process.env.OPENCODE_GEMINI_CLI_VERSION?.trim();
25
+ if (explicitVersion) {
26
+ cachedGeminiCliVersion = explicitVersion;
27
+ return cachedGeminiCliVersion;
28
+ }
29
+
30
+ if (GEMINI_CLI_VERSION.trim()) {
31
+ cachedGeminiCliVersion = GEMINI_CLI_VERSION.trim();
32
+ return cachedGeminiCliVersion;
33
+ }
34
+
35
+ const envVersion = process.env.npm_package_version?.trim();
36
+ if (envVersion) {
37
+ cachedGeminiCliVersion = envVersion;
38
+ return cachedGeminiCliVersion;
39
+ }
40
+
41
+ const moduleDir = dirname(fileURLToPath(import.meta.url));
42
+ const candidatePaths = [
43
+ join(moduleDir, "../../package.json"),
44
+ join(moduleDir, "../package.json"),
45
+ join(process.cwd(), "package.json"),
46
+ ];
47
+
48
+ for (const packagePath of candidatePaths) {
49
+ try {
50
+ const parsed = JSON.parse(readFileSync(packagePath, "utf8")) as { version?: unknown };
51
+ if (typeof parsed.version === "string" && parsed.version.trim()) {
52
+ cachedGeminiCliVersion = parsed.version.trim();
53
+ return cachedGeminiCliVersion;
54
+ }
55
+ } catch {
56
+ continue;
57
+ }
58
+ }
59
+
60
+ cachedGeminiCliVersion = "0.0.0";
61
+ return cachedGeminiCliVersion;
62
+ }
63
+
64
+ /**
65
+ * Builds a Gemini CLI-style User-Agent string.
66
+ */
67
+ export function buildGeminiCliUserAgent(model?: string): string {
68
+ const modelSegment = model?.trim() || GEMINI_CLI_DEFAULT_MODEL;
69
+ return `${GEMINI_CLI_UA_NAME}/${getGeminiCliVersion()}/${modelSegment} (${process.platform}; ${process.arch})`;
70
+ }
71
+
72
+ export const userAgentInternals = {
73
+ resetCache() {
74
+ cachedGeminiCliVersion = undefined;
75
+ },
76
+ };