diff --git a/packages/coding-agent/docs/session-tree-plan.md b/packages/coding-agent/docs/session-tree-plan.md index 68aa7e6f..44a3eb04 100644 --- a/packages/coding-agent/docs/session-tree-plan.md +++ b/packages/coding-agent/docs/session-tree-plan.md @@ -165,20 +165,20 @@ Calls `sessionManager.appendCustomEntry()` directly. **New: `registerCommand()` (types ✅, wiring TODO)** ```typescript -interface CommandContext { +interface HookCommandContext { args: string; // Everything after /commandname ui: HookUIContext; hasUI: boolean; cwd: string; sessionManager: SessionManager; modelRegistry: ModelRegistry; - sendMessage: HookAPI['sendMessage']; exec(command: string, args: string[], options?: ExecOptions): Promise; } +// Note: sendMessage not on context - handler captures `pi` in closure registerCommand(name: string, options: { description?: string; - handler: (ctx: CommandContext) => Promise; + handler: (ctx: HookCommandContext) => Promise; }): void; ``` @@ -188,7 +188,7 @@ Handler return: Wiring (all in AgentSession.prompt()): - [x] Add hook commands to autocomplete in interactive-mode - [x] `_tryExecuteHookCommand()` in AgentSession handles command execution -- [x] Build CommandContext with ui (from hookRunner), exec, sessionManager, etc. +- [x] Build HookCommandContext with ui (from hookRunner), exec, sessionManager, etc. - [x] If handler returns string, use as prompt text - [x] If handler returns undefined, return early (no LLM call) - [x] Works for all modes (interactive, RPC, print) via shared AgentSession @@ -243,7 +243,7 @@ Review and update all docs: - New `pi.appendEntry()` for state persistence - New `pi.registerCommand()` for custom slash commands - New `pi.registerCustomMessageRenderer()` for custom TUI rendering - - `CommandContext` interface and handler patterns + - `HookCommandContext` interface and handler patterns - `HookMessage` type - Updated event signatures (`SessionEventBase`, `before_compact`, etc.) - [ ] `docs/hooks-v2.md` - Review/merge or remove if obsolete diff --git a/packages/coding-agent/src/core/agent-session.ts b/packages/coding-agent/src/core/agent-session.ts index ffc964f8..0a7d523a 100644 --- a/packages/coding-agent/src/core/agent-session.ts +++ b/packages/coding-agent/src/core/agent-session.ts @@ -28,9 +28,9 @@ import { import type { LoadedCustomTool, SessionEvent as ToolSessionEvent } from "./custom-tools/index.js"; import { exportSessionToHtml } from "./export-html.js"; import { - type CommandContext, type ExecOptions, execCommand, + type HookCommandContext, type HookMessage, type HookRunner, type SessionEventResult, @@ -512,18 +512,13 @@ export class AgentSession { // Build command context const cwd = process.cwd(); - const ctx: CommandContext = { + const ctx: HookCommandContext = { args, ui: uiContext, hasUI: this._hookRunner.getHasUI(), cwd, sessionManager: this.sessionManager, modelRegistry: this._modelRegistry, - sendMessage: (message, triggerTurn) => { - this.sendHookMessage(message, triggerTurn).catch(() => { - // Error handling is done in sendHookMessage - }); - }, exec: (cmd: string, cmdArgs: string[], options?: ExecOptions) => execCommand(cmd, cmdArgs, cwd, options), }; diff --git a/packages/coding-agent/src/core/hooks/index.ts b/packages/coding-agent/src/core/hooks/index.ts index 43901993..5bff545d 100644 --- a/packages/coding-agent/src/core/hooks/index.ts +++ b/packages/coding-agent/src/core/hooks/index.ts @@ -1,18 +1,18 @@ +// biome-ignore assist/source/organizeImports: biome is not smart export { - type AppendEntryHandler, discoverAndLoadHooks, + loadHooks, + type AppendEntryHandler, type LoadedHook, type LoadHooksResult, - loadHooks, type SendMessageHandler, } from "./loader.js"; -export { execCommand, type HookErrorListener, HookRunner } from "./runner.js"; +export { execCommand, HookRunner, type HookErrorListener } from "./runner.js"; export { wrapToolsWithHooks, wrapToolWithHooks } from "./tool-wrapper.js"; export type { AgentEndEvent, AgentStartEvent, BashToolResultEvent, - CommandContext, CustomMessageRenderer, CustomMessageRenderOptions, CustomToolResultEvent, @@ -22,6 +22,7 @@ export type { FindToolResultEvent, GrepToolResultEvent, HookAPI, + HookCommandContext, HookError, HookEvent, HookEventContext, diff --git a/packages/coding-agent/src/core/hooks/types.ts b/packages/coding-agent/src/core/hooks/types.ts index 7a3e72f7..35b339e1 100644 --- a/packages/coding-agent/src/core/hooks/types.ts +++ b/packages/coding-agent/src/core/hooks/types.ts @@ -12,6 +12,7 @@ import type { Theme } from "../../modes/interactive/theme/theme.js"; import type { CompactionPreparation, CompactionResult } from "../compaction.js"; import type { ModelRegistry } from "../model-registry.js"; import type { CompactionEntry, CustomMessageEntry, SessionManager } from "../session-manager.js"; +import type { EditToolDetails } from "../tools/edit.js"; import type { BashToolDetails, FindToolDetails, @@ -237,7 +238,7 @@ export interface ReadToolResultEvent extends ToolResultEventBase { /** Tool result event for edit tool */ export interface EditToolResultEvent extends ToolResultEventBase { toolName: "edit"; - details: undefined; + details: EditToolDetails | undefined; } /** Tool result event for write tool */ @@ -394,9 +395,9 @@ export type CustomMessageRenderer = ( export type HookMessage = Pick, "customType" | "content" | "display" | "details">; /** - * Context passed to command handlers. + * Context passed to hook command handlers. */ -export interface CommandContext { +export interface HookCommandContext { /** Arguments after the command name */ args: string; /** UI methods for user interaction */ @@ -411,13 +412,6 @@ export interface CommandContext { sessionManager: SessionManager; /** Model registry for API keys */ modelRegistry: ModelRegistry; - /** - * Send a custom message to the session. - * If streaming, queued and appended after turn ends. - * If idle and triggerTurn=true, appends and triggers a new turn. - * If idle and triggerTurn=false (default), just appends. - */ - sendMessage(message: HookMessage, triggerTurn?: boolean): void; } /** @@ -426,7 +420,7 @@ export interface CommandContext { export interface RegisteredCommand { name: string; description?: string; - handler: (ctx: CommandContext) => Promise; + handler: (ctx: HookCommandContext) => Promise; } /** diff --git a/packages/coding-agent/src/core/tools/edit.ts b/packages/coding-agent/src/core/tools/edit.ts index ff040091..4cd3dd0d 100644 --- a/packages/coding-agent/src/core/tools/edit.ts +++ b/packages/coding-agent/src/core/tools/edit.ts @@ -122,6 +122,11 @@ const editSchema = Type.Object({ newText: Type.String({ description: "New text to replace the old text with" }), }); +export interface EditToolDetails { + /** Unified diff of the changes made */ + diff: string; +} + export function createEditTool(cwd: string): AgentTool { return { name: "edit",