mirror of
https://github.com/bendtherules/opencode-multi-model.git
synced 2026-08-18 13:42:21 +00:00
4.0 KiB
4.0 KiB
llm, status
| llm | status |
|---|---|
| google/gemini-3.1-pro-preview | draft |
Multi-model git worktree support plan
Goal
Enhance the multi-model tool to:
- Create a unique git worktree for each session + modelName.
- Store worktree folders inside
~/.local/share/opencode/multi-model/<sessionName>/<windowName>. - Initialize
opencodewith that specific worktree to avoid conflicts.
Implementation Details
- Target file:
.opencode/tools/multi-model.ts - Path Sanitization:
- Sanitize
sessionName(e.g., replace non-alphanumeric with hyphens) to ensure safe paths and branch names.windowNameis already sanitized by existing code.
- Sanitize
- Worktree Path Construction:
worktreePath:~/.local/share/opencode/multi-model/<sanitizedSessionName>/<windowName>.
- Git Repository Check:
- Run
git rev-parse --is-inside-work-treeat the start ofexecute. - If false, gracefully fail with an error
multi-model requires a git repository.
- Run
- Creating Worktrees:
- Iterate through
windowPlansto create tmux windows:- Generate
worktreePath. - Generate
branchNameasopencode/<sanitizedSessionName>/<windowName>. - Handle edge cases (Fail Fast approach):
- Run
fs.existsSync(worktreePath)to check if the path exists. If it does, fail fast with an error indicating the path collision. - Run
git show-ref --verify --quiet refs/heads/<branchName>to check if the branch exists. If it does, fail fast with an error indicating the branch collision.
- Run
- Run
git worktree add -b <branchName> <worktreePath>to create the new branch and worktree.
- Generate
- In
tmux new-sessionandtmux new-window, pass the newly createdworktreePathto the-cargument instead ofcontext.directory.
- Iterate through
- Cleanup Strategy:
- On launch failure: If
tmuxoropencodelaunch fails after worktree creation, rungit worktree remove -f <worktreePath>andgit branch -D <branchName>. Keep track of successful and failed cleanups (undos) and report them in the tool output if the undo process fails. - On success: Output a command snippet to the user on how to clean up the session's worktrees and branches when done:
rm -rf ~/.local/share/opencode/multi-model/<sanitizedSessionName> && git worktree prune && git branch -d $(git branch --format='%(refname:short)' --list 'opencode/<sanitizedSessionName>/*')
- On launch failure: If
Non-obvious Code Blocks
Path Sanitization & Generation (Example):
import * as os from "node:os";
import * as path from "node:path";
import * as fs from "node:fs";
function sanitizeName(name: string): string {
return name.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
}
function getWorktreePath(safeSession: string, windowName: string): string {
return path.join(os.homedir(), ".local/share/opencode/multi-model", safeSession, windowName);
}
Creating Worktree (Example):
const safeSession = sanitizeName(sessionName);
const branchName = `opencode/${safeSession}/${plan.windowName}`;
if (fs.existsSync(worktreePath)) {
return `Error: Worktree path already exists at ${worktreePath}. Clean it up first.`;
}
const branchExists = await runCommand(["git", "show-ref", "--verify", "--quiet", `refs/heads/${branchName}`]);
if (branchExists.ok) {
return `Error: Branch '${branchName}' already exists.`;
}
const worktreeCmd = ["git", "worktree", "add", "-b", branchName, worktreePath];
const result = await runCommand(worktreeCmd);
if (!result.ok) {
return `Error: Failed to create worktree for ${plan.model}: ${result.stderr}`;
}
Cleanup on Failure (Example):
async function undoWorktree(worktreePath: string, branchName: string): Promise<string[]> {
const errors: string[] = [];
const removeRes = await runCommand(["git", "worktree", "remove", "-f", worktreePath]);
if (!removeRes.ok) errors.push(`Failed to remove worktree ${worktreePath}: ${removeRes.stderr}`);
const branchRes = await runCommand(["git", "branch", "-D", branchName]);
if (!branchRes.ok) errors.push(`Failed to delete branch ${branchName}: ${branchRes.stderr}`);
return errors;
}