claude-agent-sdk 1.2.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +94 -71
- data/README.md +93 -71
- data/UPGRADING-1.0.md +1 -1
- data/docs/client.md +3 -1
- data/docs/configuration.md +6 -6
- data/docs/errors.md +28 -2
- data/docs/hooks-and-permissions.md +36 -7
- data/docs/mcp-servers.md +1 -1
- data/docs/observability.md +1 -1
- data/docs/options.md +43 -0
- data/docs/rails.md +5 -5
- data/docs/sessions.md +1 -1
- data/docs/subagents.md +1 -1
- data/docs/types.md +2 -2
- data/lib/claude_agent_sdk/cli_installer.rb +1 -1
- data/lib/claude_agent_sdk/query.rb +48 -220
- data/lib/claude_agent_sdk/subprocess_cli_transport.rb +9 -0
- data/lib/claude_agent_sdk/types/hooks.rb +378 -243
- data/lib/claude_agent_sdk/types/messages.rb +14 -3
- data/lib/claude_agent_sdk/types/options.rb +35 -0
- data/lib/claude_agent_sdk/version.rb +1 -1
- data/lib/generators/claude_agent_sdk/install/install_generator.rb +1 -1
- data/lib/generators/claude_agent_sdk/install/templates/claude_agent_sdk.rb.tt +1 -1
- data/sig/claude_agent_sdk/types/hooks.rbs +286 -3
- data/sig/claude_agent_sdk/types/messages.rbs +15 -0
- data/sig/claude_agent_sdk/types/options.rbs +9 -0
- metadata +6 -6
data/docs/rails.md
CHANGED
|
@@ -356,7 +356,7 @@ end
|
|
|
356
356
|
|
|
357
357
|
Preconditions, spelled out: `:inline` is only correct when the process satisfies the same requirements as solid_queue's fiber workers — `isolation_level = :fiber`, Rails 7.2+ for AR, and no thread-keyed libraries used inside callbacks without a fiber-aware wrapper. The SDK warns once if it detects `:inline` under `isolation_level == :thread`. Everything else (Puma request threads, threaded Sidekiq/solid_queue workers) should stay on the default `callback_scheduling: :thread`.
|
|
358
358
|
|
|
359
|
-
Note that `SessionStore` adapter calls (`#append` / `#load`) stay on threads by default even in `:inline` mode — their timeouts are hard bounds (`Thread#join`) so a wedged store adapter can never stall the reactor. The exception is an adapter that declares itself fiber-native via an optional `callback_scheduling` method returning `:inline` (see "Fiber-native adapters" in [docs/sessions.md](https://github.com/
|
|
359
|
+
Note that `SessionStore` adapter calls (`#append` / `#load`) stay on threads by default even in `:inline` mode — their timeouts are hard bounds (`Thread#join`) so a wedged store adapter can never stall the reactor. The exception is an adapter that declares itself fiber-native via an optional `callback_scheduling` method returning `:inline` (see "Fiber-native adapters" in [docs/sessions.md](https://github.com/rubycatco/claude-agent-sdk-ruby/blob/main/docs/sessions.md)); its calls then run on the reactor under a cooperative timeout. In both cases a configured `callback_wrapper` composes around the adapter call inside the bound.
|
|
360
360
|
|
|
361
361
|
## ActionCable Streaming
|
|
362
362
|
|
|
@@ -541,7 +541,7 @@ end
|
|
|
541
541
|
Then every `ClaudeAgentSDK.query` and `Client` session automatically gets traced — no per-call wiring needed. The lambda factory ensures each request gets its own observer with isolated span state, safe for concurrent Puma/Sidekiq workers.
|
|
542
542
|
|
|
543
543
|
See:
|
|
544
|
-
- [examples/rails_actioncable_example.rb](https://github.com/
|
|
545
|
-
- [examples/rails_background_job_example.rb](https://github.com/
|
|
546
|
-
- [examples/session_resumption_example.rb](https://github.com/
|
|
547
|
-
- [examples/http_mcp_server_example.rb](https://github.com/
|
|
544
|
+
- [examples/rails_actioncable_example.rb](https://github.com/rubycatco/claude-agent-sdk-ruby/blob/main/examples/rails_actioncable_example.rb)
|
|
545
|
+
- [examples/rails_background_job_example.rb](https://github.com/rubycatco/claude-agent-sdk-ruby/blob/main/examples/rails_background_job_example.rb)
|
|
546
|
+
- [examples/session_resumption_example.rb](https://github.com/rubycatco/claude-agent-sdk-ruby/blob/main/examples/session_resumption_example.rb)
|
|
547
|
+
- [examples/http_mcp_server_example.rb](https://github.com/rubycatco/claude-agent-sdk-ruby/blob/main/examples/http_mcp_server_example.rb)
|
data/docs/sessions.md
CHANGED
|
@@ -398,7 +398,7 @@ end
|
|
|
398
398
|
`InMemorySessionStore#append` is a working reference.
|
|
399
399
|
|
|
400
400
|
Copy-in reference adapters for **S3, Redis, and Postgres** live in
|
|
401
|
-
[`examples/session_stores/`](https://github.com/
|
|
401
|
+
[`examples/session_stores/`](https://github.com/rubycatco/claude-agent-sdk-ruby/blob/main/examples/session_stores/README.md), each with a
|
|
402
402
|
production checklist.
|
|
403
403
|
|
|
404
404
|
#### Fiber-native adapters
|
data/docs/subagents.md
CHANGED
|
@@ -158,7 +158,7 @@ See [hook fields and permission cancellation](hooks-and-permissions.md).
|
|
|
158
158
|
|
|
159
159
|
## Minimal example
|
|
160
160
|
|
|
161
|
-
[`examples/subagent_status_example.rb`](https://github.com/
|
|
161
|
+
[`examples/subagent_status_example.rb`](https://github.com/rubycatco/claude-agent-sdk-ruby/blob/main/examples/subagent_status_example.rb)
|
|
162
162
|
defines a tool-free reviewer, registers lifecycle hooks, reads metadata, and
|
|
163
163
|
prints task events and forwarded child text without building a status model:
|
|
164
164
|
|
data/docs/types.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Types Reference
|
|
2
2
|
|
|
3
|
-
See [lib/claude_agent_sdk/types/](https://github.com/
|
|
3
|
+
See [lib/claude_agent_sdk/types/](https://github.com/rubycatco/claude-agent-sdk-ruby/tree/main/lib/claude_agent_sdk/types) for complete type definitions (one file per area; `types.rb` loads them all).
|
|
4
4
|
|
|
5
5
|
## Hash keys
|
|
6
6
|
|
|
@@ -214,7 +214,7 @@ message types of their own.
|
|
|
214
214
|
|
|
215
215
|
| Class | Wire type | Attributes | Notes |
|
|
216
216
|
|-------|-----------|------------|-------|
|
|
217
|
-
| `InitMessage` | `system` / `init` | `uuid`, `session_id`, `model`, `cwd`, `tools`, `mcp_servers`, `agents`, `skills`, `plugins`, `slash_commands`, `permission_mode`, `claude_code_version`, `api_key_source`, `betas`, `output_style`, `fast_mode_state` | Start of every turn, with the session as the CLI sees it (so a multi-query `Client` session receives one per query) |
|
|
217
|
+
| `InitMessage` | `system` / `init` | `uuid`, `session_id`, `model`, `cwd`, `tools`, `mcp_servers`, `agents`, `skills`, `plugins`, `plugin_errors`, `slash_commands`, `terminal_slash_commands`, `permission_mode`, `claude_code_version`, `api_key_source`, `betas`, `output_style`, `fast_mode_state`, `fast_mode_disabled_reason`, `capabilities` (protocol features such as `"interrupt_receipt_v1"`: test it instead of `claude_code_version`) | Start of every turn, with the session as the CLI sees it (so a multi-query `Client` session receives one per query) |
|
|
218
218
|
| `CompactBoundaryMessage` | `system` / `compact_boundary` | `uuid`, `session_id`, `compact_metadata` (a `CompactMetadata`: `pre_tokens`, `post_tokens`, `trigger`, `preserved_segment`, `custom_instructions`) | Context compaction completed |
|
|
219
219
|
| `StatusMessage` | `system` / `status` | `uuid`, `session_id`, `status`, `permission_mode` | Compacting status, permission mode changes |
|
|
220
220
|
| `APIRetryMessage` | `system` / `api_retry` | `uuid`, `session_id`, `attempt`, `max_retries`, `retry_delay_ms`, `error_status`, `error` | The CLI is retrying an API request |
|
|
@@ -53,7 +53,7 @@ module ClaudeAgentSDK
|
|
|
53
53
|
# Single source of truth: bumped here (and only here) by
|
|
54
54
|
# .github/workflows/cli-pin-bump.yml or a Python-sync release, so a
|
|
55
55
|
# Dependabot bump of the gem carries the CLI forward with it.
|
|
56
|
-
PINNED_CLI_VERSION = '2.1.
|
|
56
|
+
PINNED_CLI_VERSION = '2.1.295'
|
|
57
57
|
# @api private
|
|
58
58
|
BINARY_NAME = 'claude'
|
|
59
59
|
# @api private
|
|
@@ -868,227 +868,55 @@ module ClaudeAgentSDK
|
|
|
868
868
|
@callback_request_signals.delete(request_id)
|
|
869
869
|
end
|
|
870
870
|
|
|
871
|
-
|
|
871
|
+
# The typed input built for each hook event the SDK models; any other
|
|
872
|
+
# event becomes an UnknownHookInput.
|
|
873
|
+
HOOK_INPUT_CLASSES = {
|
|
874
|
+
'PreToolUse' => PreToolUseHookInput,
|
|
875
|
+
'PostToolUse' => PostToolUseHookInput,
|
|
876
|
+
'PostToolUseFailure' => PostToolUseFailureHookInput,
|
|
877
|
+
'UserPromptSubmit' => UserPromptSubmitHookInput,
|
|
878
|
+
'Stop' => StopHookInput,
|
|
879
|
+
'SubagentStop' => SubagentStopHookInput,
|
|
880
|
+
'Notification' => NotificationHookInput,
|
|
881
|
+
'SubagentStart' => SubagentStartHookInput,
|
|
882
|
+
'PermissionRequest' => PermissionRequestHookInput,
|
|
883
|
+
'PreCompact' => PreCompactHookInput,
|
|
884
|
+
'SessionStart' => SessionStartHookInput,
|
|
885
|
+
'SessionEnd' => SessionEndHookInput,
|
|
886
|
+
'Setup' => SetupHookInput,
|
|
887
|
+
'TeammateIdle' => TeammateIdleHookInput,
|
|
888
|
+
'TaskCompleted' => TaskCompletedHookInput,
|
|
889
|
+
'ConfigChange' => ConfigChangeHookInput,
|
|
890
|
+
'WorktreeCreate' => WorktreeCreateHookInput,
|
|
891
|
+
'WorktreeRemove' => WorktreeRemoveHookInput,
|
|
892
|
+
'StopFailure' => StopFailureHookInput,
|
|
893
|
+
'PostCompact' => PostCompactHookInput,
|
|
894
|
+
'PermissionDenied' => PermissionDeniedHookInput,
|
|
895
|
+
'TaskCreated' => TaskCreatedHookInput,
|
|
896
|
+
'Elicitation' => ElicitationHookInput,
|
|
897
|
+
'ElicitationResult' => ElicitationResultHookInput,
|
|
898
|
+
'InstructionsLoaded' => InstructionsLoadedHookInput,
|
|
899
|
+
'CwdChanged' => CwdChangedHookInput,
|
|
900
|
+
'FileChanged' => FileChangedHookInput,
|
|
901
|
+
'PostToolBatch' => PostToolBatchHookInput,
|
|
902
|
+
'UserPromptExpansion' => UserPromptExpansionHookInput,
|
|
903
|
+
'PreModelSwitch' => PreModelSwitchHookInput,
|
|
904
|
+
'PostModelSwitch' => PostModelSwitchHookInput,
|
|
905
|
+
'DirectoryAdded' => DirectoryAddedHookInput,
|
|
906
|
+
'MessageDisplay' => MessageDisplayHookInput
|
|
907
|
+
}.freeze
|
|
908
|
+
private_constant :HOOK_INPUT_CLASSES
|
|
909
|
+
|
|
910
|
+
# Every field of the payload that the class declares is assigned (the
|
|
911
|
+
# lenient parse path: other keys are skipped, not rejected), and the
|
|
912
|
+
# whole payload is kept as #raw_input, so a field the CLI added after this
|
|
913
|
+
# SDK version is still readable there.
|
|
914
|
+
def parse_hook_input(input_data)
|
|
915
|
+
input_data = {} unless input_data.is_a?(Hash)
|
|
872
916
|
event_name = input_data[:hook_event_name] || input_data['hook_event_name']
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
elsif input_data.key?(key.to_s)
|
|
877
|
-
input_data[key.to_s]
|
|
878
|
-
end
|
|
879
|
-
end
|
|
880
|
-
base_args = {
|
|
881
|
-
session_id: fetch.call(:session_id),
|
|
882
|
-
transcript_path: fetch.call(:transcript_path),
|
|
883
|
-
cwd: fetch.call(:cwd),
|
|
884
|
-
permission_mode: fetch.call(:permission_mode)
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
# Subagent context fields shared by tool-lifecycle hooks
|
|
888
|
-
subagent_args = {
|
|
889
|
-
agent_id: fetch.call(:agent_id),
|
|
890
|
-
agent_type: fetch.call(:agent_type)
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
case event_name
|
|
894
|
-
when 'PreToolUse'
|
|
895
|
-
PreToolUseHookInput.new(
|
|
896
|
-
tool_name: fetch.call(:tool_name),
|
|
897
|
-
tool_input: fetch.call(:tool_input),
|
|
898
|
-
tool_use_id: fetch.call(:tool_use_id),
|
|
899
|
-
**subagent_args, **base_args
|
|
900
|
-
)
|
|
901
|
-
when 'PostToolUse'
|
|
902
|
-
PostToolUseHookInput.new(
|
|
903
|
-
tool_name: fetch.call(:tool_name),
|
|
904
|
-
tool_input: fetch.call(:tool_input),
|
|
905
|
-
tool_response: fetch.call(:tool_response),
|
|
906
|
-
tool_use_id: fetch.call(:tool_use_id),
|
|
907
|
-
**subagent_args, **base_args
|
|
908
|
-
)
|
|
909
|
-
when 'PostToolUseFailure'
|
|
910
|
-
PostToolUseFailureHookInput.new(
|
|
911
|
-
tool_name: fetch.call(:tool_name),
|
|
912
|
-
tool_input: fetch.call(:tool_input),
|
|
913
|
-
tool_use_id: fetch.call(:tool_use_id),
|
|
914
|
-
error: fetch.call(:error),
|
|
915
|
-
is_interrupt: fetch.call(:is_interrupt),
|
|
916
|
-
**subagent_args, **base_args
|
|
917
|
-
)
|
|
918
|
-
when 'UserPromptSubmit'
|
|
919
|
-
UserPromptSubmitHookInput.new(
|
|
920
|
-
prompt: fetch.call(:prompt),
|
|
921
|
-
**base_args
|
|
922
|
-
)
|
|
923
|
-
when 'Stop'
|
|
924
|
-
StopHookInput.new(
|
|
925
|
-
stop_hook_active: fetch.call(:stop_hook_active),
|
|
926
|
-
last_assistant_message: fetch.call(:last_assistant_message),
|
|
927
|
-
background_tasks: fetch.call(:background_tasks),
|
|
928
|
-
session_crons: fetch.call(:session_crons),
|
|
929
|
-
**base_args
|
|
930
|
-
)
|
|
931
|
-
when 'SubagentStop'
|
|
932
|
-
SubagentStopHookInput.new(
|
|
933
|
-
stop_hook_active: fetch.call(:stop_hook_active),
|
|
934
|
-
agent_id: fetch.call(:agent_id),
|
|
935
|
-
agent_transcript_path: fetch.call(:agent_transcript_path),
|
|
936
|
-
agent_type: fetch.call(:agent_type),
|
|
937
|
-
last_assistant_message: fetch.call(:last_assistant_message),
|
|
938
|
-
background_tasks: fetch.call(:background_tasks),
|
|
939
|
-
session_crons: fetch.call(:session_crons),
|
|
940
|
-
**base_args
|
|
941
|
-
)
|
|
942
|
-
when 'Notification'
|
|
943
|
-
NotificationHookInput.new(
|
|
944
|
-
message: fetch.call(:message),
|
|
945
|
-
title: fetch.call(:title),
|
|
946
|
-
notification_type: fetch.call(:notification_type),
|
|
947
|
-
**base_args
|
|
948
|
-
)
|
|
949
|
-
when 'SubagentStart'
|
|
950
|
-
SubagentStartHookInput.new(
|
|
951
|
-
agent_id: fetch.call(:agent_id),
|
|
952
|
-
agent_type: fetch.call(:agent_type),
|
|
953
|
-
**base_args
|
|
954
|
-
)
|
|
955
|
-
when 'PermissionRequest'
|
|
956
|
-
PermissionRequestHookInput.new(
|
|
957
|
-
tool_name: fetch.call(:tool_name),
|
|
958
|
-
tool_input: fetch.call(:tool_input),
|
|
959
|
-
permission_suggestions: fetch.call(:permission_suggestions),
|
|
960
|
-
**subagent_args, **base_args
|
|
961
|
-
)
|
|
962
|
-
when 'PreCompact'
|
|
963
|
-
PreCompactHookInput.new(
|
|
964
|
-
trigger: fetch.call(:trigger),
|
|
965
|
-
custom_instructions: fetch.call(:custom_instructions),
|
|
966
|
-
**base_args
|
|
967
|
-
)
|
|
968
|
-
when 'SessionStart'
|
|
969
|
-
SessionStartHookInput.new(
|
|
970
|
-
source: fetch.call(:source),
|
|
971
|
-
agent_type: fetch.call(:agent_type),
|
|
972
|
-
model: fetch.call(:model),
|
|
973
|
-
**base_args
|
|
974
|
-
)
|
|
975
|
-
when 'SessionEnd'
|
|
976
|
-
SessionEndHookInput.new(
|
|
977
|
-
reason: fetch.call(:reason),
|
|
978
|
-
**base_args
|
|
979
|
-
)
|
|
980
|
-
when 'Setup'
|
|
981
|
-
SetupHookInput.new(
|
|
982
|
-
trigger: fetch.call(:trigger),
|
|
983
|
-
**base_args
|
|
984
|
-
)
|
|
985
|
-
when 'TeammateIdle'
|
|
986
|
-
TeammateIdleHookInput.new(
|
|
987
|
-
teammate_name: fetch.call(:teammate_name),
|
|
988
|
-
team_name: fetch.call(:team_name),
|
|
989
|
-
**base_args
|
|
990
|
-
)
|
|
991
|
-
when 'TaskCompleted'
|
|
992
|
-
TaskCompletedHookInput.new(
|
|
993
|
-
task_id: fetch.call(:task_id),
|
|
994
|
-
task_subject: fetch.call(:task_subject),
|
|
995
|
-
task_description: fetch.call(:task_description),
|
|
996
|
-
teammate_name: fetch.call(:teammate_name),
|
|
997
|
-
team_name: fetch.call(:team_name),
|
|
998
|
-
**base_args
|
|
999
|
-
)
|
|
1000
|
-
when 'ConfigChange'
|
|
1001
|
-
ConfigChangeHookInput.new(
|
|
1002
|
-
source: fetch.call(:source),
|
|
1003
|
-
file_path: fetch.call(:file_path),
|
|
1004
|
-
**base_args
|
|
1005
|
-
)
|
|
1006
|
-
when 'WorktreeCreate'
|
|
1007
|
-
WorktreeCreateHookInput.new(
|
|
1008
|
-
name: fetch.call(:name),
|
|
1009
|
-
**base_args
|
|
1010
|
-
)
|
|
1011
|
-
when 'WorktreeRemove'
|
|
1012
|
-
WorktreeRemoveHookInput.new(
|
|
1013
|
-
worktree_path: fetch.call(:worktree_path),
|
|
1014
|
-
**base_args
|
|
1015
|
-
)
|
|
1016
|
-
when 'StopFailure'
|
|
1017
|
-
StopFailureHookInput.new(
|
|
1018
|
-
error: fetch.call(:error),
|
|
1019
|
-
error_details: fetch.call(:error_details),
|
|
1020
|
-
last_assistant_message: fetch.call(:last_assistant_message),
|
|
1021
|
-
**base_args
|
|
1022
|
-
)
|
|
1023
|
-
when 'PostCompact'
|
|
1024
|
-
PostCompactHookInput.new(
|
|
1025
|
-
trigger: fetch.call(:trigger),
|
|
1026
|
-
compact_summary: fetch.call(:compact_summary),
|
|
1027
|
-
**base_args
|
|
1028
|
-
)
|
|
1029
|
-
when 'PermissionDenied'
|
|
1030
|
-
PermissionDeniedHookInput.new(
|
|
1031
|
-
tool_name: fetch.call(:tool_name),
|
|
1032
|
-
tool_input: fetch.call(:tool_input),
|
|
1033
|
-
tool_use_id: fetch.call(:tool_use_id),
|
|
1034
|
-
reason: fetch.call(:reason),
|
|
1035
|
-
**subagent_args, **base_args
|
|
1036
|
-
)
|
|
1037
|
-
when 'TaskCreated'
|
|
1038
|
-
TaskCreatedHookInput.new(
|
|
1039
|
-
task_id: fetch.call(:task_id),
|
|
1040
|
-
task_subject: fetch.call(:task_subject),
|
|
1041
|
-
task_description: fetch.call(:task_description),
|
|
1042
|
-
teammate_name: fetch.call(:teammate_name),
|
|
1043
|
-
team_name: fetch.call(:team_name),
|
|
1044
|
-
**base_args
|
|
1045
|
-
)
|
|
1046
|
-
when 'Elicitation'
|
|
1047
|
-
ElicitationHookInput.new(
|
|
1048
|
-
mcp_server_name: fetch.call(:mcp_server_name),
|
|
1049
|
-
message: fetch.call(:message),
|
|
1050
|
-
mode: fetch.call(:mode),
|
|
1051
|
-
url: fetch.call(:url),
|
|
1052
|
-
elicitation_id: fetch.call(:elicitation_id),
|
|
1053
|
-
requested_schema: fetch.call(:requested_schema),
|
|
1054
|
-
**base_args
|
|
1055
|
-
)
|
|
1056
|
-
when 'ElicitationResult'
|
|
1057
|
-
ElicitationResultHookInput.new(
|
|
1058
|
-
mcp_server_name: fetch.call(:mcp_server_name),
|
|
1059
|
-
elicitation_id: fetch.call(:elicitation_id),
|
|
1060
|
-
mode: fetch.call(:mode),
|
|
1061
|
-
action: fetch.call(:action),
|
|
1062
|
-
content: fetch.call(:content),
|
|
1063
|
-
**base_args
|
|
1064
|
-
)
|
|
1065
|
-
when 'InstructionsLoaded'
|
|
1066
|
-
InstructionsLoadedHookInput.new(
|
|
1067
|
-
file_path: fetch.call(:file_path),
|
|
1068
|
-
memory_type: fetch.call(:memory_type),
|
|
1069
|
-
load_reason: fetch.call(:load_reason),
|
|
1070
|
-
globs: fetch.call(:globs),
|
|
1071
|
-
trigger_file_path: fetch.call(:trigger_file_path),
|
|
1072
|
-
**base_args
|
|
1073
|
-
)
|
|
1074
|
-
when 'CwdChanged'
|
|
1075
|
-
CwdChangedHookInput.new(
|
|
1076
|
-
old_cwd: fetch.call(:old_cwd),
|
|
1077
|
-
new_cwd: fetch.call(:new_cwd),
|
|
1078
|
-
**base_args
|
|
1079
|
-
)
|
|
1080
|
-
when 'FileChanged'
|
|
1081
|
-
FileChangedHookInput.new(
|
|
1082
|
-
file_path: fetch.call(:file_path),
|
|
1083
|
-
event: fetch.call(:event),
|
|
1084
|
-
**base_args
|
|
1085
|
-
)
|
|
1086
|
-
else
|
|
1087
|
-
# Unknown event: preserve the wire event name and full raw payload
|
|
1088
|
-
# rather than dropping event-specific fields (Python passes the raw
|
|
1089
|
-
# dict through, so nothing is lost there).
|
|
1090
|
-
UnknownHookInput.new(hook_event_name: event_name, raw_input: input_data, **base_args)
|
|
1091
|
-
end
|
|
917
|
+
hook_input = HOOK_INPUT_CLASSES.fetch(event_name, UnknownHookInput).from_hash(input_data)
|
|
918
|
+
hook_input.raw_input = input_data
|
|
919
|
+
hook_input
|
|
1092
920
|
end
|
|
1093
921
|
|
|
1094
922
|
def handle_mcp_message(request_data)
|
|
@@ -373,6 +373,15 @@ module ClaudeAgentSDK
|
|
|
373
373
|
# On Windows spawn raises for :uid, wrapped below into
|
|
374
374
|
# CLIConnectionError — fail-loud instead of the old silent ignore.
|
|
375
375
|
opts = { chdir: @cwd&.to_s, uid: @options.user }.compact
|
|
376
|
+
# process_group: the terminal's Ctrl-C signals the whole foreground
|
|
377
|
+
# process group, so a CLI left in ours ends the turn on its own
|
|
378
|
+
# before the host can choose to interrupt, ask, or ignore it. Its own
|
|
379
|
+
# group keeps that decision with the host. Teardown still signals
|
|
380
|
+
# the pid, not the group. Windows has no :pgroup; :new_pgroup
|
|
381
|
+
# (CREATE_NEW_PROCESS_GROUP) is its equivalent, and Unix rejects it.
|
|
382
|
+
# Absent unless set, like :uid. The `-v` probe is short-lived and
|
|
383
|
+
# bounded, and stays in our group.
|
|
384
|
+
opts[Gem.win_platform? ? :new_pgroup : :pgroup] = true if @options.process_group?
|
|
376
385
|
|
|
377
386
|
@stdin, @stdout, @stderr, @process = Open3.popen3(process_env, *cmd, opts)
|
|
378
387
|
# The CLI emits UTF-8 regardless of the parent locale. popen3 pipes
|