Skip to content

Commit bbd905a

Browse files
akessonclaude
andauthored
v0.9.0: Generic payload support via PayloadCollector (#10)
* Add generic payload support with PayloadCollector trait Introduces a generic type parameter P to CommandContext, allowing users to pass custom typed data from client to daemon handler. Payload is auto-collected via PayloadCollector::collect() before each command. - Add PayloadCollector trait with async fn collect() -> Self - Make CommandContext<P>, SocketMessage<P>, CommandHandler<P> generic - Make DaemonServer<H, P> and DaemonClient<P> generic - Default P = () maintains full backward compatibility - Add to prelude: PayloadCollector, Serialize, Deserialize 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Add tests for generic payload feature - Add 7 unit tests for PayloadCollector and CommandContext<P> serialization - Add 2 integration tests for end-to-end payload flow through sockets - Total test count: 73 (was 64) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Remove prd * Remove EnvVarFilter in favor of PayloadCollector Users who need env vars should include them directly in their payload struct via PayloadCollector::collect(). This simplifies the API by unifying two mechanisms into one. Removed: - EnvVarFilter struct and methods - env_vars field from CommandContext - with_env_filter() from DaemonClient - 5 EnvVarFilter unit tests 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Bump to v0.9.0, update CHANGELOG for EnvVarFilter removal 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Update docs for v0.9.0: payload, handler signature, Windows support 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Fix clippy warning: use match instead of is_err + unwrap 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Fix CHANGELOG migration example: remove incorrect turbofish 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 9cd04bb commit bbd905a

15 files changed

Lines changed: 583 additions & 477 deletions

.claude/CLAUDE.md

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
44

55
## Project Overview
66

7-
`daemon-cli` is a Rust library for building streaming daemon-client applications with automatic lifecycle management. It enables CLI tools to communicate with long-running background processes via stdin/stdout streaming over Unix domain sockets.
7+
`daemon-cli` is a Rust library for building streaming daemon-client applications with automatic lifecycle management. It enables CLI tools to communicate with long-running background processes via stdin/stdout streaming (Unix domain sockets on Unix, named pipes on Windows).
88

99
## Essential Commands
1010

@@ -91,16 +91,22 @@ Note: Multiple clients can execute commands concurrently. Each connection gets i
9191
The `CommandHandler` trait is the primary extension point:
9292
```rust
9393
#[async_trait]
94-
pub trait CommandHandler: Send + Sync {
94+
pub trait CommandHandler<P = ()>: Send + Sync
95+
where
96+
P: PayloadCollector,
97+
{
9598
async fn handle(
9699
&self,
97-
command: &str, // Command string from stdin
98-
output: impl AsyncWrite, // Stream output here incrementally
100+
command: &str, // Command string from stdin
101+
ctx: CommandContext<P>, // Terminal info + custom payload
102+
output: impl AsyncWrite, // Stream output here incrementally
99103
cancel_token: CancellationToken, // Check for cancellation
100-
) -> Result<()>;
104+
) -> Result<i32>; // Return exit code (0 = success)
101105
}
102106
```
103107

108+
The generic `P` parameter allows passing custom data from client to daemon via `PayloadCollector::collect()`.
109+
104110
**Concurrency Considerations:**
105111
- Handlers must implement `Clone + Send + Sync` for concurrent execution
106112
- Each client connection receives a cloned handler instance
@@ -126,7 +132,7 @@ use daemon_cli::prelude::*;
126132

127133
let handler = MyHandler::new();
128134
// Automatically detects daemon name and binary mtime
129-
let (server, _handle) = DaemonServer::new("/path/to/project", handler);
135+
let (server, _handle) = DaemonServer::new("/path/to/project", handler, StartupReason::default());
130136
// Default: max 100 concurrent connections
131137
```
132138

@@ -139,6 +145,7 @@ let handler = MyHandler::new();
139145
let (server, _handle) = DaemonServer::new_with_limit(
140146
"/path/to/project",
141147
handler,
148+
StartupReason::default(),
142149
10 // Max 10 concurrent clients
143150
);
144151
```
@@ -147,8 +154,8 @@ When the limit is reached, new connections wait for an available slot. This is i
147154

148155
## Platform Requirements
149156

150-
- Unix-like systems only (Linux, macOS)
151-
- Uses Unix domain sockets (not portable to Windows)
157+
- Cross-platform: Linux, macOS, Windows
158+
- Uses Unix domain sockets on Unix, named pipes on Windows
152159
- Edition: Rust 2024
153160

154161
# Other memory

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,4 @@ Cargo.lock
44

55
/*.md
66
!/README.md
7-
!/PRD.md
87
!/CHANGELOG.md

CHANGELOG.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,36 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.9.0] - 2025-12-29
9+
10+
### Changed (BREAKING)
11+
12+
- Removed `EnvVarFilter` - use `PayloadCollector` trait instead for passing env vars
13+
- `CommandContext<P>` is now generic with custom payload support via `PayloadCollector`
14+
- Removed `DaemonClient::with_env_filter()` method
15+
16+
### Migration
17+
18+
```rust
19+
// Before (0.8.0):
20+
let client = DaemonClient::connect(path)
21+
.await?
22+
.with_env_filter(EnvVarFilter::with_names(["MY_VAR"]));
23+
24+
// After (0.9.0):
25+
#[derive(Serialize, Deserialize, Clone, Default)]
26+
struct MyPayload { my_var: Option<String> }
27+
28+
#[async_trait]
29+
impl PayloadCollector for MyPayload {
30+
async fn collect() -> Self {
31+
Self { my_var: std::env::var("MY_VAR").ok() }
32+
}
33+
}
34+
35+
let client = DaemonClient::<MyPayload>::connect(path).await?;
36+
```
37+
838
## [0.8.0] - 2025-12-09
939

1040
### Changed (BREAKING)

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "daemon-cli"
3-
version = "0.8.0"
3+
version = "0.9.0"
44
edition = "2024"
55

66
[dependencies]

PRD.md

Lines changed: 0 additions & 174 deletions
This file was deleted.

0 commit comments

Comments
 (0)