diff --git a/.pi/hooks/test-command.ts b/.pi/hooks/test-command.ts index 52382d85..a9bdc16e 100644 --- a/.pi/hooks/test-command.ts +++ b/.pi/hooks/test-command.ts @@ -29,6 +29,14 @@ export default function (pi: HookAPI) { return box; }); + pi.registerCommand("no-stream", { + description: "Send a message without streaming", + handler: async (ctx) => { + ctx.ui.notify("Sending message after streaming is done..."); + }, + allowDuringStreaming: true, + }) + // Register /test-msg command pi.registerCommand("test-msg", { description: "Send a test custom message", diff --git a/packages/coding-agent/examples/hooks/snake.ts b/packages/coding-agent/examples/hooks/snake.ts index e7569c60..ea7031da 100644 --- a/packages/coding-agent/examples/hooks/snake.ts +++ b/packages/coding-agent/examples/hooks/snake.ts @@ -309,7 +309,7 @@ const SNAKE_SAVE_TYPE = "snake-save"; export default function (pi: HookAPI) { pi.registerCommand("snake", { description: "Play Snake!", - immediate: true, // Run immediately, even during streaming + allowDuringStreaming: true, // Run even during streaming, not queued 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 32426f45..45943521 100644 --- a/packages/coding-agent/src/core/hooks/types.ts +++ b/packages/coding-agent/src/core/hooks/types.ts @@ -442,8 +442,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; + /** If true, command runs during streaming instead of being queued */ + allowDuringStreaming?: boolean; handler: (ctx: HookCommandContext) => Promise; } @@ -529,7 +529,7 @@ export interface HookAPI { */ registerCommand( name: string, - options: { description?: string; immediate?: boolean; handler: RegisteredCommand["handler"] }, + options: { description?: string; allowDuringStreaming?: boolean; handler: RegisteredCommand["handler"] }, ): void; /** diff --git a/packages/coding-agent/src/modes/interactive/interactive-mode.ts b/packages/coding-agent/src/modes/interactive/interactive-mode.ts index 18149fd4..68681cb9 100644 --- a/packages/coding-agent/src/modes/interactive/interactive-mode.ts +++ b/packages/coding-agent/src/modes/interactive/interactive-mode.ts @@ -744,13 +744,13 @@ export class InteractiveMode { return; } - // Check if this is an immediate hook command (runs even during streaming) + // Check if this hook command can run during streaming (not queued) 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 + if (command?.allowDuringStreaming) { + // Execute hook command right away this.editor.addToHistory(text); this.editor.setText(""); await this.session.prompt(text);