diff --git a/packages/coding-agent/src/core/custom-tools/types.ts b/packages/coding-agent/src/core/custom-tools/types.ts index 59d800f9..837462ad 100644 --- a/packages/coding-agent/src/core/custom-tools/types.ts +++ b/packages/coding-agent/src/core/custom-tools/types.ts @@ -36,6 +36,27 @@ export interface CustomToolAPI { hasUI: boolean; } +/** + * Clawd here, summarizing what's available to custom tools: + * + * CustomToolAPI (passed to factory, stable across session changes): + * - cwd: string - current working directory + * - exec(cmd, args, options?): Promise - run shell commands + * - ui: CustomToolUIContext - select, confirm, input, notify, custom, setStatus, theme + * - hasUI: boolean - false in print/RPC mode + * + * CustomToolContext (passed to execute and onSession): + * - sessionManager: ReadonlySessionManager - read session entries, branch info + * - modelRegistry: ModelRegistry - get API keys, list models + * - model: Model | undefined - current model + * - isIdle(): boolean - check if agent is streaming + * - hasQueuedMessages(): boolean - check if user queued input (skip interactive prompts!) + * - abort(): void - fire-and-forget abort (sets signal, doesn't wait) + * + * Note: Custom tools run inside the agent loop (like tool_call events in hooks), + * so they only get the safe read-only methods. No waitForIdle/newSession/branch/navigateTree. + */ + /** * Context passed to tool execute and onSession callbacks. * Provides access to session state and model information. diff --git a/packages/coding-agent/src/core/hooks/types.ts b/packages/coding-agent/src/core/hooks/types.ts index a15f2e7d..e7af5e87 100644 --- a/packages/coding-agent/src/core/hooks/types.ts +++ b/packages/coding-agent/src/core/hooks/types.ts @@ -130,6 +130,31 @@ export interface HookUIContext { readonly theme: Theme; } +/** + * Clawd here, summarizing what's available to hooks: + * + * HookContext (available in ALL event handlers): + * - ui: HookUIContext - select, confirm, input, notify, custom, setStatus, theme + * - hasUI: boolean - false in print/RPC mode + * - cwd: string - current working directory + * - sessionManager: ReadonlySessionManager - read session entries, branch info + * - modelRegistry: ModelRegistry - get API keys, list models + * - model: Model | undefined - current model + * - isIdle(): boolean - check if agent is streaming + * - hasQueuedMessages(): boolean - check if user queued input (skip interactive prompts) + * - abort(): void - fire-and-forget abort (sets signal, doesn't wait) + * + * HookCommandContext (only in registerCommand handlers, extends HookContext): + * - waitForIdle(): Promise - wait for agent to finish + * - newSession(options?): Promise - create new session with optional setup + * - branch(entryId): Promise - branch from specific entry + * - navigateTree(targetId, options?): Promise - navigate session tree + * + * Why the split? Session control methods (waitForIdle, newSession, etc.) would DEADLOCK + * if called from event handlers like tool_call or context, because those run inside + * the agent loop. Slash commands run from user input, outside the loop, so they're safe. + */ + /** * Context passed to hook event handlers. * For command handlers, see HookCommandContext which extends this with session control methods.