Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 17 additions & 72 deletions packages/opencode/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,85 +165,30 @@ export namespace Config {
}
}

// Per-directory install locks to serialize concurrent installs
const installLocks = new Map<string, Promise<void>>()

// 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<void>((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"],
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: The ternary Installation.isLocal() ? "latest" : Installation.BASE_VERSION is unreachable since line 169 returns early when Installation.isLocal() is true. Simplify to just use Installation.BASE_VERSION.

Suggested change
["add", "@opencode-ai/plugin@" + (Installation.isLocal() ? "latest" : Installation.BASE_VERSION), "--exact"],
["add", "@opencode-ai/plugin@" + Installation.BASE_VERSION, "--exact"],
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/opencode/src/config/config.ts
Line: 183:183

Comment:
**logic:** The ternary `Installation.isLocal() ? "latest" : Installation.BASE_VERSION` is unreachable since line 169 returns early when `Installation.isLocal()` is true. Simplify to just use `Installation.BASE_VERSION`.

```suggestion
      ["add", "@opencode-ai/plugin@" + Installation.BASE_VERSION, "--exact"],
```

How can I resolve this? If you propose a fix, please make it concise.

{
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")
Expand Down
33 changes: 1 addition & 32 deletions packages/opencode/test/config/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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")
},
})
})

Loading