From 818196d2c32318fb9accb279afca9a0c6d7ee92f Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Sat, 27 Dec 2025 03:22:55 +0100 Subject: [PATCH] Add immediate flag to hook commands for non-queued execution Commands with immediate: true run right away even during streaming. Used for UI-only commands like /snake that don't interact with LLM. --- packages/coding-agent/examples/hooks/snake.ts | 1 + packages/coding-agent/src/core/hooks/types.ts | 7 ++++++- .../src/modes/interactive/interactive-mode.ts | 14 ++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/coding-agent/examples/hooks/snake.ts b/packages/coding-agent/examples/hooks/snake.ts index 4dffef53..10f34c71 100644 --- a/packages/coding-agent/examples/hooks/snake.ts +++ b/packages/coding-agent/examples/hooks/snake.ts @@ -233,6 +233,7 @@ class SnakeComponent { export default function (pi: HookAPI) { pi.registerCommand("snake", { description: "Play Snake!", + immediate: true, // Run immediately, even during streaming handler: async (ctx) => { if (!ctx.hasUI) { ctx.ui.notify("Snake requires interactive mode", "error"); diff --git a/packages/coding-agent/src/core/hooks/types.ts b/packages/coding-agent/src/core/hooks/types.ts index 6ca2f11b..07f7b3f7 100644 --- a/packages/coding-agent/src/core/hooks/types.ts +++ b/packages/coding-agent/src/core/hooks/types.ts @@ -405,6 +405,8 @@ export interface HookCommandContext { export interface RegisteredCommand { name: string; description?: string; + /** If true, command runs immediately even during streaming (doesn't get queued) */ + immediate?: boolean; handler: (ctx: HookCommandContext) => Promise; } @@ -478,7 +480,10 @@ export interface HookAPI { * Register a custom slash command. * Handler receives HookCommandContext. */ - registerCommand(name: string, options: { description?: string; handler: RegisteredCommand["handler"] }): void; + registerCommand( + name: string, + options: { description?: string; immediate?: boolean; handler: RegisteredCommand["handler"] }, + ): void; /** * Execute a shell command and return stdout/stderr/code. diff --git a/packages/coding-agent/src/modes/interactive/interactive-mode.ts b/packages/coding-agent/src/modes/interactive/interactive-mode.ts index 3f2e7fda..babb141f 100644 --- a/packages/coding-agent/src/modes/interactive/interactive-mode.ts +++ b/packages/coding-agent/src/modes/interactive/interactive-mode.ts @@ -752,6 +752,20 @@ export class InteractiveMode { return; } + // Check if this is an immediate hook command (runs even during streaming) + if (text.startsWith("/") && this.session.hookRunner && this.session.isStreaming) { + const spaceIndex = text.indexOf(" "); + const commandName = spaceIndex === -1 ? text.slice(1) : text.slice(1, spaceIndex); + const command = this.session.hookRunner.getCommand(commandName); + if (command?.immediate) { + // Execute immediate hook command right away + this.editor.addToHistory(text); + this.editor.setText(""); + await this.session.prompt(text); + return; + } + } + // Queue message if agent is streaming if (this.session.isStreaming) { await this.session.queueMessage(text);