Class: RubynCode::Hooks::SubprocessExecutor
- Inherits:
-
Object
- Object
- RubynCode::Hooks::SubprocessExecutor
- Defined in:
- lib/rubyn_code/hooks/subprocess_executor.rb
Overview
Spawns external hook commands and exchanges JSON with them.
Protocol (matches Claude Code):
1. Spawn the command with { env, chdir: project_root }.
2. Write one JSON line to stdin:
{ "hookEventName": "PreToolUse",
"sessionId": "...",
"toolName": "bash", // when applicable
"toolInput": { ... }, // when applicable
"prompt": "user text..." } // when applicable
3. Close stdin.
4. Read stdout until EOF or timeout. Parse as JSON.
- One JSON object spanning the whole output, OR
- Newline-delimited JSON (first parseable line wins).
5. Stderr is captured and logged but not parsed.
The executor is stateless — each call spawns a fresh process. This is intentional: hooks must not keep state between invocations, and process startup cost (~30ms on macOS) is negligible compared to typical tool execution time.
Defined Under Namespace
Classes: ExecutionError, TimeoutError
Constant Summary collapse
- DEFAULT_TIMEOUT =
seconds
60
Instance Method Summary collapse
-
#initialize(project_root:, default_timeout: DEFAULT_TIMEOUT) ⇒ SubprocessExecutor
constructor
A new instance of SubprocessExecutor.
-
#run(command:, payload:, args: [], env: {}, timeout: nil) ⇒ Hash
Runs a single hook command with the given event payload.
Constructor Details
#initialize(project_root:, default_timeout: DEFAULT_TIMEOUT) ⇒ SubprocessExecutor
Returns a new instance of SubprocessExecutor.
41 42 43 44 |
# File 'lib/rubyn_code/hooks/subprocess_executor.rb', line 41 def initialize(project_root:, default_timeout: DEFAULT_TIMEOUT) @project_root = project_root @default_timeout = default_timeout end |
Instance Method Details
#run(command:, payload:, args: [], env: {}, timeout: nil) ⇒ Hash
Runs a single hook command with the given event payload.
57 58 59 60 61 62 63 64 65 |
# File 'lib/rubyn_code/hooks/subprocess_executor.rb', line 57 def run(command:, payload:, args: [], env: {}, timeout: nil) timeout ||= @default_timeout env = default_env.merge(env) stdout, _stderr, = invoke(command, args, env, payload, timeout) parse_response(stdout) rescue Timeout::Error => e raise TimeoutError, "Hook command '#{command}' timed out after #{timeout}s: #{e.}" end |