Skip to content

Commit fbfd6db

Browse files
author
chenbo
committed
Use async OpenCode TUI launch
1 parent a676630 commit fbfd6db

2 files changed

Lines changed: 27 additions & 6 deletions

File tree

docs/integrations/opencode-sidecar.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,5 @@ If you want to use OpenCode without OpenCode++ for a session:
165165
```bash
166166
opencode-plusplus --pure
167167
```
168+
169+
If copy/paste feels intercepted inside the OpenCode TUI, use your terminal-level paste shortcut, such as `Ctrl+Shift+V`, right-click paste, or the terminal menu. OpenCode++ launches OpenCode with inherited stdio so terminal clipboard handling stays outside the sidecar.

src/integrations/opencode/launcher.ts

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { spawnSync } from "node:child_process";
1+
import { spawn } from "node:child_process";
22
import { existsSync } from "node:fs";
33
import path from "node:path";
44
import { buildContextPackage } from "../../core/context-builder.js";
@@ -57,7 +57,7 @@ export async function launchOpenCodeWithSidecar(options: OpenCodeLauncherOptions
5757
if (!opencode.ok) return { repo, steps, command, launched: false, exitCode: 1 };
5858
if (options.dryRun) return { repo, steps, command, launched: false, exitCode: 0 };
5959
options.onPreflight?.({ repo, steps, command });
60-
const result = spawnOpenCodeTui(repo);
60+
const result = await spawnOpenCodeTui(repo);
6161
return { repo, steps, command, launched: true, exitCode: typeof result.status === "number" ? result.status : result.error ? 1 : null };
6262
}
6363

@@ -105,7 +105,7 @@ export async function launchOpenCodeWithSidecar(options: OpenCodeLauncherOptions
105105
}
106106

107107
options.onPreflight?.({ repo, steps, command });
108-
const result = spawnOpenCodeTui(repo);
108+
const result = await spawnOpenCodeTui(repo);
109109
return { repo, steps, command, launched: true, exitCode: typeof result.status === "number" ? result.status : result.error ? 1 : null };
110110
}
111111

@@ -162,10 +162,29 @@ function checkGitRepo(repo: string): { ok: boolean; error: string } {
162162
}
163163
}
164164

165-
function spawnOpenCodeTui(repo: string): ReturnType<typeof spawnSync> {
166-
const result = spawnSync("opencode", [repo], { cwd: repo, stdio: "inherit", shell: false });
165+
async function spawnOpenCodeTui(repo: string): Promise<{ status: number | null; error?: Error }> {
166+
const result = await spawnOpenCodeProcess("opencode", [repo], repo);
167167
if (!shouldTryWindowsCmdFallback(result.error)) return result;
168-
return spawnSync("cmd.exe", ["/d", "/s", "/c", `opencode.cmd ${windowsCmdQuote(repo)}`], { cwd: repo, stdio: "inherit", shell: false });
168+
return spawnOpenCodeProcess("cmd.exe", ["/d", "/s", "/c", `opencode.cmd ${windowsCmdQuote(repo)}`], repo);
169+
}
170+
171+
function spawnOpenCodeProcess(command: string, args: string[], cwd: string): Promise<{ status: number | null; error?: Error }> {
172+
return new Promise((resolve) => {
173+
const child = spawn(command, args, { cwd, stdio: "inherit", shell: false });
174+
let settled = false;
175+
176+
child.once("error", (error) => {
177+
if (settled) return;
178+
settled = true;
179+
resolve({ status: null, error });
180+
});
181+
182+
child.once("close", (code) => {
183+
if (settled) return;
184+
settled = true;
185+
resolve({ status: code });
186+
});
187+
});
169188
}
170189

171190
function shouldTryWindowsCmdFallback(error: Error | undefined): boolean {

0 commit comments

Comments
 (0)