Extract addXxxOptions() builder functions for all 9 shared commands
(ls, run, attach, logs, stop, delete, send, inspect, wait) so both
paseo <cmd> and paseo agent <cmd> use a single source of truth.
Fixes drift where agent subcommands were missing --wait-timeout (run),
--worktree/--base/--image (run), --since (logs), and --image (send).
Replace hardcoded 10-minute timeout with configurable --wait-timeout.
Default is no limit, matching the wait command behavior. Extracts
parseDuration to shared utils so both run and wait can use it.
Fixes OUTPUT_SCHEMA_FAILED errors when agents take >10 minutes.
Replace inline data-URL image handling with a persistent attachment storage service, add draft lifecycle states (active/abandoned/sent) with generation tracking, and update fetchAgent to return project placement alongside agent snapshots.
What I changed:
- extracted a single missingModeError helper in agent/mode.ts so the command no longer duplicates the same command error payload in two branches
- flattened control flow by returning early for --list and using one set-mode path guarded by explicit missing-mode validation
- tightened tests/10-agent-mode.test.ts to assert the exact missing-mode error message instead of allowing a daemon-connection fallback
Reasoning:
- this keeps behavior the same while reducing branch duplication and making the validation contract explicit
- the hardened test protects the intended precedence: missing required mode should fail before any daemon interaction
Verification:
- npm run typecheck
- (cd packages/cli && npx tsx tests/10-agent-mode.test.ts)
Notes for next agent:
- repository had a pre-existing local modification in scripts/codex-refactor-loop.sh; I intentionally did not touch or stage it
- no blockers encountered for this refactor
Context from recent agent work
- Prior commits focused on voice/background model gating, speech resolver typing, and timeline cursor loading.
- This change targets a separate CLI command path to avoid overlap.
What changed
- Normalized the optional mode argument once (`mode?.trim()`) and reused it.
- Removed duplicated `client.close()` calls and centralized cleanup in a `finally` block.
- Typed the daemon client variable explicitly (`Awaited<ReturnType<typeof connectToDaemon>> | undefined`).
- Kept user-facing behavior and error codes stable, including DAEMON_NOT_RUNNING and MODE_OPERATION_FAILED.
Reasoning
- The previous implementation duplicated lifecycle handling and relied on non-null assertions for mode values.
- Centralized resource cleanup lowers leak risk and makes control flow easier to audit.
- This is a behavior-preserving refactor aligned with the refactor skill contract.
Verification
- `npm run typecheck`
- `npx tsx packages/cli/tests/10-agent-mode.test.ts`
Accomplishments for next agent
- `runModeCommand` now has a single cleanup path and clearer branching for list vs set mode.
- Mode argument handling is explicit and trimmed before use.
Challenges / follow-up
- CLI output typing still requires `AnyCommandResult<any>` for mixed-shape commands due the current `withOutput` generic design.
- If desired, a future refactor can redesign output typing to support per-branch result schemas without `any`.
Add the `paseo agent inspect <id>` command that shows detailed
information about an agent:
- Id, name, provider, model, status, mode, cwd
- Creation timestamp
- Token usage (input, output, cached, cost)
- Capabilities (streaming, persistence, dynamic modes, MCP servers)
- Available modes
- Pending permissions count
- Parent agent ID
The default output is YAML-like key-value pairs. Use `--format json`
or `--format yaml` for machine-readable output with the full agent
snapshot.
Supports agent ID prefix matching.
Add the `paseo agent mode` command for changing and listing agent
operational modes. Supports setting a mode or listing available modes
with the --list flag.
Usage:
paseo agent mode <id> <mode> # Set mode
paseo agent mode --list <id> # List available modes
Implements the `agent stop` command for stopping agents.
Features:
- Stop a specific agent by ID (with prefix matching)
- --all flag to stop all running agents
- --cwd flag to stop all agents in a specific directory
- Cancels running agents before terminating them
- Graceful error handling for partially failed stops
Usage:
paseo agent stop <id>
paseo agent stop --all
paseo agent stop --cwd ~/dev/paseo
Implements the `agent send` command for sending messages to existing agents.
Features:
- Send follow-up tasks to running agents
- Support for ID prefix matching (e.g., "a1b2" matches "a1b2c3d4")
- --no-wait flag to return immediately without waiting for completion
- Default behavior waits for agent to become idle
Usage:
paseo agent send <id> <prompt>
paseo agent send --no-wait a1b2c3d "Run the linter"
Implements the `paseo agent run` command for creating and running agents:
- Creates agent with initial prompt
- `-d, --detach` flag for background execution
- `--name <name>` to assign a title
- `--provider <provider>` to select claude/codex/opencode
- `--mode <mode>` for provider-specific modes
- `--cwd <path>` for working directory
- Supports all output formats (table, json, yaml, quiet)
- Graceful error handling when daemon not running
Usage:
paseo agent run "Fix the failing tests"
paseo agent run -d --name "test-fixer" "Run the test suite"
paseo agent run --mode bypass "Refactor the auth module"
Phase 4 of CLI implementation (TDD checklist 4.1-4.6)
Implements the `paseo agent ps` command for listing agents:
- Lists running agents by default
- `-a, --all` flag to include archived agents
- `--status <status>` filter by agent status
- `--cwd <path>` filter by working directory
- Supports all output formats (table, json, yaml, quiet)
- Graceful error handling when daemon not running
Output format:
AGENT ID NAME PROVIDER STATUS CWD CREATED
a1b2c3d 🎭 Test fixer claude running ~/dev/paseo 2 minutes ago
Phase 3 of CLI implementation (TDD checklist 3.1-3.5)