From 01e71361f2adfe70fb1605f11e1584becc644bbb Mon Sep 17 00:00:00 2001 From: Anthony Rose <20302208+Cx01N@users.noreply.github.com> Date: Mon, 16 Mar 2026 08:22:26 -0400 Subject: [PATCH 1/5] Add background override toggle to module execution (#266) Adds a "Run as Background Job" checkbox to the module execute form, allowing users to override a module's default background setting. The toggle pre-populates from the module's YAML background value. Co-authored-by: Claude Opus 4.6 (1M context) --- src/api/module-api.js | 2 ++ src/components/agents/AgentExecuteModule.vue | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/api/module-api.js b/src/api/module-api.js index 3f8fcbf9..a418ef81 100644 --- a/src/api/module-api.js +++ b/src/api/module-api.js @@ -18,6 +18,7 @@ export function executeModule( options, ignoreAdminCheck, ignoreLanguageCheck, + backgroundOverride, ) { return axios .post(`/agents/${options.Agent}/tasks/module/`, { @@ -25,6 +26,7 @@ export function executeModule( options, ignore_admin_check: ignoreAdminCheck, ignore_language_version_check: ignoreLanguageCheck, + background_override: backgroundOverride, }) .then(({ data }) => ({ agent: options.Agent, ...data })) .catch((error) => diff --git a/src/components/agents/AgentExecuteModule.vue b/src/components/agents/AgentExecuteModule.vue index 9210281a..5fd043e7 100644 --- a/src/components/agents/AgentExecuteModule.vue +++ b/src/components/agents/AgentExecuteModule.vue @@ -106,6 +106,12 @@ label="Ignore Language Version Check" color="primary" /> + Date: Sun, 22 Mar 2026 12:47:51 -0400 Subject: [PATCH 2/5] Add dedicated Shell session tab and multi-tab Terminal support (#265) * Add dedicated Shell session tab and multi-tab Terminal support - Add AgentShellSession component: dedicated interactive shell that immediately enters shell mode with directory tracking, command history, and inline result display - Add TabbedTerminalContainer component: supports multiple Terminal instances with add/close/rename (right-click) tabs - Remove shell menu mode from AgentTerminal (redundant with Shell tab) - Persist active interact sub-tab and terminal tab state to localStorage Co-Authored-By: Claude Opus 4.6 (1M context) * Fix review findings: tab storage collision, dead style binding, eslint comment - Pass tabId prop from TabbedTerminalContainer to child components so each terminal/shell tab gets a unique localStorage key - Remove undefined contextMenuStyle binding from v-menu - Add eslint-disable comment for v-html in AgentShellSession Co-Authored-By: Claude Opus 4.6 (1M context) --------- Co-authored-by: Claude Opus 4.6 (1M context) --- src/components/agents/AgentShellSession.vue | 348 ++++++++++++++++++ src/components/agents/AgentTerminal.vue | 90 +---- .../agents/TabbedTerminalContainer.vue | 199 ++++++++++ src/views/AgentEdit.vue | 28 +- 4 files changed, 580 insertions(+), 85 deletions(-) create mode 100644 src/components/agents/AgentShellSession.vue create mode 100644 src/components/agents/TabbedTerminalContainer.vue diff --git a/src/components/agents/AgentShellSession.vue b/src/components/agents/AgentShellSession.vue new file mode 100644 index 00000000..4fe09f4d --- /dev/null +++ b/src/components/agents/AgentShellSession.vue @@ -0,0 +1,348 @@ + + + + + diff --git a/src/components/agents/AgentTerminal.vue b/src/components/agents/AgentTerminal.vue index 1fd17993..2fc250b4 100644 --- a/src/components/agents/AgentTerminal.vue +++ b/src/components/agents/AgentTerminal.vue @@ -16,7 +16,6 @@ @@ -66,6 +65,10 @@ export default { type: Object, required: true, }, + tabId: { + type: Number, + default: null, + }, }, data() { return { @@ -136,6 +139,7 @@ export default { command: "shell", description: "Tasks the specified agent to execute a shell command", usage: "shell [--literal / -l] ", + // For interactive shell sessions, use the Shell tab }, { command: "ps", @@ -224,8 +228,6 @@ export default { usage: "back", }, ], - isShellMenu: false, - currentDir: "loading...", }; }, computed: { @@ -250,8 +252,6 @@ export default { let body = ""; if (this.currentModule) { body = this.colorizeText(`usemodule/${this.currentModule.id}`, "red"); - } else if (this.isShellMenu) { - body = this.colorizeText(this.currentDir, "green"); } else { body = this.colorizeText(this.agent.session_id, "red"); } @@ -290,14 +290,8 @@ export default { }, methods: { storageName() { - return `terminal-history-${this.agent.session_id}`; - }, - ctrlCHandler(_event) { - if (this.isShellMenu) { - this.isShellMenu = false; - } - this.addLine(`${this.currentPrompt} ${this.currentInput}`); - this.currentInput = ""; + const suffix = this.tabId != null ? `-${this.tabId}` : ""; + return `terminal-history-${this.agent.session_id}${suffix}`; }, positionSuggestions() { const { inputField } = this.$refs; @@ -386,10 +380,6 @@ export default { } }, async generateSuggestions() { - if (this.isShellMenu) { - this.suggestions = []; - return; - } const query = this.currentInput.toLowerCase().trim(); if (!query) { @@ -512,9 +502,7 @@ export default { const command = commandParts[0]; const args = commandParts.slice(1); - if (this.isShellMenu) { - this.shellCommandOperator(this.currentInput); - } else if (command === "back") { + if (command === "back") { if (this.currentModule) { this.currentModule = null; } else { @@ -562,10 +550,9 @@ export default { break; case "shell": if (args.length < 1) { - this.isShellMenu = true; - this.updateCurrentDirectory(); - this.addInfo(`Shell session started on ${this.agent.session_id}`); - this.addInfo("Exit shell menu with Ctrl+C."); + this.addError( + "Usage: shell [--literal / -l] . Use the Shell tab for an interactive session.", + ); } else { this.runShellCommand(commandParts.slice(1).join(" ")); } @@ -799,61 +786,6 @@ export default { return res; }, - getDirectoryCommand() { - if (this.agent.language === "python") { - return "echo $PWD"; - } - if (this.agent.language === "ironpython") { - return "cd ."; - } - return "(Resolve-Path .\\).Path"; - }, - async updateCurrentDirectory() { - this.currentDir = "loading..."; - const response = await agentTaskApi.shell( - this.agent.session_id, - this.getDirectoryCommand(), - ); - - const complete = await this.pollForResult(response.id, { print: false }); - - if (complete) { - // eslint-disable-next-line prefer-destructuring - this.currentDir = ( - await this.checkTaskComplete(response.id) - ).output.split("\r")[0]; - } - }, - // This is for when in the shell menu. - // The other function is for when not in the shell menu. - async shellCommandOperator(stdin) { - let response = null; - try { - if (stdin.trim() === "sysinfo") { - response = await agentTaskApi.sysinfo(this.agent.session_id); - } else { - response = await agentTaskApi.shell( - this.agent.session_id, - stdin, - false, - ); - } - } catch (error) { - this.addError(`Error executing command: ${error.message}`); - return; - } - - const complete = await this.pollForResult(response.id, { print: false }); - - if (["cd", "set-location"].includes(stdin.toLowerCase().split(" ")[0])) { - this.updateCurrentDirectory(); - return; - } - - if (complete) { - this.addLine(complete.output, "indent-5-spaces"); - } - }, async checkTaskComplete(taskId) { try { const task = await agentTaskApi.getTask(this.agent.session_id, taskId); diff --git a/src/components/agents/TabbedTerminalContainer.vue b/src/components/agents/TabbedTerminalContainer.vue new file mode 100644 index 00000000..2ac4acc8 --- /dev/null +++ b/src/components/agents/TabbedTerminalContainer.vue @@ -0,0 +1,199 @@ + + + + + diff --git a/src/views/AgentEdit.vue b/src/views/AgentEdit.vue index 2dfe9a05..3dcde5a0 100644 --- a/src/views/AgentEdit.vue +++ b/src/views/AgentEdit.vue @@ -194,11 +194,12 @@ - + - + @@ -296,12 +303,13 @@