feat(sync,prune): hook lifecycle in TUI with verbose job sub-rows#290
Merged
feat(sync,prune): hook lifecycle in TUI with verbose job sub-rows#290
Conversation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements ProgressSink (no-op) and HookRunner via HookExecutor, forwarding HookStarted/HookCompleted DagEvents through the DAG channel. Skipped hooks produce no events; abort-mode failures are caught and surfaced as failed events rather than propagating the error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- execute_prune_task now accepts hooks_config and tx parameters and uses TuiBridge so hook events are forwarded to the TUI renderer - handle_post_tui_deferred now accepts hooks_config and uses CommandBridge so hooks run with full CLI output after TUI exits - Remove NullBridge import (no longer used in this file) WIP: call sites in prune.rs and sync.rs not yet updated Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add exit_code to HookCompleted event and HookSummaryEntry, fix post-TUI summary format to show exit codes and 'Prune was aborted' line, add clarifying comment for warned flag semantics. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Verifies that worktree-pre-remove hooks are executed when git-worktree-prune removes a worktree whose remote branch was deleted. The test creates a feature branch that inherits .daft/hooks/ from main, trusts the repository, deletes the remote branch, and runs prune. It then asserts that the pre-remove hook marker file was created with the correct DAFT_BRANCH_NAME. This covers both the sequential path (CommandBridge, always executed hooks) and proves the overall wiring works after the NullBridge→TuiBridge fix that enables hooks in TUI mode. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…w rendering
Two rendering issues fixed:
1. Hook status labels ("worktree-pre-remove") were wider than STATUS_MAX_WIDTH,
causing the Status column to dynamically expand and garble the table layout.
Use short labels ("pre-remove") instead and bump STATUS_MAX_WIDTH to 13.
2. Hook sub-rows had only 1 cell but the table has multiple columns, causing
ratatui to squish content into the Status column width. Sub-rows now have
the correct number of cells (empty cells for non-Status columns).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Foundation for the three-layer separation architecture that decouples job execution from presentation. Introduces generic types (JobSpec, ExecutionMode, NodeStatus, JobResult), a JobPresenter trait with NullPresenter for tests, and a CliPresenter wrapping HookRenderer with interior Mutex for thread safety. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add migration note on NodeStatus to replace TaskStatus - Clarify ExecutionMode docs re: DAG mode and hooks Follow variant - Use .lock().expect() instead of .unwrap() for clearer panic messages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract shell command spawning logic from hooks/yaml_executor/command.rs into src/executor/command.rs with a hooks-independent CommandResult type. The old functions become thin wrappers that build the hook environment and delegate to the new generalized functions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…l execution Extract domain-agnostic DAG scheduling from hooks and sync implementations into a reusable DagGraph that handles ordering, failure cascading, and thread coordination via closure-based task execution. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement run_jobs() that combines JobSpec execution with presenter notifications. Routes to sequential, piped (stop-on-failure), parallel, or DAG-ordered execution based on mode and dependencies. Includes real-time output streaming via reader threads and comprehensive tests (33 unit tests covering all execution modes, presenter events, and edge cases). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bridge between the hooks input layer (YAML JobDef, legacy script paths) and the generic executor. yaml_jobs_to_specs handles command resolution, env merging, working dir, RC sourcing, and template substitution. scripts_to_specs converts legacy hook scripts into JobSpec values. Group jobs are skipped for now (to be handled in full migration). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace direct process spawning in HookExecutor::execute_legacy() with scripts_to_specs() + run_jobs(), delegating to the new generic executor pipeline. The execute() signature now accepts Arc<dyn JobPresenter> so callers control presentation. Key changes: - execute() takes an Arc<dyn JobPresenter> parameter - Legacy path uses job_adapter::scripts_to_specs() + runner::run_jobs() - Remove execute_hook_file_with_renderer() and wait_with_timeout() - Remove unused imports (BufRead, BufReader, Command, Stdio, Duration) - CLI callers pass CliPresenter::auto(), TUI bridge passes NullPresenter - CommandBridge stores HookOutputConfig for presenter construction - try_yaml_hook() accepts presenter (unused for now, future migration) - All 4 executor.rs tests updated to pass NullPresenter Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements JobPresenter for the TUI renderer by forwarding phase-level lifecycle events (HookStarted, HookCompleted) through an mpsc channel instead of writing directly to stderr. Job-level events are no-ops since the TUI shows phase-level status only, though output is accumulated for failure reporting. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
TuiPresenter implements JobPresenter and sends DagEvents through the mpsc channel in real-time, replacing the retroactive event sending that currently happens in TuiBridge. This prevents ratatui and indicatif from both writing to stderr simultaneously (which causes garbled output). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wire TuiPresenter into TuiBridge so hook lifecycle events (HookStarted, HookCompleted) are sent in real-time via presenter callbacks instead of retroactively after execution completes. This eliminates the garbled TUI rendering caused by hooks executing between retroactive event pairs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove the old sequential.rs, parallel.rs, and dependency.rs modules from yaml_executor and route YAML hook execution through the generic executor (job_adapter + runner::run_jobs). This unifies both legacy script hooks and YAML hooks under the same execution engine. - Delete yaml_executor/sequential.rs, parallel.rs, dependency.rs, command.rs - Remove ExecContext and ParallelJobData structs (no longer needed) - Remove execute_jobs() and execute_single_job() functions - Add presenter parameter to execute_yaml_hook_with_rc() - Convert YAML ExecutionMode to generic executor::ExecutionMode - Use yaml_jobs_to_specs() + run_jobs() for execution - Convert Vec<JobResult> back to HookResult via job_results_to_hook_result() - Forward presenter from try_yaml_hook() to the YAML execution path Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
print_hook_header and print_hook_summary are no longer called after the yaml_executor migration to the generic executor (which uses the JobPresenter trait for progress output). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Hook sub-rows were truncated because they were confined to table column widths. Instead, render them as Paragraph overlays on empty placeholder rows so the hook name and status can use the full terminal width. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ough - Add ACCENT_COLOR_INDEX constant in styles.rs as single source of truth for the brand color (orange 208) - Hook names in verbose TUI now render in the accent color - Add job-level sub-rows under hooks in verbose mode with status-colored names, tree indentation, icons, and duration - New DagEvent::JobStarted/JobCompleted variants carry job lifecycle events from TuiPresenter through the channel to TuiState - Pruned worktree rows get strikethrough+dim from Branch column onwards - Increase viewport budget for job sub-rows Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Render pruned row content (Branch column onwards) as a single overlay Paragraph instead of per-cell styling, so the CROSSED_OUT modifier runs unbroken through column separator gaps and ends at the last column's text boundary. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
daft syncanddaft pruneTUI mode, with real-time status display as sub-rows beneath each worktree-v): Shows hook sub-rows with orange accent-colored names, and nested job sub-rows with status-colored names (green/red/yellow), duration, and tree-drawing connectors-v/-vv):-vshows inline hook/job progress in TUI;-vvfalls back to full sequential CLI outputTest plan
mise run test:unit— 618 tests pass (612 lib + 6 security)mise run clippy— zero warningsmise run fmt:check— cleandaft sync -vin a repo with hooks having multiple jobs — verify hook names orange, job sub-rows visible with correct status colors and durationsdaft pruneafter deleting remote branches — verify pruned rows have continuous strikethroughdaft sync(no-v) — verify non-verbose mode is unchangeddaft sync -vv— verify full sequential CLI output fallback🤖 Generated with Claude Code