aboutsummaryrefslogtreecommitdiff
path: root/IMPLEMENTATION_PLAN.md
diff options
context:
space:
mode:
authordiogo464 <[email protected]>2025-06-23 10:37:37 +0100
committerdiogo464 <[email protected]>2025-06-23 10:37:37 +0100
commit8da000524e50610076d02c32ab97d57e8e01f0bb (patch)
tree3b430492f6eeeecdc216818aa68301c7dfd8cc37 /IMPLEMENTATION_PLAN.md
parentb257b2259dc3ad7d0aa4df86ef241b66932204a9 (diff)
Remove implementation plans and goal files
Clean up project by removing internal planning documents 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
Diffstat (limited to 'IMPLEMENTATION_PLAN.md')
-rw-r--r--IMPLEMENTATION_PLAN.md313
1 files changed, 0 insertions, 313 deletions
diff --git a/IMPLEMENTATION_PLAN.md b/IMPLEMENTATION_PLAN.md
deleted file mode 100644
index 56c3caf..0000000
--- a/IMPLEMENTATION_PLAN.md
+++ /dev/null
@@ -1,313 +0,0 @@
1# Demon CLI Implementation Plan
2
3## Project Overview
4A CLI tool named `demon` for spawning and managing background processes with stdout/stderr redirection.
5
6## Requirements Summary
7- **Files created**: `<id>.pid`, `<id>.stdout`, `<id>.stderr` in working directory
8- **Platform**: Linux only (maybe macOS later)
9- **File location**: Working directory (add to .gitignore)
10- **Signal handling**: SIGTERM then SIGKILL with configurable timeout
11- **Logging**: Tool logs to stderr, process output to stdout
12- **Concurrency**: Single process tail for now
13
14## CLI Structure
15```
16demon run --id <identifier> <command...>
17demon stop --id <id> [--timeout <seconds>]
18demon tail [--stdout] [--stderr] --id <id>
19demon cat [--stdout] [--stderr] --id <id>
20demon list
21demon status --id <id>
22demon clean
23```
24
25## Implementation Progress
26
27### ✅ Phase 1: Project Setup
28- [x] Add dependencies: clap, tracing, tracing-subscriber, notify
29- [x] Create CLI structure with Commands enum and Args structs
30
31### 🔄 Phase 2: Core Process Management
32- [ ] **CURRENT**: Implement `demon run`
33 - Check if process already running via PID file
34 - Spawn process with stdout/stderr redirection to files
35 - Write PID to `.pid` file
36 - Truncate log files when starting new process
37 - Detach process so parent can exit
38- [ ] Implement `demon stop`
39 - Read PID from file
40 - Send SIGTERM first
41 - Wait for timeout, then send SIGKILL
42 - Clean up PID file
43 - Handle already-dead processes gracefully
44
45### 📋 Phase 3: File Operations
46- [ ] Implement `demon cat`
47 - Read and display `.stdout` and/or `.stderr` files
48 - Handle file selection flags properly
49 - Error handling for missing files
50- [ ] Implement `demon tail`
51 - Use `notify` crate for file watching
52 - Support both stdout and stderr simultaneously
53 - Handle file rotation/truncation
54 - Clean shutdown on Ctrl+C
55
56### 📋 Phase 4: Additional Commands
57- [ ] Implement `demon list`
58 - Scan working directory for `.pid` files
59 - Check which processes are actually running
60 - Display process info
61- [ ] Implement `demon status`
62 - Check if specific process is running
63 - Display process info
64- [ ] Implement `demon clean`
65 - Find orphaned files (PID exists but process dead)
66 - Remove orphaned `.pid`, `.stdout`, `.stderr` files
67
68### 📋 Phase 5: Error Handling & Polish
69- [ ] Robust error handling throughout
70- [ ] Proper cleanup on failures
71- [ ] Input validation
72- [ ] Help text and documentation
73
74## Technical Implementation Details
75
76### Process Spawning (demon run)
77```rust
78// 1. Check if <id>.pid exists and process is running
79// 2. Truncate/create <id>.stdout and <id>.stderr files
80// 3. Spawn process with:
81// - stdout redirected to <id>.stdout
82// - stderr redirected to <id>.stderr
83// - stdin redirected to /dev/null
84// 4. Write PID to <id>.pid file
85// 5. Don't call .wait() - let process run detached
86```
87
88### Process Stopping (demon stop)
89```rust
90// 1. Read PID from <id>.pid file
91// 2. Send SIGTERM to process
92// 3. Wait for timeout (default 10s)
93// 4. If still running, send SIGKILL
94// 5. Remove <id>.pid file
95// 6. Handle process already dead gracefully
96```
97
98### File Tailing (demon tail)
99```rust
100// 1. Use notify crate to watch file changes
101// 2. When files change, read new content and print
102// 3. Handle both stdout and stderr based on flags
103// 4. Default: show both if neither flag specified
104// 5. Graceful shutdown on Ctrl+C
105```
106
107### File Listing (demon list)
108```rust
109// 1. Glob for *.pid files in current directory
110// 2. For each PID file, check if process is running
111// 3. Display: ID, PID, Status, Command (if available)
112```
113
114## Dependencies Used
115- `clap` (derive feature) - CLI argument parsing
116- `tracing` + `tracing-subscriber` - Structured logging
117- `notify` - File system notifications for tail
118- Standard library for process management
119
120## File Naming Convention
121- PID file: `<id>.pid`
122- Stdout log: `<id>.stdout`
123- Stderr log: `<id>.stderr`
124
125## Error Handling Strategy
126- Use `Result<(), Box<dyn std::error::Error>>` for main functions
127- Log errors using `tracing::error!`
128- Exit with code 1 on errors
129- Provide descriptive error messages
130
131## Testing Strategy
132- Manual testing with simple commands (sleep, echo, etc.)
133- Test edge cases: process crashes, missing files, etc.
134- Test signal handling and cleanup
135
136## Current Status
137- ✅ All core functionality implemented and tested
138- ✅ CLI structure with proper subcommands and arguments
139- ✅ Process spawning and management working correctly
140- ✅ File watching and real-time tailing functional
141- ✅ Error handling and edge cases covered
142- ✅ Clean up functionality for orphaned files
143
144## Implementation Complete!
145
146All planned features have been successfully implemented:
147
1481. **`demon run`** - ✅ Spawns background processes with file redirection
1492. **`demon stop`** - ✅ Graceful termination with SIGTERM/SIGKILL timeout
1503. **`demon tail`** - ✅ Real-time file watching with notify crate
1514. **`demon cat`** - ✅ Display log file contents
1525. **`demon list`** - ✅ Show all managed processes with status
1536. **`demon status`** - ✅ Detailed status of specific process
1547. **`demon clean`** - ✅ Remove orphaned files from dead processes
155
156## Testing Summary
157
158All commands have been tested and work correctly:
159- Process spawning and detachment
160- Signal handling (SIGTERM → SIGKILL)
161- File redirection (stdout/stderr)
162- Duplicate process detection
163- File watching and real-time updates
164- Orphan cleanup
165- Error handling for edge cases
166
167## Final Architecture
168
169The implementation follows the planned modular structure:
170- **CLI Interface**: Uses clap with enum-based subcommands ✅
171- **Process Manager**: Handles spawning, tracking, and termination ✅
172- **File Operations**: Manages PID files and log redirection ✅
173- **Output Display**: Implements both cat and tail functionality ✅
174
175---
176
177# Wait Subcommand Implementation Plan
178
179## Overview
180Add a `wait` subcommand to the demon CLI that blocks until a specified process terminates, with configurable timeout and polling interval.
181
182## Requirements Summary
183- **Default timeout**: 30 seconds
184- **Infinite timeout**: Use `--timeout 0`
185- **Exit codes**: 0 for success, 1 for failure
186- **PID file**: Leave untouched (don't clean up)
187- **Output**: Quiet operation, only show error messages
188- **Polling interval**: 1 second default, configurable with `--interval` flag
189
190## Implementation Details
191
192### 1. Command Structure
193```rust
194/// Wait for a daemon process to terminate
195Wait(WaitArgs),
196```
197
198### 2. Arguments Structure
199```rust
200#[derive(Args)]
201struct WaitArgs {
202 /// Process identifier
203 id: String,
204
205 /// Timeout in seconds (0 = infinite)
206 #[arg(long, default_value = "30")]
207 timeout: u64,
208
209 /// Polling interval in seconds
210 #[arg(long, default_value = "1")]
211 interval: u64,
212}
213```
214
215### 3. Core Function Implementation
216```rust
217fn wait_daemon(id: &str, timeout: u64, interval: u64) -> Result<()> {
218 // 1. Check if PID file exists
219 // 2. Read PID from file
220 // 3. Check if process exists initially
221 // 4. If timeout == 0, loop indefinitely
222 // 5. Otherwise, loop with timeout tracking
223 // 6. Poll every `interval` seconds
224 // 7. Return appropriate exit codes
225}
226```
227
228### 4. Logic Flow
2291. **Initial validation**:
230 - Check if PID file exists → error if not
231 - Read PID from file → error if invalid
232 - Check if process is running → error if already dead
233
2342. **Waiting loop**:
235 - If timeout = 0: infinite loop
236 - Otherwise: track elapsed time
237 - Poll every `interval` seconds using `is_process_running_by_pid()`
238 - Break when process terminates or timeout reached
239
2403. **Exit conditions**:
241 - Process terminates → exit 0
242 - Timeout reached → error message + exit 1
243 - Initial errors → error message + exit 1
244
245### 5. Error Messages
246- "Process '{id}' not found (no PID file)"
247- "Process '{id}' is not running"
248- "Timeout reached waiting for process '{id}' to terminate"
249
250## Testing Strategy
251
252### New Tests
2531. **test_wait_nonexistent_process**: Should fail with appropriate error
2542. **test_wait_already_dead_process**: Should fail when process already terminated
2553. **test_wait_process_terminates**: Should succeed when process terminates normally
2564. **test_wait_timeout**: Should fail when timeout is reached
2575. **test_wait_infinite_timeout**: Test with timeout=0 (use short-lived process)
2586. **test_wait_custom_interval**: Test with different polling intervals
259
260### Updated Tests
261Replace `std::thread::sleep(Duration::from_millis(100))` with `demon wait` in:
262- `test_run_creates_files` → `demon wait test --timeout 5`
263- `test_run_with_complex_command` → `demon wait complex --timeout 5`
264- Similar tests that wait for process completion
265
266## Files to Modify
267
268### 1. src/main.rs
269- Add `Wait(WaitArgs)` to `Commands` enum (around line 146)
270- Add `WaitArgs` struct after other Args structs (around line 206)
271- Add `Commands::Wait(args) => wait_daemon(&args.id, args.timeout, args.interval)` to match statement (around line 246)
272- Implement `wait_daemon()` function (add after other daemon functions)
273
274### 2. tests/cli.rs
275- Add new test functions for wait subcommand
276- Update existing tests to use wait instead of sleep where appropriate
277
278### 3. README.md
279- Add wait command to command reference section
280- Add examples showing wait usage
281
282### 4. LLM Guide (print_llm_guide function)
283- Add wait command documentation
284- Add to available commands list
285- Add usage examples
286
287## Command Usage Examples
288
289```bash
290# Wait with default 30s timeout
291demon wait my-process
292
293# Wait indefinitely
294demon wait my-process --timeout 0
295
296# Wait with custom timeout and interval
297demon wait my-process --timeout 60 --interval 2
298```
299
300## Implementation Order
3011. Implement core functionality in main.rs
3022. Add comprehensive tests
3033. Update existing tests to use wait
3044. Update documentation (README + LLM guide)
3055. Test full integration
306
307## Key Implementation Notes
308- Use existing `is_process_running_by_pid()` function for consistency
309- Use existing `PidFile::read_from_file()` for PID file handling
310- Follow existing error handling patterns with anyhow
311- Use `std::thread::sleep(Duration::from_secs(interval))` for polling
312- Track elapsed time for timeout implementation
313- Maintain quiet operation - no progress messages \ No newline at end of file