mirror of
https://github.com/bendtherules/opencode-multi-model.git
synced 2026-08-18 13:42:21 +00:00
build: color-code open and close outputs
This commit is contained in:
+1
-13
@@ -55,19 +55,7 @@ program
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
console.log(`Closed session: ${result.sessionName}`);
|
||||
if (result.cleanupPerformed) {
|
||||
console.log(` Removed ${result.worktreesRemoved?.length || 0} worktrees`);
|
||||
if (result.tagsCreated && result.tagsCreated.length > 0) {
|
||||
console.log(` Created backup tags: ${result.tagsCreated.join(", ")}`);
|
||||
}
|
||||
if (result.warnings && result.warnings.length > 0) {
|
||||
console.log(` Warnings: ${result.warnings.join("; ")}`);
|
||||
}
|
||||
if (result.branchesDeleted && result.branchesDeleted.length > 0) {
|
||||
console.log(` Deleted ${result.branchesDeleted.length} branches`);
|
||||
}
|
||||
}
|
||||
console.log(result.instructions);
|
||||
} else {
|
||||
console.error(`Failed: ${result.error}`);
|
||||
process.exit(1);
|
||||
|
||||
+33
-18
@@ -1,6 +1,7 @@
|
||||
import * as readline from "node:readline";
|
||||
import chalk from 'chalk'; // removed console usage
|
||||
import type { CloseSessionOptions, CloseSessionResult } from "../types";
|
||||
import { runCommand, getSessionPath, getWorktreesForSession } from "./utils";
|
||||
import { runCommand, getSessionPath, getWorktreesForSession, sanitizeName } from "./utils";
|
||||
|
||||
/**
|
||||
* Prompts the user for input on the terminal.
|
||||
@@ -45,33 +46,42 @@ async function promptUser(question: string): Promise<string> {
|
||||
*/
|
||||
export async function closeMultiModel(options: CloseSessionOptions): Promise<CloseSessionResult> {
|
||||
const worktreesRemoved: string[] = [];
|
||||
const instructionsArr: string[] = [];
|
||||
const branchesDeleted: string[] = [];
|
||||
const tagsCreated: string[] = [];
|
||||
const warnings: string[] = [];
|
||||
|
||||
|
||||
const safeSessionName = sanitizeName(options.sessionName);
|
||||
try {
|
||||
// Check if session exists
|
||||
const { ok: sessionExists } = await runCommand(["tmux", "has-session", "-t", options.sessionName]);
|
||||
const { ok: sessionExists } = await runCommand(["tmux", "has-session", "-t", safeSessionName]);
|
||||
|
||||
// Kill tmux session if it exists
|
||||
if (sessionExists) {
|
||||
await runCommand(["tmux", "kill-session", "-t", options.sessionName]);
|
||||
await runCommand(["tmux", "kill-session", "-t", safeSessionName]);
|
||||
instructionsArr.push(chalk.green(`Closed session '${safeSessionName}'`));
|
||||
} else {
|
||||
instructionsArr.push(chalk.yellow(`Session '${safeSessionName}' does not exist`));
|
||||
}
|
||||
|
||||
// Get list of worktrees for this session before killing tmux
|
||||
const worktrees = await getWorktreesForSession(options.sessionName);
|
||||
const worktrees = await getWorktreesForSession(safeSessionName);
|
||||
|
||||
// If cleanup requested and not forced, ask for confirmation
|
||||
if (options.cleanupWorktrees && !options.force && worktrees.length > 0) {
|
||||
console.log(`\nThe following worktrees and branches will be removed:`);
|
||||
worktrees.forEach((wt) => console.log(` - ${wt.path} (branch: ${wt.branch})`));
|
||||
instructionsArr.push(chalk.red('The following worktrees and branches will be removed:'));
|
||||
worktrees.forEach((wt) => {
|
||||
const msg = ` - ${wt.path} (branch: ${wt.branch})`;
|
||||
instructionsArr.push(msg.trim());
|
||||
});
|
||||
|
||||
const answer = await promptUser("\nDo you want to proceed? (y/N): ");
|
||||
const answer = await promptUser(chalk.bold("\nDo you want to proceed? (y/N): "));
|
||||
if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
|
||||
return {
|
||||
success: false,
|
||||
sessionName: options.sessionName,
|
||||
sessionName: safeSessionName,
|
||||
error: "Cleanup cancelled by user",
|
||||
instructions: instructionsArr.join("\n"),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -94,20 +104,19 @@ export async function closeMultiModel(options: CloseSessionOptions): Promise<Clo
|
||||
if (tagResult.ok) {
|
||||
tagsCreated.push(archiveTag);
|
||||
} else {
|
||||
const warningMsg = `Failed to create tag ${archiveTag} for branch ${worktree.branch}.`;
|
||||
warnings.push(warningMsg);
|
||||
console.warn(`Warning: ${warningMsg}`);
|
||||
const warningMsg = chalk.red(`Warning: Failed to create tag ${archiveTag} for branch ${worktree.branch}.`);
|
||||
instructionsArr.push(warningMsg);
|
||||
}
|
||||
|
||||
await runCommand(["git", "branch", "-D", worktree.branch]);
|
||||
branchesDeleted.push(worktree.branch);
|
||||
} catch (err) {
|
||||
console.warn(`Warning: Failed to cleanup worktree ${worktree.path}: ${err}`);
|
||||
instructionsArr.push(chalk.red(`Failed to cleanup worktree ${worktree.path}: ${err}`));
|
||||
}
|
||||
}
|
||||
|
||||
// Also remove the base directory
|
||||
const worktreeBase = getSessionPath(options.sessionName);
|
||||
const worktreeBase = getSessionPath(safeSessionName);
|
||||
try {
|
||||
await runCommand(["rm", "-rf", worktreeBase]);
|
||||
} catch {
|
||||
@@ -115,26 +124,32 @@ export async function closeMultiModel(options: CloseSessionOptions): Promise<Clo
|
||||
}
|
||||
|
||||
cleanupPerformed = worktreesRemoved.length > 0;
|
||||
if (cleanupPerformed) {
|
||||
instructionsArr.push(chalk.dim(`Removed ${worktreesRemoved.length} worktrees, alongwith their branches.`));
|
||||
if (tagsCreated.length > 0) {
|
||||
instructionsArr.push(chalk.dim(`Created archive tags: ${tagsCreated.join(", ")}.`));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
sessionName: options.sessionName,
|
||||
sessionName: safeSessionName,
|
||||
cleanupPerformed,
|
||||
worktreesRemoved,
|
||||
branchesDeleted,
|
||||
tagsCreated,
|
||||
warnings,
|
||||
instructions: instructionsArr.join("\n"),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
sessionName: options.sessionName,
|
||||
sessionName: safeSessionName,
|
||||
error: String(error),
|
||||
worktreesRemoved,
|
||||
branchesDeleted,
|
||||
tagsCreated,
|
||||
warnings,
|
||||
instructions: instructionsArr.join("\n"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+6
-2
@@ -154,7 +154,9 @@ export async function openMultiModel(options: MultiModelOptions): Promise<MultiM
|
||||
if (!sessionCreateResult.ok) {
|
||||
const undoErrors = await undoWorktree(worktreePath, branchName);
|
||||
let errorMsg = `Error: Failed to create tmux session '${sessionName}'.${sessionCreateResult.stderr ? ` ${sessionCreateResult.stderr}` : ""}`;
|
||||
if (undoErrors.length > 0) errorMsg += ` Cleanup errors: ${undoErrors.join(", ")}`;
|
||||
if (undoErrors.length > 0) {
|
||||
errorMsg += ` Cleanup errors: ${undoErrors.join(", ")}`;
|
||||
}
|
||||
return { success: false, sessionName, error: errorMsg };
|
||||
}
|
||||
} else {
|
||||
@@ -173,7 +175,9 @@ export async function openMultiModel(options: MultiModelOptions): Promise<MultiM
|
||||
if (!windowCreateResult.ok) {
|
||||
failedModels.push(`${plan.model} (${windowCreateResult.stderr || "failed to create window"})`);
|
||||
const undoErrors = await undoWorktree(worktreePath, branchName);
|
||||
if (undoErrors.length > 0) failedModels.push(`cleanup failed for ${plan.model}: ${undoErrors.join(", ")}`);
|
||||
if (undoErrors.length > 0) {
|
||||
failedModels.push(`cleanup failed for ${plan.model}: ${undoErrors.join(", ")}`);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-12
@@ -25,17 +25,6 @@ export const closeTool = tool({
|
||||
return result.error!;
|
||||
}
|
||||
|
||||
let details = "";
|
||||
if (result.cleanupPerformed) {
|
||||
details += ` Removed ${result.worktreesRemoved?.length || 0} worktrees.`;
|
||||
if (result.tagsCreated && result.tagsCreated.length > 0) {
|
||||
details += ` Created backup tags: ${result.tagsCreated.join(", ")}.`;
|
||||
}
|
||||
if (result.warnings && result.warnings.length > 0) {
|
||||
details += ` Warnings: ${result.warnings.join("; ")}.`;
|
||||
}
|
||||
}
|
||||
|
||||
return `Session "${result.sessionName}" has been closed.${details}`;
|
||||
return result.instructions;
|
||||
},
|
||||
});
|
||||
|
||||
+3
-2
@@ -44,6 +44,8 @@ export interface CloseSessionOptions {
|
||||
* Result returned after attempting to close a multi-model session.
|
||||
*/
|
||||
export interface CloseSessionResult {
|
||||
/** Console messages and instructions. */
|
||||
instructions: string;
|
||||
/** Whether the close succeeded. */
|
||||
success: boolean;
|
||||
/** The session name that was closed. */
|
||||
@@ -58,8 +60,7 @@ export interface CloseSessionResult {
|
||||
branchesDeleted?: string[];
|
||||
/** Archive tags that were created before branch deletion. */
|
||||
tagsCreated?: string[];
|
||||
/** Warning messages. */
|
||||
warnings?: string[];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+4
-4
@@ -98,7 +98,7 @@ describe("closeMultiModel", () => {
|
||||
expect(result.worktreesRemoved).toEqual([worktreePath]);
|
||||
expect(result.branchesDeleted).toEqual(["opencode/test-session/model"]);
|
||||
expect(result.tagsCreated?.length).toBe(1);
|
||||
expect(result.warnings).toEqual([]);
|
||||
|
||||
// Ensure removal commands were executed
|
||||
expect(executedCommands).toContain(`git worktree remove -f ${worktreePath}`);
|
||||
expect(executedCommands).toContain(`git branch -D opencode/test-session/model`);
|
||||
@@ -153,7 +153,7 @@ describe("closeMultiModel", () => {
|
||||
expect(result.worktreesRemoved).toEqual([worktreePath]);
|
||||
expect(result.branchesDeleted).toEqual(["opencode/test-session/model"]);
|
||||
expect(result.tagsCreated?.length).toBe(1);
|
||||
expect(result.warnings).toEqual([]);
|
||||
|
||||
|
||||
// Verify the expected git commands were executed
|
||||
expect(executedCommands).toContain(`git worktree remove -f ${worktreePath}`);
|
||||
@@ -183,8 +183,8 @@ describe("closeMultiModel", () => {
|
||||
global.Date = OriginalDate;
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.warnings?.length).toBe(1);
|
||||
expect(result.warnings?.[0]).toContain("Failed to create tag");
|
||||
// Expect the warning message to be captured in instructions
|
||||
expect(result.instructions?.some(msg => msg.includes('Failed to create tag'))).toBe(true);
|
||||
expect(result.tagsCreated).toEqual([]);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user