build: remember last models

This commit is contained in:
2026-03-23 16:54:51 +05:30
parent fabd2f6519
commit af5d888f56
10 changed files with 204 additions and 43 deletions
+24 -3
View File
@@ -4,7 +4,7 @@ import pkg from "../package.json";
import { cleanupMultiModel } from "./core/cleanup";
import { closeMultiModel } from "./core/close";
import { openMultiModel } from "./core/open";
import { getBinaryName } from "./core/utils";
import { getBinaryName, loadSettings, promptUser } from "./core/utils";
const program = new Command();
@@ -26,19 +26,40 @@ program
"-b, --binary <binary>",
"Binary to use (opencode or kilo). Defaults to env var OPENCODE_MULTI_MODEL_BINARY or 'opencode'",
)
.option("-f, --force", "Skip confirmation prompts", false)
.action(
async (
sessionName: string,
options: { models: string[]; binary?: string },
options: { models: string[]; binary?: string; force: boolean },
) => {
try {
let models = options.models;
if (models.length === 0) {
const settings = await loadSettings();
if (settings.lastModels.length > 0) {
if (!options.force) {
const answer = await promptUser(
`Use models [${models.join(", ")}]? (Y/n): `,
);
if (answer.toLowerCase() === "y" || answer.toLowerCase() === "yes") {
models = settings.lastModels;
}
} else {
models = settings.lastModels;
}
}
}
const binaryName = options.binary || getBinaryName();
const result = await openMultiModel({
sessionName,
models: options.models,
models,
binaryName,
mode: "cli",
saveToSettings: true,
});
if (result.success) {
+1 -18
View File
@@ -1,23 +1,6 @@
import * as readline from "node:readline";
import chalk from "chalk";
import type { CleanupOptions, CleanupResult } from "../types";
import { runCommand } from "./utils";
/**
* Prompts the user for confirmation on the terminal.
*/
async function promptUser(question: string): Promise<string> {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
return new Promise((resolve) => {
rl.question(question, (answer) => {
rl.close();
resolve(answer);
});
});
}
import { promptUser, runCommand } from "./utils";
/**
* Lists all archive tags matching the pattern archive/*.
+1 -21
View File
@@ -1,33 +1,13 @@
import * as readline from "node:readline";
import chalk from "chalk"; // removed console usage
import type { CloseSessionOptions, CloseSessionResult } from "../types";
import {
getSessionPath,
getWorktreesForSession,
promptUser,
runCommand,
sanitizeName,
} from "./utils";
/**
* Prompts the user for input on the terminal.
*
* @param question The question to display.
* @returns The user's answer.
*/
async function promptUser(question: string): Promise<string> {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
return new Promise((resolve) => {
rl.question(question, (answer) => {
rl.close();
resolve(answer);
});
});
}
/**
* Closes a multi-model tmux session and optionally cleans up worktrees and branches.
*
+5
View File
@@ -10,6 +10,7 @@ import {
normalizeModels,
runCommand,
sanitizeName,
saveSettings,
undoWorktree,
} from "./utils";
@@ -313,6 +314,10 @@ export async function openMultiModel(
};
}
if (options.saveToSettings) {
await saveSettings({ lastModels: models });
}
return {
success: true,
sessionName,
+49
View File
@@ -1,8 +1,11 @@
import * as fs from "node:fs";
import * as os from "node:os";
import * as path from "node:path";
import * as readline from "node:readline";
import ora, { type Ora } from "ora";
import type {
CommandResult,
MultiModelSettings,
RunCommandOptions,
WindowLaunchPlan,
WorktreeInfo,
@@ -489,3 +492,49 @@ export async function undoWorktree(
export function getBinaryName(): string {
return process.env.OPENCODE_MULTI_MODEL_BINARY || "opencode";
}
export function getSettingsPath(): string {
const homedir = os.homedir();
return path.join(homedir, ".config", "opencode-multi-model", "settings.json");
}
export async function loadSettings(): Promise<MultiModelSettings> {
const settingsPath = getSettingsPath();
try {
const content = await fs.promises.readFile(settingsPath, "utf-8");
const parsed = JSON.parse(content) as MultiModelSettings;
if (!Array.isArray(parsed.lastModels)) {
return { lastModels: [] };
}
return parsed;
} catch {
return { lastModels: [] };
}
}
export async function saveSettings(
settings: MultiModelSettings,
): Promise<void> {
const settingsPath = getSettingsPath();
const dir = path.dirname(settingsPath);
await fs.promises.mkdir(dir, { recursive: true });
await fs.promises.writeFile(
settingsPath,
JSON.stringify(settings, null, 2),
"utf-8",
);
}
export async function promptUser(question: string): Promise<string> {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
return new Promise((resolve) => {
rl.question(question, (answer) => {
rl.close();
resolve(answer);
});
});
}
+9
View File
@@ -1,3 +1,10 @@
/**
* Settings stored in ~/.config/opencode-multi-model/settings.json
*/
export interface MultiModelSettings {
lastModels: string[];
}
/**
* Options for launching a multi-model tmux session.
*/
@@ -10,6 +17,8 @@ export interface MultiModelOptions {
binaryName?: string;
/** Caller context: 'cli' shows shell commands, 'tool' shows tool instructions. */
mode: "cli" | "tool";
/** Save models to settings file on successful launch (CLI only). */
saveToSettings?: boolean;
}
/**