From 3899c2d1e55600a2ca74c2f619c349a17e1578ae Mon Sep 17 00:00:00 2001 From: shuv Date: Fri, 2 Jan 2026 12:48:54 -0800 Subject: [PATCH 1/2] refactor: remove .deps-installed.json marker file to match upstream Revert to upstream behavior for plugin dependency installation: - Skip dependency installation when running locally (isLocal check) - Remove marker file caching mechanism that was dropping .deps-installed.json in user project directories - Remove .deps-installed.json from .gitignore template - Remove related test that was specific to marker file behavior This fixes user confusion when .deps-installed.json appears in project directories, matching upstream opencode behavior. --- packages/opencode/src/config/config.ts | 89 ++++---------------- packages/opencode/test/config/config.test.ts | 33 +------- 2 files changed, 18 insertions(+), 104 deletions(-) diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index f0bef52d560..81a13bbe392 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -165,85 +165,30 @@ export namespace Config { } } - // Per-directory install locks to serialize concurrent installs - const installLocks = new Map>() - - // Marker file schema for tracking installed dependencies - const DepsInstalledMarker = z.object({ - version: z.string(), - timestamp: z.number(), - }) - async function installDependencies(dir: string) { - // Wait for any ongoing install in this directory to complete - const existingLock = installLocks.get(dir) - if (existingLock) { - await existingLock - return - } + if (Installation.isLocal()) return - // Create a new lock for this directory - let resolveLock: () => void - const lockPromise = new Promise((resolve) => { - resolveLock = resolve - }) - installLocks.set(dir, lockPromise) - - try { - const markerPath = path.join(dir, ".deps-installed.json") - const targetVersion = Installation.isLocal() ? "latest" : Installation.BASE_VERSION - - // Check if dependencies are already installed with correct version - try { - const markerContent = await Bun.file(markerPath).text() - const marker = DepsInstalledMarker.parse(JSON.parse(markerContent)) - if (marker.version === targetVersion) { - log.debug("dependencies already installed", { dir, version: marker.version }) - return - } - } catch { - // Marker doesn't exist or is invalid, proceed with install - } + const pkg = path.join(dir, "package.json") - const pkg = path.join(dir, "package.json") - - if (!(await Bun.file(pkg).exists())) { - await Bun.write(pkg, "{}") - } + if (!(await Bun.file(pkg).exists())) { + await Bun.write(pkg, "{}") + } - const gitignore = path.join(dir, ".gitignore") - const hasGitIgnore = await Bun.file(gitignore).exists() - if (!hasGitIgnore) { - await Bun.write( - gitignore, - ["node_modules", "package.json", "bun.lock", ".gitignore", ".deps-installed.json"].join("\n"), - ) - } + const gitignore = path.join(dir, ".gitignore") + const hasGitIgnore = await Bun.file(gitignore).exists() + if (!hasGitIgnore) await Bun.write(gitignore, ["node_modules", "package.json", "bun.lock", ".gitignore"].join("\n")) - // Use BASE_VERSION for @opencode-ai/plugin since it's published by upstream without our -N suffix - await BunProc.run(["add", "@opencode-ai/plugin@" + targetVersion, "--exact"], { + // Use BASE_VERSION for @opencode-ai/plugin since it's published by upstream without our -N suffix + await BunProc.run( + ["add", "@opencode-ai/plugin@" + (Installation.isLocal() ? "latest" : Installation.BASE_VERSION), "--exact"], + { cwd: dir, - }) - - // Install any additional dependencies defined in the package.json - // This allows local plugins and custom tools to use external packages - await BunProc.run(["install"], { cwd: dir }).catch(() => {}) + }, + ).catch(() => {}) - // Write marker file after successful install - await Bun.write( - markerPath, - JSON.stringify({ - version: targetVersion, - timestamp: Date.now(), - }), - ) - log.info("dependencies installed", { dir, version: targetVersion }) - } catch (err) { - log.error("failed to install dependencies", { dir, error: err }) - } finally { - installLocks.delete(dir) - resolveLock!() - } + // Install any additional dependencies defined in the package.json + // This allows local plugins and custom tools to use external packages + await BunProc.run(["install"], { cwd: dir }).catch(() => {}) } const COMMAND_GLOB = new Bun.Glob("{command,commands}/**/*.md") diff --git a/packages/opencode/test/config/config.test.ts b/packages/opencode/test/config/config.test.ts index 2d3b148acc2..8671c7a52e7 100644 --- a/packages/opencode/test/config/config.test.ts +++ b/packages/opencode/test/config/config.test.ts @@ -724,35 +724,4 @@ test("processes .opencode directory without errors in local dev mode", async () }) }) -test(".opencode directory gets package.json and gitignore created", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - const opencodeDir = path.join(dir, ".opencode") - await fs.mkdir(opencodeDir, { recursive: true }) - }, - }) - await Instance.provide({ - directory: tmp.path, - fn: async () => { - await Config.get() - - const opencodeDir = path.join(tmp.path, ".opencode") - - // Verify package.json was created - const pkgPath = path.join(opencodeDir, "package.json") - const pkgExists = await Bun.file(pkgPath).exists() - expect(pkgExists).toBe(true) - - // Verify .gitignore was created - const gitignorePath = path.join(opencodeDir, ".gitignore") - const gitignoreExists = await Bun.file(gitignorePath).exists() - expect(gitignoreExists).toBe(true) - - // Verify .gitignore contains necessary entries - const gitignoreContent = await Bun.file(gitignorePath).text() - expect(gitignoreContent).toContain("node_modules") - expect(gitignoreContent).toContain("package.json") - expect(gitignoreContent).toContain("bun.lock") - }, - }) -}) + From 31efdbc08bb808966c16bc1385e38cef69690d41 Mon Sep 17 00:00:00 2001 From: shuv Date: Fri, 2 Jan 2026 12:58:50 -0800 Subject: [PATCH 2/2] fix: remove unreachable ternary in installDependencies Apply Greptile suggestion - the Installation.isLocal() check on line 169 returns early, making the ternary unreachable. Simplify to just use Installation.BASE_VERSION. --- packages/opencode/src/config/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index 81a13bbe392..fe5e2c90873 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -180,7 +180,7 @@ export namespace Config { // Use BASE_VERSION for @opencode-ai/plugin since it's published by upstream without our -N suffix await BunProc.run( - ["add", "@opencode-ai/plugin@" + (Installation.isLocal() ? "latest" : Installation.BASE_VERSION), "--exact"], + ["add", "@opencode-ai/plugin@" + Installation.BASE_VERSION, "--exact"], { cwd: dir, },