diff --git a/packages/desktop/scripts/utils.ts b/packages/desktop/scripts/utils.ts index 36df4a18fd..bf728758ed 100644 --- a/packages/desktop/scripts/utils.ts +++ b/packages/desktop/scripts/utils.ts @@ -72,17 +72,23 @@ export function getCurrentCli(target = RUST_TARGET ?? nativeTarget()) { export async function downloadCliToResources() { const cli = getCurrentCli() const directory = await mkdtemp(join(tmpdir(), "opencode-cli-")) - await $`bun install --no-save --cwd ${directory} ${`${cli.package}@${CLI_VERSION}`} ${`--os=${cli.os}`} ${`--cpu=${cli.cpu}`}` - const source = join(directory, "node_modules", cli.package, "bin", cli.os === "win32" ? "opencode2.exe" : "opencode2") const dest = windowsify("resources/opencode-cli") - await copyFile(source, dest).finally(() => rm(directory, { recursive: true, force: true })) + try { + await $`bun install --no-save --cwd ${directory} ${`${cli.package}@${CLI_VERSION}`} ${`--os=${cli.os}`} ${`--cpu=${cli.cpu}`}` + await copyFile( + join(directory, "node_modules", cli.package, "bin", cli.os === "win32" ? "opencode2.exe" : "opencode2"), + dest, + ) + } finally { + await rm(directory, { recursive: true, force: true }) + } if (process.platform !== "win32") await chmod(dest, 0o755) if (process.platform === "win32" && process.env.GITHUB_ACTIONS === "true") { await $`pwsh -NoLogo -NoProfile -ExecutionPolicy Bypass -File ../../script/sign-windows.ps1 ${dest}` } if (process.platform === "darwin") await $`codesign --force --sign - ${dest}` - console.log(`Copied ${source} to ${dest}`) + console.log(`Copied ${cli.package} to ${dest}`) } export function windowsify(path: string) { diff --git a/packages/desktop/src/main/background-cli.ts b/packages/desktop/src/main/background-cli.ts index 6d26ce9daf..66602d51f1 100644 --- a/packages/desktop/src/main/background-cli.ts +++ b/packages/desktop/src/main/background-cli.ts @@ -16,7 +16,7 @@ type Logger = { error(message: string, meta?: Record): void } -export async function startBackgroundCli(logger: Logger) { +export async function startBackgroundCli(logger: Logger, shellStateHome?: string) { const bundled = app.isPackaged ? join(process.resourcesPath, executableName()) : join(root, "../../resources", executableName()) @@ -25,7 +25,7 @@ export async function startBackgroundCli(logger: Logger) { const binary = app.isPackaged ? await installCli(bundled, version, logger) : bundled const candidates = [ - ...new Set([stateHome, ...desktopStateNames.map((name) => join(app.getPath("appData"), name))]), + ...new Set([stateHome, shellStateHome, ...desktopStateNames.map((name) => join(app.getPath("appData"), name))]), ].filter((candidate) => candidate === undefined || existsSync(candidate)) const discovered = await Promise.all( candidates.map(async (candidate) => ({ @@ -40,7 +40,7 @@ export async function startBackgroundCli(logger: Logger) { }) const daemonStateHome = found?.stateHome ?? stateHome - const url = found?.url ?? (await run(binary, ["service", "start"], logger, { stateHome: daemonStateHome })) + const url = await run(binary, ["service", "start"], logger, { stateHome: daemonStateHome }) const password = await run(binary, ["service", "get", "password"], logger, { redact: true, stateHome: daemonStateHome, diff --git a/packages/desktop/src/main/index.ts b/packages/desktop/src/main/index.ts index 9e2e05244a..7430b6c7ef 100644 --- a/packages/desktop/src/main/index.ts +++ b/packages/desktop/src/main/index.ts @@ -201,7 +201,7 @@ const main = Effect.gen(function* () { return } - preferAppEnv(app.getPath("userData")) + const shellEnv = preferAppEnv(app.getPath("userData")) app.on("second-instance", (_event: Event, argv: string[]) => { const urls = argv.filter((arg: string) => arg.startsWith("opencode://")) @@ -315,33 +315,6 @@ const main = Effect.gen(function* () { ), ) - const port = yield* Effect.gen(function* () { - const fromEnv = process.env.OPENCODE_PORT - if (fromEnv) { - const parsed = Number.parseInt(fromEnv, 10) - if (!Number.isNaN(parsed)) return parsed - } - - const res = yield* Deferred.make() - const server = createServer() - server.on("error", (e) => Deferred.failSync(res, () => e)) - server.listen(0, "127.0.0.1", () => { - const address = server.address() - if (typeof address !== "object" || !address) { - server.close() - Deferred.failSync(res, () => new Error("Failed to get port")) - return - } - const port = address.port - server.close(() => Effect.runSync(Deferred.succeed(res, port))) - }) - - return yield* Deferred.await(res) - }) - const hostname = "127.0.0.1" - const url = `http://${hostname}:${port}` - const password = randomUUID() - const loadingTask = yield* Effect.gen(function* () { logger.log("sidecar connection started", { version: SIDECAR_VERSION }) @@ -350,7 +323,7 @@ const main = Effect.gen(function* () { if (SIDECAR_VERSION === "v2") { logger.log("spawning v2 sidecar") - const sidecar = yield* Effect.promise(() => startBackgroundCli(logger)) + const sidecar = yield* Effect.promise(() => startBackgroundCli(logger, shellEnv?.XDG_STATE_HOME)) yield* Deferred.succeed(serverReady, { url: sidecar.url, username: sidecar.username, @@ -365,6 +338,33 @@ const main = Effect.gen(function* () { return } + const port = yield* Effect.gen(function* () { + const fromEnv = process.env.OPENCODE_PORT + if (fromEnv) { + const parsed = Number.parseInt(fromEnv, 10) + if (!Number.isNaN(parsed)) return parsed + } + + const res = yield* Deferred.make() + const socket = createServer() + socket.on("error", (e) => Deferred.failSync(res, () => e)) + socket.listen(0, "127.0.0.1", () => { + const address = socket.address() + if (typeof address !== "object" || !address) { + socket.close() + Deferred.failSync(res, () => new Error("Failed to get port")) + return + } + const port = address.port + socket.close(() => Effect.runSync(Deferred.succeed(res, port))) + }) + + return yield* Deferred.await(res) + }) + const hostname = "127.0.0.1" + const url = `http://${hostname}:${port}` + const password = randomUUID() + logger.log("spawning sidecar", { url }) const { listener, health } = yield* Effect.promise(() => spawnLocalServer(hostname, port, password, { diff --git a/packages/desktop/src/main/server.ts b/packages/desktop/src/main/server.ts index c620b76ae8..ae1a98efdf 100644 --- a/packages/desktop/src/main/server.ts +++ b/packages/desktop/src/main/server.ts @@ -43,13 +43,15 @@ export function setDefaultServerUrl(url: string | null) { export function preferAppEnv(userDataPath: string) { const shell = process.platform === "win32" ? null : getUserShell() + const shellEnv = shell ? loadShellEnv(shell, getLogger()) : null Object.assign(process.env, { - ...(shell ? loadShellEnv(shell, getLogger()) : null), + ...shellEnv, OPENCODE_EXPERIMENTAL_ICON_DISCOVERY: "true", OPENCODE_EXPERIMENTAL_FILEWATCHER: "true", OPENCODE_CLIENT: "desktop", XDG_STATE_HOME: process.env.XDG_STATE_HOME ?? userDataPath, }) + return shellEnv } export async function spawnLocalServer(