plan diff now detects the worktree branch cleveragents/plan-<id> created
during plan execute and runs git diff HEAD...<branch> to display actual
file changes. Falls back to changeset-based diff when no worktree branch
exists.
Infrastructure layer:
- GitWorktreeSandbox.diff_against_head() classmethod: checks branch
existence via rev-parse, runs git diff, returns diff text or None
- Uses _run_git() helper (existing) for subprocess calls with proper
CalledProcessError/TimeoutExpired handling
CLI layer:
- _get_worktree_diff() thin wrapper: resolves plan -> project -> resource
via DI container, delegates to GitWorktreeSandbox.diff_against_head()
- Specific exception handling (NotFoundError, CleverAgentsError) with
structlog debug logging
- Input validation: empty plan_id returns None early
- Called in plan_diff() before changeset fallback (spec §13225)
Tests:
- 4 Behave scenarios covering: branch exists with diff, no branch,
service resolution path, no linked resources fallback
Fixes:
- CheckpointRepository prune test: use shared session so flush() in
create() is visible to prune() within the same scenario
ISSUES CLOSED: #9231