feat: expose file hook execution events in SDK#39
Conversation
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Added HOOK_EXECUTION_STARTED and HOOK_EXECUTION_COMPLETED notification types - Implemented Zod schemas for hook commands and results - Updated DroidStreamMessage and DroidMessageType to include 'hook' - Implemented conversion from hook notifications to stream messages - Added tests for hook message structures and conversion - Added runnable example demonstrating hook handling Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
| this._cleanupAbortSignal = null; | ||
|
|
||
| try { | ||
| await this._client.closeSession({ reason: 'other' }).catch(() => {}); |
There was a problem hiding this comment.
[warning] close() sends unsupported droid.close_session.
The current Droid JSON-RPC runner in factory-mono does not accept or route DroidServerMethod.CLOSE_SESSION, so this request can be treated as invalid and never resolve by id; session.close() may wait for the default RPC timeout before closing, and SessionEnd hooks still won’t run. Land/require the CLI-side droid.close_session handler first, or gate/fallback this SDK call so close remains fast with older CLIs.
| eventName: notification.hookEventName, | ||
| matcher: notification.hookMatcher, | ||
| toolCallId: notification.hookToolCallId, | ||
| command: hookResult.command, |
There was a problem hiding this comment.
[warning] Completed hook messages lose command metadata.
Real CLI hook_execution_completed payloads only include hookId, hookStatus, and results with exitCode/stdout/stderr, while this SDK API claims completed stream messages include eventName, matcher, toolCallId, command, and timeout. For multi-command hooks, consumers can’t tell which command produced which output; include command/timeout in CLI completion payloads or have the SDK correlate completions with the earlier started notification by hookId.
factory-ain3sh
left a comment
There was a problem hiding this comment.
Reviewed the PR and left 2 warning comments on the close-session protocol contract and hook completion metadata.
Summary
This PR moves SDK hook support to the file/config-based model owned by the Droid CLI. SDK consumers now observe hook activity through structured
hookstream events, while hook configuration continues to come from the normal resolved Droid settings hierarchy instead of SDK callback registration or SDK-specific settings-source selection.Usage examples
Hooks are configured as normal Droid file/config hooks. For example, an SDK caller can run in a project with
.factory/settings.jsonat the git root:{ "hooks": { "PreToolUse": [ { "matcher": "Execute", "hooks": [ { "type": "command", "command": "echo \"about to run: $tool_name\"", "timeout": 5 } ] } ], "SessionEnd": [ { "hooks": [ { "type": "command", "command": "echo \"session ended: $reason\"" } ] } ] } }Then consume hook execution events from the SDK stream:
When
message.type === 'hook', the narrowed message shape is:Callback hooks are intentionally no longer part of the SDK API. This old shape does not register hooks anymore:
What changed
hook_execution_startedandhook_execution_completednotification schemas, exported hook command/result types, and a publicHookExecutionstream message.SessionEndreliable by sendingclose_sessionduringDroidSession.close()before the transport shuts down.settingSourcesSDK API so callers do not pass a field the CLI-side session request handling ignores.Validation
npm run typechecknpm run typecheck:examplesnpm testnpm run lintnpx prettier --check src tests examplesgit diff --checkclaude-haiku-4-5-20251001:lifecycle-session-start-end,user-prompt-submit-update, andexecute-deny-pre-tool-use