Skip to content

Commit 9adcf52

Browse files
committed
core: bundle GitLab auth plugin directly instead of dynamic install
Remove dynamic installation of built-in plugins. GitLab auth is now imported directly as an internal plugin, eliminating network requests during startup and simplifying the plugin loading logic. Removes the need for test mocks since plugins are no longer dynamically installed at runtime.
1 parent 531b194 commit 9adcf52

File tree

7 files changed

+97
-120
lines changed

7 files changed

+97
-120
lines changed

bun.lock

Lines changed: 79 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/opencode/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
"@ai-sdk/xai": "2.0.51",
7373
"@clack/prompts": "1.0.0-alpha.1",
7474
"@gitlab/gitlab-ai-provider": "3.4.0",
75+
"@gitlab/opencode-gitlab-auth": "1.3.2",
7576
"@hono/standard-validator": "0.1.5",
7677
"@hono/zod-validator": "catalog:",
7778
"@modelcontextprotocol/sdk": "1.25.2",

packages/opencode/src/config/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ export namespace Config {
274274
...(proxied() ? ["--no-cache"] : []),
275275
],
276276
{ cwd: dir },
277-
).catch(() => {})
277+
)
278278
}
279279

280280
async function isWritable(dir: string) {

packages/opencode/src/plugin/index.ts

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,15 @@ import { createOpencodeClient } from "@opencode-ai/sdk"
66
import { Server } from "../server/server"
77
import { BunProc } from "../bun"
88
import { Instance } from "../project/instance"
9-
import { Flag } from "../flag/flag"
109
import { CodexAuthPlugin } from "./codex"
11-
import { Session } from "../session"
12-
import { NamedError } from "@opencode-ai/util/error"
1310
import { CopilotAuthPlugin } from "./copilot"
11+
import { gitlabAuthPlugin as GitlabAuthPlugin } from "@gitlab/opencode-gitlab-auth"
1412

1513
export namespace Plugin {
1614
const log = Log.create({ service: "plugin" })
1715

18-
const BUILTIN = ["opencode-anthropic-auth@0.0.13", "@gitlab/opencode-gitlab-auth@1.3.2"]
19-
2016
// Built-in plugins that are directly imported (not installed from npm)
21-
const INTERNAL_PLUGINS: PluginInstance[] = [CodexAuthPlugin, CopilotAuthPlugin]
17+
const INTERNAL_PLUGINS: PluginInstance[] = [CodexAuthPlugin, CopilotAuthPlugin, GitlabAuthPlugin]
2218

2319
const state = Instance.state(async () => {
2420
const client = createOpencodeClient({
@@ -45,9 +41,6 @@ export namespace Plugin {
4541

4642
const plugins = [...(config.plugin ?? [])]
4743
if (plugins.length) await Config.waitForDependencies()
48-
if (!Flag.OPENCODE_DISABLE_DEFAULT_PLUGINS) {
49-
plugins.push(...BUILTIN)
50-
}
5144

5245
for (let plugin of plugins) {
5346
// ignore old codex plugin since it is supported first party now
@@ -57,24 +50,7 @@ export namespace Plugin {
5750
const lastAtIndex = plugin.lastIndexOf("@")
5851
const pkg = lastAtIndex > 0 ? plugin.substring(0, lastAtIndex) : plugin
5952
const version = lastAtIndex > 0 ? plugin.substring(lastAtIndex + 1) : "latest"
60-
const builtin = BUILTIN.some((x) => x.startsWith(pkg + "@"))
61-
plugin = await BunProc.install(pkg, version).catch((err) => {
62-
if (!builtin) throw err
63-
64-
const message = err instanceof Error ? err.message : String(err)
65-
log.error("failed to install builtin plugin", {
66-
pkg,
67-
version,
68-
error: message,
69-
})
70-
Bus.publish(Session.Event.Error, {
71-
error: new NamedError.Unknown({
72-
message: `Failed to install built-in plugin ${pkg}@${version}: ${message}`,
73-
}).toObject(),
74-
})
75-
76-
return ""
77-
})
53+
plugin = await BunProc.install(pkg, version)
7854
if (!plugin) continue
7955
}
8056
const mod = await import(plugin)

packages/opencode/test/provider/amazon-bedrock.test.ts

Lines changed: 6 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,12 @@
1-
import { test, expect, mock, describe } from "bun:test"
1+
import { test, expect, describe } from "bun:test"
22
import path from "path"
33
import { unlink } from "fs/promises"
44

5-
// === Mocks ===
6-
// These mocks are required because Provider.list() triggers:
7-
// 1. BunProc.install("@aws-sdk/credential-providers") - in bedrock custom loader
8-
// 2. Plugin.list() which calls BunProc.install() for default plugins
9-
// Without mocks, these would attempt real package installations that timeout in tests.
10-
11-
mock.module("../../src/bun/index", () => ({
12-
BunProc: {
13-
install: async (pkg: string, _version?: string) => {
14-
// Return package name without version for mocking
15-
const lastAtIndex = pkg.lastIndexOf("@")
16-
return lastAtIndex > 0 ? pkg.substring(0, lastAtIndex) : pkg
17-
},
18-
run: async () => {
19-
throw new Error("BunProc.run should not be called in tests")
20-
},
21-
which: () => process.execPath,
22-
InstallFailedError: class extends Error {},
23-
},
24-
}))
25-
26-
mock.module("@aws-sdk/credential-providers", () => ({
27-
fromNodeProviderChain: () => async () => ({
28-
accessKeyId: "mock-access-key-id",
29-
secretAccessKey: "mock-secret-access-key",
30-
}),
31-
}))
32-
33-
const mockPlugin = () => ({})
34-
mock.module("opencode-copilot-auth", () => ({ default: mockPlugin }))
35-
mock.module("opencode-anthropic-auth", () => ({ default: mockPlugin }))
36-
mock.module("@gitlab/opencode-gitlab-auth", () => ({ default: mockPlugin }))
37-
38-
// Import after mocks are set up
39-
const { tmpdir } = await import("../fixture/fixture")
40-
const { Instance } = await import("../../src/project/instance")
41-
const { Provider } = await import("../../src/provider/provider")
42-
const { Env } = await import("../../src/env")
43-
const { Global } = await import("../../src/global")
5+
import { tmpdir } from "../fixture/fixture"
6+
import { Instance } from "../../src/project/instance"
7+
import { Provider } from "../../src/provider/provider"
8+
import { Env } from "../../src/env"
9+
import { Global } from "../../src/global"
4410

4511
test("Bedrock: config region takes precedence over AWS_REGION env var", async () => {
4612
await using tmp = await tmpdir({

packages/opencode/test/provider/gitlab-duo.test.ts

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,11 @@
1-
import { test, expect, mock } from "bun:test"
1+
import { test, expect } from "bun:test"
22
import path from "path"
33

4-
// === Mocks ===
5-
// These mocks prevent real package installations during tests
6-
7-
mock.module("../../src/bun/index", () => ({
8-
BunProc: {
9-
install: async (pkg: string, _version?: string) => {
10-
// Return package name without version for mocking
11-
const lastAtIndex = pkg.lastIndexOf("@")
12-
return lastAtIndex > 0 ? pkg.substring(0, lastAtIndex) : pkg
13-
},
14-
run: async () => {
15-
throw new Error("BunProc.run should not be called in tests")
16-
},
17-
which: () => process.execPath,
18-
InstallFailedError: class extends Error {},
19-
},
20-
}))
21-
22-
const mockPlugin = () => ({})
23-
mock.module("opencode-copilot-auth", () => ({ default: mockPlugin }))
24-
mock.module("opencode-anthropic-auth", () => ({ default: mockPlugin }))
25-
mock.module("@gitlab/opencode-gitlab-auth", () => ({ default: mockPlugin }))
26-
27-
// Import after mocks are set up
28-
const { tmpdir } = await import("../fixture/fixture")
29-
const { Instance } = await import("../../src/project/instance")
30-
const { Provider } = await import("../../src/provider/provider")
31-
const { Env } = await import("../../src/env")
32-
const { Global } = await import("../../src/global")
4+
import { tmpdir } from "../fixture/fixture"
5+
import { Instance } from "../../src/project/instance"
6+
import { Provider } from "../../src/provider/provider"
7+
import { Env } from "../../src/env"
8+
import { Global } from "../../src/global"
339

3410
test("GitLab Duo: loads provider with API key from environment", async () => {
3511
await using tmp = await tmpdir({

packages/opencode/test/provider/provider.test.ts

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,6 @@
1-
import { test, expect, mock } from "bun:test"
1+
import { test, expect } from "bun:test"
22
import path from "path"
33

4-
// Mock BunProc and default plugins to prevent actual installations during tests
5-
mock.module("../../src/bun/index", () => ({
6-
BunProc: {
7-
install: async (pkg: string, _version?: string) => {
8-
// Return package name without version for mocking
9-
const lastAtIndex = pkg.lastIndexOf("@")
10-
return lastAtIndex > 0 ? pkg.substring(0, lastAtIndex) : pkg
11-
},
12-
run: async () => {
13-
throw new Error("BunProc.run should not be called in tests")
14-
},
15-
which: () => process.execPath,
16-
InstallFailedError: class extends Error {},
17-
},
18-
}))
19-
20-
const mockPlugin = () => ({})
21-
mock.module("opencode-copilot-auth", () => ({ default: mockPlugin }))
22-
mock.module("opencode-anthropic-auth", () => ({ default: mockPlugin }))
23-
mock.module("@gitlab/opencode-gitlab-auth", () => ({ default: mockPlugin }))
24-
254
import { tmpdir } from "../fixture/fixture"
265
import { Instance } from "../../src/project/instance"
276
import { Provider } from "../../src/provider/provider"

0 commit comments

Comments
 (0)