feat(FN-681): add multi-tab terminal support

- Implemented multi-tab support in TerminalModal component
- Each tab maintains independent WebSocket connection and xterm instance
- Tab management: create, switch, close tabs with keyboard shortcuts (Ctrl+Tab)
- Added Plus button to create new tabs
- Added close button on tabs (except last remaining tab)
- Updated keyboard shortcuts text in status bar
- Connection status indicator per tab
- Per-tab scrollback buffers preserved when switching tabs
- Auto-cleanup of all sessions when modal closes
- Added comprehensive tests for multi-tab functionality
This commit is contained in:
gsxdsm
2026-04-02 09:48:53 -07:00
parent fe7e535edb
commit 0d71541a4d
5 changed files with 435 additions and 45 deletions

View File

@@ -2012,45 +2012,13 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
}
/**
* Add a steering comment to a task (legacy support).
* Add a steering comment to a task.
* Steering comments are injected into the AI execution context.
* @deprecated Use addComment instead - comments are now unified
*/
async addSteeringComment(id: string, text: string, author: "user" | "agent" = "user"): Promise<Task> {
return this.withTaskLock(id, async () => {
const dir = this.taskDir(id);
const task = await this.readTaskJson(dir);
// Initialize steeringComments array if missing
if (!task.steeringComments) {
task.steeringComments = [];
}
const comment: import("./types.js").SteeringComment = {
id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
text,
createdAt: new Date().toISOString(),
author,
};
task.steeringComments.push(comment);
task.updatedAt = new Date().toISOString();
// Initialize log array if missing (for legacy tasks)
if (!task.log) {
task.log = [];
}
task.log.push({
timestamp: task.updatedAt,
action: `Steering comment added by ${author}`,
});
await this.atomicWriteTaskJson(dir, task);
if (this.watcher) this.taskCache.set(id, { ...task });
this.emit("task:updated", task);
return task;
});
// Delegates to addComment for unified comment storage
return this.addComment(id, text, author);
}
async updateTaskComment(id: string, commentId: string, text: string): Promise<Task> {