Commit graph

3 commits

Author SHA1 Message Date
ba189340e5 port the subprocess transport
Ports _internal/transport/subprocess_cli.py. Spawns the claude CLI with
--output-format stream-json --input-format stream-json --verbose, then
exposes a split (TransportReader, TransportWriter, TransportHandle) trio.

The split is the key difference from the Python single-class transport:
the reader half owns stdout exclusively and is moved into a background
task; the writer half is Arc/Mutex over stdin and clones freely. A single
mutex over the whole transport would deadlock the moment the reader
blocked on stdin — which it does after each turn.

Other notes:
- find_cli() mirrors the Python search path (PATH, then ~/.npm-global/bin,
  /usr/local/bin, ~/.local/bin, ~/node_modules/.bin, ~/.yarn/bin,
  ~/.claude/local/claude).
- build_command() faithfully ports _build_command() with the v0.1 option
  subset.
- Env handling matches Python: filter CLAUDECODE on inherit, set
  CLAUDE_CODE_ENTRYPOINT=sdk-rust, layer user env, stamp
  CLAUDE_AGENT_SDK_VERSION last.
- Stdout JSON parsing speculatively accumulates until serde_json succeeds
  or max_buffer_size (1 MiB default) overflows — same buffer-and-retry
  loop as the Python TextReceiveStream path. Non-JSON chatter
  ([SandboxDebug] etc.) is skipped between frames.
- TransportHandle::close() gives the subprocess a 5s graceful shutdown
  window after stdin EOF before SIGKILL, mirroring the #625 fix in the
  Python SDK.
- Drop on TransportHandle starts a best-effort kill so abandoned clients
  do not leak claude processes.

Unit tests cover the JSON accumulator (full + partial + complete,
non-JSON skip, overflow, multiline split) and the version parser.
2026-05-14 08:03:38 -07:00
184b0a786a port message, option, and error types
- Errors: single enum mirroring the Python SDK's exception hierarchy
  (CliNotFound, CliConnection, Process, JsonDecode, MessageParse). Each
  Python class becomes a variant; the Process variant carries exit code +
  optional captured stderr.

- Options: ClaudeAgentOptions as a plain struct with a builder. Covers the
  full subprocess-arg surface (system_prompt with String / PresetAppend /
  File forms, tools / allowed / disallowed, permission_mode, model and
  fallback, cwd / cli_path / settings, env, extra_args, effort, output_format,
  mcp_servers, fork_session, include_partial_messages, etc.). Deferred
  fields documented inline.

- Messages: ContentBlock enum (Text / Thinking / ToolUse / ToolResult /
  ServerToolUse / ServerToolResult / Unknown) with serde tag dispatch and
  an Unknown fallthrough for forward compatibility. Top-level Message enum
  uses a hand-written Deserialize that dispatches on the "type" tag so
  unrecognised top-level frames land in Message::Unknown with the raw JSON
  preserved (matches the Python SDK's "skip unknown" behaviour, but lets
  Rust callers introspect).

Unit tests cover roundtrip for the common shapes (assistant text +
thinking + tool_use, user with both string and structured content, result,
system, unknown top-level).
2026-05-14 08:03:24 -07:00
6af8273f98 scaffold the crate
Initial layout for an async Rust port of the Python claude-agent-sdk. Sets
up Cargo.toml on 2024 edition, MIT LICENSE matching the upstream Python SDK's
text with the Sulkta Coop copyright appended, a workspace .gitignore, and a
README laying out the v0.1 scope and the Python -> Rust mapping table.

No source modules yet — those land in the following commits.
2026-05-14 08:03:11 -07:00