fix: add script invocation of opencode bash
This commit is contained in:
parent
b1b32adb0f
commit
9a09d8be25
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 754ac957381d4b32ed245f4e4346999f4ca1b5f8
|
||||
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 866c056d82fdaea3786812fd42af5746e743741f
|
||||
|
|
@ -0,0 +1 @@
|
|||
Subproject commit b052b6af3c230ec50be57f6d18e70149ceacaf7e
|
||||
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 59044e9ffe4681192a264d29816119c62126693f
|
||||
|
|
@ -64,8 +64,8 @@ function parseSessionList(raw: string): OpenCodeSessionListEntry[] {
|
|||
|
||||
/**
|
||||
* Parse JSON stream lines from `opencode run --format json` output.
|
||||
* Each line is a JSON object. We look for objects containing a session_id field.
|
||||
* The step_start event typically contains the session_id.
|
||||
* Each line is a JSON object. Different OpenCode versions emit either
|
||||
* `session_id` or `sessionID`, so accept both.
|
||||
*/
|
||||
function buildSessionIdCaptureScript(): string {
|
||||
const script = `
|
||||
|
|
@ -81,8 +81,9 @@ process.stdin.on('data', chunk => {
|
|||
if (!trimmed) continue;
|
||||
try {
|
||||
const obj = JSON.parse(trimmed);
|
||||
if (obj && typeof obj.session_id === 'string' && /^ses_[A-Za-z0-9_-]+$/.test(obj.session_id)) {
|
||||
captured = obj.session_id;
|
||||
const candidate = obj?.session_id ?? obj?.sessionID;
|
||||
if (typeof candidate === 'string' && /^ses_[A-Za-z0-9_-]+$/.test(candidate)) {
|
||||
captured = candidate;
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
|
@ -90,8 +91,9 @@ process.stdin.on('data', chunk => {
|
|||
if (buffer.trim()) {
|
||||
try {
|
||||
const obj = JSON.parse(buffer.trim());
|
||||
if (obj && typeof obj.session_id === 'string' && /^ses_[A-Za-z0-9_-]+$/.test(obj.session_id)) {
|
||||
captured = obj.session_id;
|
||||
const candidate = obj?.session_id ?? obj?.sessionID;
|
||||
if (typeof candidate === 'string' && /^ses_[A-Za-z0-9_-]+$/.test(candidate)) {
|
||||
captured = candidate;
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
|
@ -204,7 +206,12 @@ function createOpenCodeAgent(): Agent {
|
|||
];
|
||||
const captureScript = buildSessionIdCaptureScript();
|
||||
const fallbackScript = buildSessionLookupScript();
|
||||
const runCommand = ["opencode", "run", ...runOptions, "--command", "true"].join(" ");
|
||||
const runCommand = [
|
||||
"opencode",
|
||||
"run",
|
||||
...runOptions,
|
||||
shellEscape("Create a session and reply with exactly: READY"),
|
||||
].join(" ");
|
||||
const resumeOptions = [...(promptValue ? ["--prompt", promptValue] : []), ...sharedOptions];
|
||||
const resumeOptionsSuffix = resumeOptions.length > 0 ? ` ${resumeOptions.join(" ")}` : "";
|
||||
const missingSessionError = shellEscape(
|
||||
|
|
|
|||
|
|
@ -148,6 +148,48 @@ describe("runtime.create()", () => {
|
|||
);
|
||||
});
|
||||
|
||||
it("uses a temp launch script for long launch commands", async () => {
|
||||
const runtime = create();
|
||||
const longCommand = "x".repeat(250);
|
||||
|
||||
mockTmuxSuccess();
|
||||
mockTmuxSuccess();
|
||||
mockTmuxSuccess();
|
||||
|
||||
await runtime.create({
|
||||
sessionId: "launch-long",
|
||||
workspacePath: "/tmp/ws",
|
||||
launchCommand: longCommand,
|
||||
environment: {},
|
||||
});
|
||||
|
||||
expect(fs.writeFileSync).toHaveBeenCalledWith(
|
||||
expect.stringContaining("ao-launch-test-uuid-1234.sh"),
|
||||
expect.stringContaining(longCommand),
|
||||
{ encoding: "utf-8", mode: 0o700 },
|
||||
);
|
||||
|
||||
expect(mockExecFileCustom).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
"tmux",
|
||||
[
|
||||
"send-keys",
|
||||
"-t",
|
||||
"launch-long",
|
||||
"-l",
|
||||
expect.stringContaining("bash "),
|
||||
],
|
||||
expectedTmuxOptions,
|
||||
);
|
||||
|
||||
expect(mockExecFileCustom).toHaveBeenNthCalledWith(
|
||||
3,
|
||||
"tmux",
|
||||
["send-keys", "-t", "launch-long", "Enter"],
|
||||
expectedTmuxOptions,
|
||||
);
|
||||
});
|
||||
|
||||
it("cleans up session if send-keys fails", async () => {
|
||||
const runtime = create();
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,21 @@ function assertValidSessionId(id: string): void {
|
|||
}
|
||||
}
|
||||
|
||||
function shellQuote(value: string): string {
|
||||
return `'${value.replace(/'/g, `'\\''`)}'`;
|
||||
}
|
||||
|
||||
function writeLaunchScript(command: string): string {
|
||||
const scriptPath = join(tmpdir(), `ao-launch-${randomUUID()}.sh`);
|
||||
const content = `#!/usr/bin/env bash
|
||||
rm -- "$0" 2>/dev/null || true
|
||||
${command}
|
||||
`;
|
||||
writeFileSync(scriptPath, content, { encoding: "utf-8", mode: 0o700 });
|
||||
const invocation = `bash ${shellQuote(scriptPath)}`;
|
||||
return invocation
|
||||
}
|
||||
|
||||
/** Run a tmux command and return stdout */
|
||||
async function tmux(...args: string[]): Promise<string> {
|
||||
const { stdout } = await execFileAsync("tmux", args, {
|
||||
|
|
@ -59,23 +74,12 @@ export function create(): Runtime {
|
|||
await tmux("new-session", "-d", "-s", sessionName, "-c", config.workspacePath, ...envArgs);
|
||||
|
||||
// Send the launch command — clean up the session if this fails.
|
||||
// Use load-buffer + paste-buffer for long commands to avoid tmux/zsh
|
||||
// truncation issues (commands >200 chars get mangled by send-keys).
|
||||
// Use a temp script for long commands so the pane shows a short
|
||||
// invocation instead of a pasted wall of shell.
|
||||
try {
|
||||
if (config.launchCommand.length > 200) {
|
||||
const bufferName = `ao-launch-${randomUUID().slice(0, 8)}`;
|
||||
const tmpPath = join(tmpdir(), `ao-launch-${randomUUID()}.txt`);
|
||||
writeFileSync(tmpPath, config.launchCommand, { encoding: "utf-8", mode: 0o600 });
|
||||
try {
|
||||
await tmux("load-buffer", "-b", bufferName, tmpPath);
|
||||
await tmux("paste-buffer", "-b", bufferName, "-t", sessionName, "-d");
|
||||
} finally {
|
||||
try {
|
||||
unlinkSync(tmpPath);
|
||||
} catch {
|
||||
/* ignore cleanup errors */
|
||||
}
|
||||
}
|
||||
const invocation = writeLaunchScript(config.launchCommand);
|
||||
await tmux("send-keys", "-t", sessionName, "-l", invocation);
|
||||
await sleep(300);
|
||||
await tmux("send-keys", "-t", sessionName, "Enter");
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Reference in New Issue