build: color-code open and close outputs

This commit is contained in:
2026-03-21 01:05:17 +05:30
parent 17bb1130c8
commit 787fa75df4
6 changed files with 64 additions and 67 deletions
+47 -32
View File
@@ -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,
cleanupPerformed,
worktreesRemoved,
branchesDeleted,
tagsCreated,
warnings,
};
return {
success: true,
sessionName: safeSessionName,
cleanupPerformed,
worktreesRemoved,
branchesDeleted,
tagsCreated,
instructions: instructionsArr.join("\n"),
};
} catch (error) {
return {
success: false,
sessionName: options.sessionName,
error: String(error),
worktreesRemoved,
branchesDeleted,
tagsCreated,
warnings,
};
return {
success: false,
sessionName: safeSessionName,
error: String(error),
worktreesRemoved,
branchesDeleted,
tagsCreated,
instructions: instructionsArr.join("\n"),
};
}
}
+6 -2
View File
@@ -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;
}
}