terminal user interface to jujutsu. Focused on speed and clarity
9
fork

Configure Feed

Select the types of activity you want to include in your feed.

produce plan

+1402 -119
+104
.planning/PROJECT.md
··· 1 + # jj_tui - Interactive Rebase Preview 2 + 3 + ## What This Is 4 + 5 + A terminal UI for Jujutsu (jj) version control that provides visual, interactive rebase previews. Users can see exactly how their commit graph will look after a rebase before executing the operation, making rebasing safer and more intuitive. 6 + 7 + ## Core Value 8 + 9 + Visual rebase preview with live graph updates - users must be able to configure a rebase interactively, see the resulting graph structure with preview nodes, and execute only when they're confident the result is correct. 10 + 11 + ## Requirements 12 + 13 + ### Validated 14 + 15 + <!-- Existing capabilities confirmed from codebase --> 16 + 17 + - ✓ TUI commit graph visualization with Nottui/Notty/Lwd - existing 18 + - ✓ JJ CLI subprocess execution and output parsing - existing 19 + - ✓ Reactive UI state management via Lwd.var - existing 20 + - ✓ Multi-node selection with space key - existing 21 + - ✓ Graph navigation (up/down/scroll) - existing 22 + - ✓ Custom graph renderer (static display working) - existing 23 + - ✓ Rebase command variants (single/children/branch) - existing 24 + - ✓ Command keybinding system with mode support - existing 25 + - ✓ Functor-based modular architecture - existing 26 + 27 + ### Active 28 + 29 + <!-- Current scope: Interactive rebase preview feature --> 30 + 31 + - [ ] Rebase mode activation (press 'r' on hovered commit) 32 + - [ ] Destination selection (space-select target nodes while in rebase mode) 33 + - [ ] Source mode toggle (press 's': single/children/branch) 34 + - [ ] Destination mode toggle (press 'd': insert-before/insert-after/add-after) 35 + - [ ] Preview node insertion into graph data structure 36 + - [ ] Preview node rendering (distinct color + symbol) 37 + - [ ] Dynamic graph re-rendering on mode/selection changes 38 + - [ ] Cycle detection (prevent commit being ancestor + descendant) 39 + - [ ] UI mode indicators (show current source and destination modes) 40 + - [ ] Rebase execution on confirmation (press 'y') 41 + - [ ] Cancel and exit rebase mode (press 'esc') 42 + 43 + ### Out of Scope 44 + 45 + - Multiple simultaneous rebases (treating multi-select as separate operations) - complexity not needed for MVP 46 + - Other preview modes (squash, split, parallelize) - future enhancement 47 + - Performance optimization for large graphs - premature until rebase preview works 48 + - Undo/redo within rebase preview mode - JJ has `jj undo` at CLI level 49 + - Persistent rebase state across sessions - ephemeral mode is sufficient 50 + 51 + ## Context 52 + 53 + **Codebase Architecture:** 54 + - OCaml 5.2+ functional reactive TUI 55 + - Nottui/Notty for terminal rendering, Lwd for reactive state 56 + - Picos for structured concurrency 57 + - Custom graph renderer in `render_jj_graph.ml` (1,117 lines, lane-based algorithm) 58 + - Command system in `graph_commands.ml` with 547 lines of existing commands 59 + - Global reactive state in `global_vars.ml` (ui_state_t, graph state) 60 + 61 + **Graph Rendering:** 62 + - Custom renderer implemented and working for static display 63 + - Renders commit graph with Unicode box-drawing glyphs 64 + - Lane-based algorithm handles node positioning and parent-child relationships 65 + - Golden tests verify exact glyph output 66 + 67 + **Rebase Command Structure:** 68 + - Three source modes: single revision (`-r`), with descendants (`-s`), bookmark (`-b`) 69 + - Destination specified via `-d` flag 70 + - Insert modes: `--insert-before`, `--insert-after`, or default (add as parent) 71 + - Existing commands at lines 312-342 in `graph_commands.ml` 72 + 73 + **Technical Debt to Navigate:** 74 + - Frame rendering delay (TODO in `global_funcs.ml:46`) 75 + - Unsafe list access patterns in graph rendering 76 + - No tests for command execution logic 77 + 78 + **Known Constraints:** 79 + - Must integrate with existing JJ CLI (no direct repo access) 80 + - Graph structure from JJ must be augmented, not replaced 81 + - Preview nodes need clear visual distinction to avoid confusion 82 + 83 + ## Constraints 84 + 85 + - **Language**: OCaml 5.2+ - existing codebase 86 + - **TUI Framework**: Nottui/Notty/Lwd - forked versions maintained in `forks/` 87 + - **VCS Integration**: JJ CLI subprocess execution only - no direct libgit2/jj library access 88 + - **Architecture**: Functor-based with reactive state - must maintain existing patterns 89 + - **Build System**: Dune 3.12+ - established build configuration 90 + - **Testing**: ppx_expect inline tests - existing test infrastructure 91 + 92 + ## Key Decisions 93 + 94 + | Decision | Rationale | Outcome | 95 + |----------|-----------|---------| 96 + | Custom graph renderer over jj's ASCII output | Need dynamic preview node insertion and re-rendering | ✓ Good - static rendering complete | 97 + | Hovered node as rebase source, space-select for destinations | Consistent with existing selection model, clear intent | — Pending | 98 + | Single rebase at a time (ignore multi-select) | Simpler state management, clearer preview | — Pending | 99 + | Mode toggles with 'd'/'s' keys | Quick iteration without prompts, shows all options | — Pending | 100 + | Distinct preview node rendering (color + symbol) | Must be unmistakably different from real commits | — Pending | 101 + | Cycle detection before preview | Prevent invalid graph states, better UX than error on execute | — Pending | 102 + 103 + --- 104 + *Last updated: 2026-01-15 after initialization*
+173
.planning/codebase/ARCHITECTURE.md
··· 1 + # Architecture 2 + 3 + **Analysis Date:** 2026-01-15 4 + 5 + ## Pattern Overview 6 + 7 + **Overall:** Functional Reactive TUI Application with Structured Concurrency 8 + 9 + **Key Characteristics:** 10 + - Single native executable with reactive UI 11 + - Functor-based modular architecture 12 + - Structured concurrency via Picos multi-domain parallelism 13 + - Reactive data flow using Lwd 14 + 15 + ## Layers 16 + 17 + **UI/Presentation Layer:** 18 + - Purpose: Terminal rendering and user interaction 19 + - Contains: View implementations, widget composition, rendering logic 20 + - Key modules: 21 + - `jj_tui/bin/jj_ui.ml` - Main UI orchestrator 22 + - `jj_tui/bin/graph_view.ml` - Commit graph visualization 23 + - `jj_tui/bin/file_view.ml` - File explorer and modification pane 24 + - `jj_tui/bin/show_view.ml` - Details/preview pane 25 + - `jj_tui/lib/commit_render.ml` - Commit rendering with syntax highlighting 26 + - Depends on: Notty, Nottui, Lwd, global state 27 + - Used by: Main entry point 28 + 29 + **Command/Input Layer:** 30 + - Purpose: Handle user input and map to actions 31 + - Contains: Command definitions, keybinding system, input handlers 32 + - Key modules: 33 + - `jj_tui/bin/graph_commands.ml` - Graph view commands (552 lines) 34 + - `jj_tui/bin/file_commands.ml` - File view commands 35 + - `jj_tui/bin/jj_commands.ml` - Core command execution framework (512 lines) 36 + - `jj_tui/lib/key_map.ml` - Flexible keybinding system (405 lines) 37 + - Depends on: Global state, JJ process layer 38 + - Used by: View implementations 39 + 40 + **State Management Layer:** 41 + - Purpose: Reactive application state 42 + - Contains: Lwd.var-based state store 43 + - Key modules: 44 + - `jj_tui/bin/global_vars.ml` - Central reactive state (ui_state_t, graph state) 45 + - `jj_tui/bin/global_funcs.ml` - State manipulation utilities 46 + - Depends on: Lwd reactive primitives 47 + - Used by: All layers 48 + 49 + **Process Execution Layer:** 50 + - Purpose: Execute JJ CLI and parse output 51 + - Contains: Process spawning, output parsing, JJ integration 52 + - Key modules: 53 + - `jj_tui/bin/jj_process.ml` - Mutex-protected JJ CLI execution (375 lines) 54 + - `jj_tui/lib/process_wrappers.ml` - JJ output parsing (336 lines) 55 + - `jj_tui/lib/jj_json.ml` - JSON/JSONL parsing from jj log 56 + - Depends on: Picos_io for async I/O 57 + - Used by: Command layer 58 + 59 + **Data Processing Layer:** 60 + - Purpose: Parse and render JJ data structures 61 + - Contains: Graph rendering algorithm, ANSI parsing 62 + - Key modules: 63 + - `jj_tui/lib/render_jj_graph.ml` - Lane-based graph rendering (1,117 lines) 64 + - `jj_tui/lib/ansiReverse.ml` - ANSI escape code handling (337 lines) 65 + - `jj_tui/lib/outputParsing.ml` - JJ output utilities 66 + - Depends on: Parsing libraries (angstrom, re) 67 + - Used by: UI layer 68 + 69 + **Configuration Layer:** 70 + - Purpose: Load and manage user preferences 71 + - Contains: Config loading, logging setup 72 + - Key modules: 73 + - `jj_tui/lib/config.ml` - YAML config loading 74 + - `jj_tui/lib/logging.ml` - Structured logging 75 + - `jj_tui/lib/os.ml` - OS detection 76 + - Depends on: Yaml, logs libraries 77 + - Used by: All layers 78 + 79 + ## Data Flow 80 + 81 + **User Input Flow:** 82 + 83 + 1. User presses key in terminal 84 + 2. `jj_tui/bin/main.ml` - Nottui event loop captures input 85 + 3. `jj_tui/bin/jj_ui.ml` - UI forwards event to active view 86 + 4. Command lookup via `key_map` registry 87 + 5. Command builder in `graph_commands.ml` or `file_commands.ml` constructs command variant 88 + 6. `jj_tui/bin/jj_commands.ml` - `run_command` executes command 89 + 7. `jj_tui/bin/jj_process.ml` - JJ CLI execution (mutex-protected) 90 + 8. Output parsing via `jj_json.ml` or `process_wrappers.ml` 91 + 9. State update via `Lwd.set` in `global_vars.ml` 92 + 10. Reactive re-render: `render_jj_graph.ml` + `commit_render.ml` 93 + 11. Display to terminal via Notty 94 + 95 + **Command Execution Lifecycle:** 96 + 97 + ``` 98 + Key press → Command resolution → Command variant construction → 99 + Async execution (Cmd_async) or Synchronous (Cmd) → 100 + JJ process spawn → Output capture → State update → UI re-render 101 + ``` 102 + 103 + **State Management:** 104 + - All state stored as `Lwd.var` reactive variables 105 + - Changes trigger automatic UI updates 106 + - Global mutex prevents concurrent JJ CLI access 107 + 108 + ## Key Abstractions 109 + 110 + **Functors (Dependency Injection):** 111 + - Purpose: Modular architecture with testability 112 + - Pattern: `module Make (Vars : Global_vars.Vars)` 113 + - Examples: 114 + - `Jj_ui.Make(Vars)` - `jj_tui/bin/jj_ui.ml` 115 + - `Graph_view.Make(Vars)`, `File_view.Make(Vars)` - View implementations 116 + - `Jj_process.Make(Vars)` - Process execution 117 + - `Graph_commands.Make(Vars)`, `File_commands.Make(Vars)` - Command definitions 118 + 119 + **Command Variants:** 120 + - Purpose: Flexible command system supporting various execution patterns 121 + - Examples: `Cmd`, `Cmd_r`, `Dynamic_r`, `PromptThen`, `Selection_prompt`, `Cmd_async`, `SubCmd` 122 + - Pattern: Variant types with lazy evaluation and composition 123 + 124 + **Reactive Variables (Lwd.var):** 125 + - Purpose: State management with automatic propagation 126 + - Examples: `hovered_revision`, `graph_revs`, `ui_state`, `term_width_height` 127 + - Pattern: `let$` syntax sugar for reactive bindings 128 + 129 + **Process Safety:** 130 + - Purpose: Prevent concurrent JJ CLI access 131 + - Pattern: Global mutex `Jj_process.access_lock` in `jj_tui/bin/jj_process.ml` 132 + - Concurrency: Picos structured concurrency with Flock task management 133 + 134 + ## Entry Points 135 + 136 + **Main Executable:** 137 + - Location: `jj_tui/bin/main.ml` (88 lines) 138 + - Triggers: User runs `jj_tui` command 139 + - Responsibilities: Initialize 4 Picos domains, setup logging, launch TUI event loop 140 + 141 + **UI Orchestrator:** 142 + - Location: `jj_tui/bin/jj_ui.ml` (261 lines) 143 + - Triggers: Called by main after initialization 144 + - Responsibilities: Bind views together, forward events, manage popups 145 + 146 + ## Error Handling 147 + 148 + **Strategy:** Exception-based with Result types for parsing 149 + 150 + **Patterns:** 151 + - Process errors: Captured and logged, UI shows error messages 152 + - Parse errors: Result types propagate failures to UI 153 + - Unsafe operations: Some intentional `failwith` for programmer errors 154 + 155 + ## Cross-Cutting Concerns 156 + 157 + **Logging:** 158 + - File-based logging via `logs` library - `jj_tui/lib/logging.ml` 159 + - Mutex-protected for thread safety 160 + - Platform-specific log directories 161 + 162 + **Validation:** 163 + - YAML schema validation for config - `jj_tui/lib/config.ml` 164 + - Key binding validation - `jj_tui/lib/key.ml` 165 + 166 + **Concurrency:** 167 + - Picos structured concurrency - 4 domains launched in `jj_tui/bin/main.ml` 168 + - Global mutex for JJ CLI access - `jj_tui/bin/jj_process.ml` 169 + 170 + --- 171 + 172 + *Architecture analysis: 2026-01-15* 173 + *Update when major patterns change*
+176
.planning/codebase/CONCERNS.md
··· 1 + # Codebase Concerns 2 + 3 + **Analysis Date:** 2026-01-15 4 + 5 + ## Tech Debt 6 + 7 + **Rendering delay (performance):** 8 + - Issue: UI always renders "at least one frame behind" user input 9 + - Files: `jj_tui/bin/global_funcs.ml:46` (TODO comment) 10 + - Why: Current reactive variable update pattern introduces frame delay 11 + - Impact: Slight UI lag, user perceives delayed response 12 + - Fix approach: Mailbox processor pattern to trigger updates without Lwd.var delay 13 + 14 + **Double rendering requirement:** 15 + - Issue: Some UI updates require double render pass for correct display 16 + - Files: `jj_tui/bin/graph_view.ml:137` (TODO comment) 17 + - Why: Dependency on layout calculations from previous frame 18 + - Impact: Slight performance overhead, extra frame delay 19 + - Fix approach: Refactor rendering to compute layout in single pass 20 + 21 + **DOP list duplication:** 22 + - Issue: "Stop using dop last twice" - code duplication in list processing 23 + - Files: `jj_tui/bin/global_funcs.ml:61` (TODO comment) 24 + - Why: Quick implementation without refactoring 25 + - Impact: Redundant computation, harder to maintain 26 + - Fix approach: Extract shared logic into helper function 27 + 28 + **Commented-out code:** 29 + - Issue: Large blocks of old implementation left in comments 30 + - Files: `jj_tui/bin/jj_process.ml:57-110` (picos_process old implementation) 31 + - Why: Historical reference during refactoring 32 + - Impact: Code clutter, confusion for new contributors 33 + - Fix approach: Remove commented code, rely on git history 34 + 35 + ## Known Bugs 36 + 37 + **No known critical bugs documented** 38 + - No explicit bug tracking in code comments 39 + - No FIXME comments found 40 + - TODO items represent planned improvements, not bugs 41 + 42 + ## Security Considerations 43 + 44 + **Shell command execution (low risk):** 45 + - Risk: JJ CLI executed with user-provided arguments 46 + - Files: `jj_tui/bin/jj_process.ml` 47 + - Current mitigation: Arguments come from UI state, not direct user input 48 + - Recommendations: Input validation already adequate for TUI context 49 + 50 + **Build-time shell substitution:** 51 + - Risk: Shell command in dune build rule with environment variable 52 + - Files: `jj_tui/bin/dune:40-42` (GIT_DESCRIBE substitution) 53 + - Current mitigation: Build-time only, not runtime 54 + - Recommendations: Low priority - build environment trusted 55 + 56 + **Unsafe operations:** 57 + - Risk: `unsafe_color_of_int`, `unsafe_style_of_int` could crash on invalid input 58 + - Files: `jj_tui/lib/ansiReverse.ml:9-11,14-15,142,164` 59 + - Current mitigation: Input validated by ANSI parser before unsafe ops 60 + - Recommendations: Add defensive checks or document preconditions 61 + 62 + ## Performance Bottlenecks 63 + 64 + **Graph rendering complexity:** 65 + - Problem: Graph rendering algorithm is computationally intensive 66 + - Files: `jj_tui/lib/render_jj_graph.ml` (1,117 lines) 67 + - Measurement: No profiling data available 68 + - Cause: Lane-based algorithm with complex state tracking 69 + - Improvement path: Profile to identify hotspots, consider caching rendered glyphs 70 + 71 + **String concatenation in loops:** 72 + - Problem: Inefficient string building during graph construction 73 + - Files: `jj_tui/lib/process_wrappers.ml:161` 74 + - Cause: Using `^` operator instead of Buffer 75 + - Improvement path: Replace with `Buffer.add_string` for better performance 76 + 77 + **ANSI parsing on every render:** 78 + - Problem: Complex regex parsing runs on each frame 79 + - Files: `jj_tui/lib/ansiReverse.ml` 80 + - Cause: No caching of parsed ANSI sequences 81 + - Improvement path: Cache parsed output keyed by input string 82 + 83 + ## Fragile Areas 84 + 85 + **Unsafe list access (high risk):** 86 + - Why fragile: `List.hd`, `List.nth` crash on empty/short lists 87 + - Files: 88 + - `jj_tui/bin/graph_view.ml:68,87` - unchecked `List.nth` 89 + - `jj_tui/lib/render_jj_graph.ml:525,1092` - `List.hd` without empty check 90 + - Multiple test files use `List.hd` (acceptable in tests) 91 + - Common failures: Runtime exceptions on empty lists 92 + - Safe modification: Use pattern matching or `List.nth_opt` 93 + - Test coverage: No tests for edge cases (empty lists) 94 + 95 + **Error escalation with failwith:** 96 + - Why fragile: Parsing errors converted to exceptions instead of Result propagation 97 + - Files: 98 + - `jj_tui/lib/jj_json.ml:88` - failwith on JSON parse error 99 + - `jj_tui/lib/process_wrappers.ml:63,72` - failwith for divergent parsing 100 + - `jj_tui/lib/util.ml:54` - failwith for unicode validation 101 + - Common failures: Crashes on malformed JJ output 102 + - Safe modification: Return `Result.t` throughout parsing pipeline 103 + - Test coverage: Limited error case testing 104 + 105 + **Mutable state in rendering:** 106 + - Why fragile: Multiple refs in graph rendering create complex state dependencies 107 + - Files: `jj_tui/lib/render_jj_graph.ml` (refs: `need_link_line`, `columns`, `result`, etc.) 108 + - Common failures: State inconsistencies if render order changes 109 + - Safe modification: Refactor to pure functional style with explicit state passing 110 + - Test coverage: Golden tests catch output changes but not state bugs 111 + 112 + ## Scaling Limits 113 + 114 + **No explicit scaling limits identified** 115 + - Application is a local TUI tool, not a service 116 + - Performance scales with JJ repository size 117 + - Memory usage grows with commit graph size 118 + 119 + ## Dependencies at Risk 120 + 121 + **ppx_record_updater (unmaintained fork):** 122 + - Risk: Pinned to personal fork `git+https://github.com/faldor20/ppx_record_updater.git` 123 + - Files: `dune-project` 124 + - Impact: Custom record update syntax used throughout (`[@updater]` attribute) 125 + - Migration plan: Monitor upstream, consider inlining if abandoned 126 + 127 + **Forked UI libraries:** 128 + - Risk: Maintaining forks of nottui, notty, lwd 129 + - Files: `forks/nottui/`, `forks/notty/`, `forks/lwd/` 130 + - Impact: Need to track upstream changes, apply patches manually 131 + - Migration plan: Contribute patches upstream, reduce divergence 132 + 133 + ## Missing Critical Features 134 + 135 + **No persistent state:** 136 + - Problem: No session persistence across restarts 137 + - Current workaround: Users restart from scratch each time 138 + - Blocks: Resuming work, saving UI preferences beyond config 139 + - Implementation complexity: Medium (add state serialization) 140 + 141 + **No undo/redo:** 142 + - Problem: JJ operations cannot be undone from TUI 143 + - Current workaround: Use JJ CLI `jj undo` manually 144 + - Blocks: Safe experimentation with rebases/squashes 145 + - Implementation complexity: Medium (track command history) 146 + 147 + ## Test Coverage Gaps 148 + 149 + **Command execution untested:** 150 + - What's not tested: Core command execution logic in `jj_commands.ml` (512 lines) 151 + - Risk: Commands could fail silently, incorrect JJ CLI invocation 152 + - Priority: High 153 + - Difficulty to test: Medium (need mock JJ CLI or integration tests) 154 + 155 + **Process execution untested:** 156 + - What's not tested: JJ process spawning in `jj_process.ml` (375 lines) 157 + - Risk: Process management bugs, I/O handling failures 158 + - Priority: High 159 + - Difficulty to test: Medium (need process mocking) 160 + 161 + **UI orchestration untested:** 162 + - What's not tested: Main UI logic in `jj_ui.ml` (261 lines) 163 + - Risk: Event routing bugs, view integration issues 164 + - Priority: Medium 165 + - Difficulty to test: High (requires TUI testing framework) 166 + 167 + **State management untested:** 168 + - What's not tested: State updates in `global_funcs.ml` 169 + - Risk: State inconsistencies, race conditions 170 + - Priority: Medium 171 + - Difficulty to test: Medium (unit tests for state transitions) 172 + 173 + --- 174 + 175 + *Concerns audit: 2026-01-15* 176 + *Update as issues are fixed or new ones discovered*
+133
.planning/codebase/CONVENTIONS.md
··· 1 + # Coding Conventions 2 + 3 + **Analysis Date:** 2026-01-15 4 + 5 + ## Naming Patterns 6 + 7 + **Files:** 8 + - snake_case for all source files (`commit_render.ml`, `jj_json.ml`, `render_jj_graph.ml`) 9 + - Test files: `*_tests.ml` suffix (`commit_render_tests.ml`, `jj_json_tests.ml`) 10 + - Some camelCase preserved in library names (`ansiReverse.ml`, `outputParsing.ml`) 11 + 12 + **Functions:** 13 + - snake_case for all functions (`render_commit_content`, `graph_node_attr`, `parse_jj_log_output`) 14 + - No special prefix for async functions 15 + - Event handlers: descriptive names (`forward_events`, `handle_input`) 16 + 17 + **Variables:** 18 + - snake_case for variables (`hovered_revision`, `graph_revs`, `active_files`) 19 + - Constants: lowercase with underscores (`pad_amount = 2`) 20 + - Lwd reactive vars: descriptive names without special suffix 21 + 22 + **Types:** 23 + - snake_case for type names (`ui_state_t`, `jj_commit`, `jj_author`, `command_variant`) 24 + - Variant constructors: PascalCase (`Cmd`, `Cmd_r`, `PromptThen`, `Selection_prompt`) 25 + - Record fields: snake_case (`working_copy`, `is_preview`, `change_id`) 26 + 27 + ## Code Style 28 + 29 + **Formatting:** 30 + - OCamlformat with janestreet profile (`.ocamlformat`) 31 + - 2 space indentation 32 + - `let-binding-spacing=double-semicolon` - double semicolon termination 33 + - `space-around-records=true`, `space-around-lists=true`, `space-around-arrays=true` 34 + - `dock-collection-brackets=true` - collections start on new lines 35 + - `break-cases=nested` - match statements on multiple lines 36 + 37 + **Linting:** 38 + - No explicit linting tool configured 39 + - Warnings enabled via dune (`-w A-4-42-44-45-48-66`) 40 + 41 + ## Import Organization 42 + 43 + **Order:** 44 + 1. External packages (Notty, Nottui, Lwd, Base, etc.) 45 + 2. Local library modules (Jj_tui, Util, etc.) 46 + 3. Functor modules (Make(Vars)) 47 + 48 + **Patterns:** 49 + - `open` statements at top of file or module 50 + - Selective opens: `open! Util` (force open even if shadowing) 51 + - Infix operators from Lwd: `open Lwd_infix` 52 + 53 + **Path Aliases:** 54 + - None - uses explicit module paths 55 + 56 + ## Error Handling 57 + 58 + **Patterns:** 59 + - Result types for parsing: `Result.t` with `Ok`/`Error` 60 + - Exceptions for programmer errors: `failwith` with descriptive messages 61 + - Graceful degradation: `Option.value ~default:...` for missing config 62 + 63 + **Error Types:** 64 + - Parsing: Return `Result.t` with `Error (``Msg msg)` 65 + - Runtime: `failwith` for invariant violations 66 + - Unsafe operations: Deliberate `*_exn` suffix (e.g., `key_of_string_exn`) 67 + 68 + ## Logging 69 + 70 + **Framework:** 71 + - `logs` library with custom file reporter (`jj_tui/lib/logging.ml`) 72 + - Levels: debug, info, warn, error 73 + 74 + **Patterns:** 75 + - PPX syntax: `[%log info "message %s" arg]` 76 + - Structured logging with format strings 77 + - File-based logging to platform-specific directories 78 + 79 + ## Comments 80 + 81 + **When to Comment:** 82 + - Module-level documentation: `(** ... *)` with markdown 83 + - Function documentation: Single-line `(** ... *)` before definitions 84 + - Inline explanations: `(* ... *)` for non-obvious logic 85 + - Algorithm explanations: Multi-line doc comments 86 + 87 + **OCamldoc:** 88 + - Used for public APIs and complex functions 89 + - Format: `(** Description *)` before declarations 90 + - Markdown formatting supported in doc comments 91 + 92 + **TODO Comments:** 93 + - Format: `(* TODO: description *)` or inline 94 + - Examples found in: `jj_tui/bin/global_funcs.ml`, `jj_tui/bin/graph_view.ml` 95 + 96 + ## Function Design 97 + 98 + **Size:** 99 + - Generally under 50 lines per function 100 + - Large functions: Graph rendering algorithm (~100+ lines acceptable) 101 + - Extract helpers for complex logic 102 + 103 + **Parameters:** 104 + - Named parameters: `~prefix:string ~rest:string` 105 + - Optional parameters: `?(working_copy = false)` 106 + - Labeled arguments preferred for clarity 107 + 108 + **Return Values:** 109 + - Explicit `Result.t` for operations that can fail 110 + - Option types for nullable values 111 + - Direct values for infallible operations 112 + 113 + ## Module Design 114 + 115 + **Exports:** 116 + - Library modules auto-exported from `lib/` directory 117 + - Explicit module signatures rarely used (prefer `.ml` only) 118 + - Functor pattern: `module Make (Vars : Global_vars.Vars) = struct ... end` 119 + 120 + **Functors:** 121 + - Used extensively for dependency injection 122 + - Pattern: Most major modules parameterized over `Vars` signature 123 + - Examples: `Jj_ui.Make(Vars)`, `Graph_view.Make(Vars)`, `Jj_process.Make(Vars)` 124 + 125 + **Patterns:** 126 + - Double semicolon termination: All top-level let bindings end with `;;` 127 + - PPX deriving: Heavy use of `[@@deriving yojson, yaml, show, eq]` 128 + - Custom operators: Lwd operators in `util.ml` (`<-$`, `$->`, `|>$`, etc.) 129 + 130 + --- 131 + 132 + *Convention analysis: 2026-01-15* 133 + *Update when patterns change*
+94
.planning/codebase/INTEGRATIONS.md
··· 1 + # External Integrations 2 + 3 + **Analysis Date:** 2026-01-15 4 + 5 + ## APIs & External Services 6 + 7 + **Jujutsu VCS (Primary Integration):** 8 + - JJ CLI subprocess execution - `jj_tui/bin/jj_process.ml` 9 + - Integration method: Direct CLI invocation via `Picos_io.Unix` 10 + - Auth: Inherits from user's jj configuration 11 + - Commands: log, commit, rebase, bookmark, squash, split, git operations 12 + - Template system: Custom JJ templates for JSON output (`jj_tui/lib/jj_json.ml`) 13 + 14 + **JSON/YAML Parsing:** 15 + - Yojson - `jj_tui/lib/jj_json.ml` (parses JSONL from `jj log --template`) 16 + - Yaml - `jj_tui/lib/config.ml` (user configuration) 17 + 18 + ## Data Storage 19 + 20 + **Databases:** 21 + - None - Stateless TUI application 22 + 23 + **File Storage:** 24 + - Configuration: `$XDG_CONFIG_HOME/jj_tui/config.yaml` (Linux) or `~/Library/Preferences/jj_tui/` (macOS) 25 + - Logs: `$XDG_STATE_HOME/jj_tui/` (Linux) or `~/Library/Logs/jj_tui/` (macOS) 26 + - Log rotation: Keeps 20 most recent log files (`jj_tui/lib/logging.ml`) 27 + 28 + **Caching:** 29 + - None 30 + 31 + ## Authentication & Identity 32 + 33 + **Auth Provider:** 34 + - None - Relies on JJ CLI authentication 35 + 36 + ## Monitoring & Observability 37 + 38 + **Error Tracking:** 39 + - None 40 + 41 + **Analytics:** 42 + - None 43 + 44 + **Logs:** 45 + - File-based logging via `logs` library - `jj_tui/lib/logging.ml` 46 + - Location: Platform-specific (see File Storage above) 47 + - Format: Timestamped structured logs 48 + - Level: Debug by default 49 + 50 + ## CI/CD & Deployment 51 + 52 + **Hosting:** 53 + - GitHub repository - Source distribution 54 + 55 + **CI Pipeline:** 56 + - GitHub Actions - `.github/workflows/build-nix.yml` 57 + - Multi-platform builds via Nix 58 + - Platforms: x86_64-linux, aarch64-linux, aarch64-darwin, x86_64-darwin 59 + 60 + ## Environment Configuration 61 + 62 + **Development:** 63 + - Required: OCaml 5.2+, Dune 3.12+ 64 + - Optional: Nix for reproducible builds 65 + - JJ CLI must be installed and on PATH 66 + 67 + **Production:** 68 + - JJ CLI required on PATH 69 + - Optional YAML config at standard locations 70 + - No network dependencies 71 + 72 + ## Webhooks & Callbacks 73 + 74 + **Incoming:** 75 + - None 76 + 77 + **Outgoing:** 78 + - None 79 + 80 + ## Forked Dependencies (Customized) 81 + 82 + **Local forks maintained in `forks/`:** 83 + - Nottui - `forks/nottui/` (Picos async integration, custom modifications) 84 + - Notty - `forks/notty/` (Unicode graphics support) 85 + - Lwd - `forks/lwd/` (OCaml 5.2+ compatibility) 86 + 87 + **External forks (pinned):** 88 + - ppx_record_updater - `git+https://github.com/faldor20/ppx_record_updater.git` 89 + - picos - `github:ocaml-multicore/picos` 90 + 91 + --- 92 + 93 + *Integration audit: 2026-01-15* 94 + *Update when adding/removing external services*
+78
.planning/codebase/STACK.md
··· 1 + # Technology Stack 2 + 3 + **Analysis Date:** 2026-01-15 4 + 5 + ## Languages 6 + 7 + **Primary:** 8 + - OCaml 5.2+ - All application code (`dune-project`) 9 + 10 + **Secondary:** 11 + - None 12 + 13 + ## Runtime 14 + 15 + **Environment:** 16 + - OCaml 5.2+ native compilation 17 + - OPAM package manager 18 + 19 + **Package Manager:** 20 + - OPAM (inferred from `.opam` files) 21 + - Lockfile: Not detected 22 + 23 + ## Frameworks 24 + 25 + **Core:** 26 + - Nottui (forked) - TUI framework built on Notty and Lwd (`forks/nottui/dune-project`) 27 + - Notty 0.3.0 (forked) - Declarative terminal rendering library (`forks/notty/dune-project`) 28 + - Lwd (forked) - Lightweight reactive documents for UI (`forks/lwd/dune-project`) 29 + 30 + **Testing:** 31 + - ppx_expect - Inline snapshot testing (`jj_tui/lib/dune`) 32 + 33 + **Build/Dev:** 34 + - Dune 3.12+ - Build system (`dune-project`) 35 + - OCamlformat (janestreet profile) - Code formatting (`.ocamlformat`) 36 + - Nix flakes - Development environment (`flake.nix`) 37 + 38 + ## Key Dependencies 39 + 40 + **Critical:** 41 + - picos 0.5.0+ - Structured concurrency with multicore support (`dune-project`) 42 + - picos_io 0.5.0+ - I/O operations for Picos (`dune-project`) 43 + - yojson - JSON parsing for JJ output (`jj_tui/lib/jj_json.ml`) 44 + - yaml - YAML configuration loading (`jj_tui/lib/config.ml`) 45 + - angstrom - Parser combinators (`jj_tui/lib/dune`) 46 + 47 + **Infrastructure:** 48 + - re - Regular expressions (`jj_tui/lib/dune`) 49 + - logs - Structured logging framework (`jj_tui/lib/logging.ml`) 50 + - signal 0.4.0+ - Signal handling (`forks/nottui/dune-project`) 51 + - base - Jane Street Base library (`jj_tui/lib/dune`) 52 + - stdio - Standard I/O (`jj_tui/lib/dune`) 53 + 54 + ## Configuration 55 + 56 + **Environment:** 57 + - YAML-based user configuration: `$XDG_CONFIG_HOME/jj_tui/config.yaml` (Linux) or `~/Library/Preferences/jj_tui/` (macOS) 58 + - Key bindings: Configurable via YAML (`jj_tui/lib/config.ml`) 59 + 60 + **Build:** 61 + - Dune build system with static linking (`jj_tui/bin/dune`) 62 + - Version generated from git at build time (`jj_tui/bin/dune:34-42`) 63 + - PPX preprocessing for deriving, logging, and testing (`jj_tui/lib/dune`) 64 + 65 + ## Platform Requirements 66 + 67 + **Development:** 68 + - Any platform with OCaml 5.2+ support 69 + - Nix for reproducible builds (`flake.nix`) 70 + 71 + **Production:** 72 + - Distributed as native executable 73 + - Multi-platform static builds: x86_64-linux, aarch64-linux, aarch64-darwin, x86_64-darwin 74 + 75 + --- 76 + 77 + *Stack analysis: 2026-01-15* 78 + *Update after major dependency changes*
+155
.planning/codebase/STRUCTURE.md
··· 1 + # Codebase Structure 2 + 3 + **Analysis Date:** 2026-01-15 4 + 5 + ## Directory Layout 6 + 7 + ``` 8 + jj_tui/ 9 + ├── bin/ # Executable and main UI components 10 + ├── lib/ # Reusable library components 11 + ├── test/ # Test suite 12 + ├── forks/ # Forked dependencies (nottui, notty, lwd) 13 + ├── dune-project # Project metadata 14 + ├── jj_tui.opam # OPAM package manifest 15 + └── README.md # User documentation 16 + ``` 17 + 18 + ## Directory Purposes 19 + 20 + **bin/** 21 + - Purpose: Executable entry point and UI orchestration 22 + - Contains: Main binary, views, commands, process execution 23 + - Key files: 24 + - `main.ml` (88 lines) - Entry point with Picos domain initialization 25 + - `jj_ui.ml` (261 lines) - Main UI functor orchestrating views 26 + - `graph_view.ml` - Commit graph visualization 27 + - `file_view.ml` - File explorer and diff pane 28 + - `show_view.ml` (187 lines) - Details/preview pane 29 + - `jj_commands.ml` (512 lines) - Command execution framework 30 + - `graph_commands.ml` (552 lines) - Graph view command definitions 31 + - `file_commands.ml` - File view command definitions 32 + - `jj_process.ml` (375 lines) - JJ CLI process execution 33 + - `jj_widgets.ml` (213 lines) - JJ-specific widgets 34 + - `global_vars.ml` - Reactive state store (Lwd.var-based) 35 + - `global_funcs.ml` - State manipulation utilities 36 + - Subdirectories: None 37 + 38 + **lib/** 39 + - Purpose: Reusable library components 40 + - Contains: Core logic, parsing, rendering, configuration 41 + - Key files: 42 + - `jj_json.ml` - JJ log output parsing (JSONL) 43 + - `render_jj_graph.ml` (1,117 lines) - Lane-based graph rendering algorithm 44 + - `render_jj_graph_tests.ml` (848 lines) - Golden tests for graph rendering 45 + - `commit_render.ml` - Commit content rendering with syntax highlighting 46 + - `commit_render_tests.ml` (189 lines) - Commit render tests 47 + - `process_wrappers.ml` (336 lines) - JJ output parsing wrappers 48 + - `widgets_citty.ml` - Custom widget implementations 49 + - `config.ml` (54 lines) - YAML config loading 50 + - `key_map.ml` (405 lines) - Keybinding system 51 + - `key.ml` (85 lines) - Key type definitions 52 + - `logging.ml` - Structured logging framework 53 + - `ansiReverse.ml` (337 lines) - ANSI escape code handling 54 + - `ansiReverseTests.ml` (298 lines) - ANSI parsing tests 55 + - `jj_json_tests.ml` (290 lines) - JSON parsing tests 56 + - `process.ml` - Basic process execution interface 57 + - `outputParsing.ml` - JJ output parsing utilities 58 + - `util.ml` (102 lines) - General utilities 59 + - `os.ml` - OS detection 60 + - Subdirectories: 61 + - `key_map/` - Additional key map implementations 62 + - `widgets/` - Archived widget implementations 63 + - `test/` - Library-level test fixtures 64 + 65 + **test/** 66 + - Purpose: Test suite 67 + - Contains: Test files and fixtures 68 + - Key files: 69 + - `lib/ansi.ml` - ANSI integration tests 70 + 71 + **forks/** 72 + - Purpose: Forked dependencies maintained locally 73 + - Contains: nottui, notty, lwd subdirectories 74 + - Subdirectories: 75 + - `nottui/` - Forked TUI framework with Picos integration 76 + - `notty/` - Forked terminal rendering library 77 + - `lwd/` - Forked reactive document framework 78 + 79 + ## Key File Locations 80 + 81 + **Entry Points:** 82 + - `jj_tui/bin/main.ml` - CLI entry point (4 Picos domains, TUI loop) 83 + - `jj_tui/bin/jj_ui.ml` - UI orchestrator 84 + 85 + **Configuration:** 86 + - `.ocamlformat` - OCamlformat config (janestreet profile) 87 + - `dune-project` - Dune project metadata 88 + - `jj_tui/lib/dune` - Library build configuration 89 + - `jj_tui/bin/dune` - Executable build configuration 90 + 91 + **Core Logic:** 92 + - `jj_tui/lib/render_jj_graph.ml` - Graph rendering algorithm (1,117 lines) 93 + - `jj_tui/bin/jj_commands.ml` - Command execution framework (512 lines) 94 + - `jj_tui/bin/graph_commands.ml` - Graph commands (552 lines) 95 + - `jj_tui/bin/jj_process.ml` - Process execution (375 lines) 96 + 97 + **Testing:** 98 + - `jj_tui/lib/*_tests.ml` - Inline ppx_expect tests 99 + - `jj_tui/test/lib/` - Separate test library 100 + 101 + **Documentation:** 102 + - `README.md` - User-facing documentation 103 + - `design.md` - Implementation notes 104 + 105 + ## Naming Conventions 106 + 107 + **Files:** 108 + - snake_case for all files (e.g., `graph_view.ml`, `jj_widgets.ml`, `commit_render.ml`) 109 + - Test files: `*_tests.ml` suffix (e.g., `jj_json_tests.ml`, `render_jj_graph_tests.ml`) 110 + 111 + **Directories:** 112 + - snake_case for all directories 113 + - Plural names for collections: `forks/`, `test/`, `widgets/` 114 + 115 + **Special Patterns:** 116 + - `*.ml` - OCaml implementation files 117 + - `*.mli` - OCaml interface files (rarely used in this project) 118 + - `dune` - Build configuration files in each directory 119 + 120 + ## Where to Add New Code 121 + 122 + **New View:** 123 + - Primary code: `jj_tui/bin/{name}_view.ml` 124 + - Commands: `jj_tui/bin/{name}_commands.ml` 125 + - Register in: `jj_tui/bin/jj_ui.ml` 126 + 127 + **New Widget:** 128 + - Implementation: `jj_tui/lib/widgets_citty.ml` 129 + - JJ-specific: `jj_tui/bin/jj_widgets.ml` 130 + - Tests: Co-located `*_tests.ml` file 131 + 132 + **New Parsing Logic:** 133 + - Implementation: `jj_tui/lib/{name}.ml` 134 + - Tests: `jj_tui/lib/{name}_tests.ml` with ppx_expect 135 + 136 + **Utilities:** 137 + - Shared helpers: `jj_tui/lib/util.ml` 138 + - Lwd operators: `jj_tui/lib/util.ml` 139 + 140 + ## Special Directories 141 + 142 + **forks/** 143 + - Purpose: Local forks of dependencies with custom patches 144 + - Source: Git submodules or vendored code 145 + - Committed: Yes (source of truth) 146 + 147 + **test/** 148 + - Purpose: Test suite separate from inline tests 149 + - Source: Hand-written test cases 150 + - Committed: Yes 151 + 152 + --- 153 + 154 + *Structure analysis: 2026-01-15* 155 + *Update when directory structure changes*
+230
.planning/codebase/TESTING.md
··· 1 + # Testing Patterns 2 + 3 + **Analysis Date:** 2026-01-15 4 + 5 + ## Test Framework 6 + 7 + **Runner:** 8 + - ppx_expect - OCaml inline snapshot testing 9 + - Config: `(inline_tests)` in `jj_tui/lib/dune` 10 + 11 + **Assertion Library:** 12 + - ppx_expect built-in: `[%expect {| ... |}]` blocks 13 + - Custom test helpers for rendering 14 + 15 + **Run Commands:** 16 + ```bash 17 + dune test # Run all tests 18 + dune runtest # Run tests (alias) 19 + dune test jj_tui/lib # Run library tests only 20 + dune promote # Accept test output changes 21 + ``` 22 + 23 + ## Test File Organization 24 + 25 + **Location:** 26 + - Co-located with source: `jj_tui/lib/*_tests.ml` 27 + - Separate test directory: `jj_tui/test/lib/` 28 + 29 + **Naming:** 30 + - Pattern: `{module}_tests.ml` (e.g., `jj_json_tests.ml`, `commit_render_tests.ml`) 31 + - Integration tests: `jj_tui/test/lib/ansi.ml` 32 + 33 + **Structure:** 34 + ``` 35 + jj_tui/lib/ 36 + commit_render.ml 37 + commit_render_tests.ml # Co-located tests 38 + jj_json.ml 39 + jj_json_tests.ml # Co-located tests (290 lines) 40 + render_jj_graph.ml 41 + render_jj_graph_tests.ml # Golden tests (848 lines) 42 + ansiReverse.ml 43 + ansiReverseTests.ml # Co-located tests (298 lines) 44 + ``` 45 + 46 + ## Test Structure 47 + 48 + **Suite Organization:** 49 + ```ocaml 50 + let%expect_test "test_name" = 51 + (* Arrange *) 52 + let node = make_test_node ... in 53 + 54 + (* Act *) 55 + let result = render_commit_content node in 56 + 57 + (* Assert *) 58 + render_and_print result; 59 + [%expect {| 60 + Expected output here 61 + |}] 62 + ;; 63 + ``` 64 + 65 + **Patterns:** 66 + - `let%expect_test` for each test case 67 + - Helper functions for test data creation 68 + - Direct output comparison via expect blocks 69 + - Golden tests for graph rendering (exact glyph output) 70 + 71 + ## Mocking 72 + 73 + **Framework:** 74 + - No explicit mocking library 75 + - Test data created via helper functions 76 + 77 + **Patterns:** 78 + ```ocaml 79 + (* Factory pattern for test data *) 80 + let make_test_node 81 + ?(working_copy = false) 82 + ?(immutable = false) 83 + () 84 + = { 85 + commit_id = "test123"; 86 + working_copy; 87 + immutable; 88 + ... 89 + } 90 + ``` 91 + 92 + **What to Mock:** 93 + - JJ output: Create sample JSON/JSONL strings 94 + - ANSI sequences: Hand-crafted escape code strings 95 + - UI state: Construct test state records 96 + 97 + **What NOT to Mock:** 98 + - Rendering functions: Test actual Notty output 99 + - Parsing logic: Test real angstrom parsers 100 + - Pure functions: Test directly 101 + 102 + ## Fixtures and Factories 103 + 104 + **Test Data:** 105 + ```ocaml 106 + (* Factory functions in test files *) 107 + let make_test_commit ?(id = "abc123") () = 108 + { 109 + commit_id = id; 110 + parents = []; 111 + change_id = "xyz789"; 112 + description = "Test commit"; 113 + ... 114 + } 115 + 116 + (* Example from jj_json_tests.ml *) 117 + let sample_jsonl = {| 118 + {"commit_id":"abc123","parents":[]} 119 + {"commit_id":"def456","parents":["abc123"]} 120 + |} 121 + ``` 122 + 123 + **Location:** 124 + - Factory functions: Defined in test files near usage 125 + - Shared fixtures: Inline strings in test files 126 + - Test data: `jj_tui/test/` directory 127 + 128 + ## Coverage 129 + 130 + **Requirements:** 131 + - No enforced coverage target 132 + - Coverage tracked for awareness 133 + - Focus on critical paths: parsing, rendering, graph algorithm 134 + 135 + **Configuration:** 136 + - No coverage tool configured in dune 137 + - Manual coverage via test count 138 + 139 + **View Coverage:** 140 + - Not available - no coverage tool integration 141 + 142 + ## Test Types 143 + 144 + **Unit Tests:** 145 + - Scope: Single function/module in isolation 146 + - Examples: `jj_json_tests.ml` (JSON parsing), `key.ml` tests 147 + - Speed: Fast (< 1s per test file) 148 + 149 + **Golden Tests:** 150 + - Scope: Exact output verification for graph rendering 151 + - Examples: `render_jj_graph_tests.ml` (848 lines) 152 + - Philosophy: "Prefer updating algorithm to match golden outputs" 153 + - Use: Regression detection for complex visual output 154 + 155 + **Integration Tests:** 156 + - Scope: Multiple modules together 157 + - Examples: `jj_tui/test/lib/ansi.ml` (ANSI parsing + rendering) 158 + - Setup: Real JJ output strings 159 + 160 + ## Common Patterns 161 + 162 + **Expect Test Pattern:** 163 + ```ocaml 164 + let%expect_test "parse_valid_jsonl" = 165 + let input = {|{"commit_id":"abc123"}|} in 166 + (match parse_jj_log_output input with 167 + | Ok commits -> 168 + Printf.printf "Parsed %d commits\n" (List.length commits) 169 + | Error msg -> 170 + Printf.printf "Error: %s\n" msg); 171 + [%expect {| 172 + Parsed 1 commits 173 + |}] 174 + ;; 175 + ``` 176 + 177 + **Error Testing:** 178 + ```ocaml 179 + let%expect_test "parse_invalid_json" = 180 + let input = {|invalid json|} in 181 + (match parse_jj_log_output input with 182 + | Ok _ -> print_endline "Unexpected success" 183 + | Error msg -> Printf.printf "Error: %s\n" msg); 184 + [%expect {| 185 + Error: JSON parse failed 186 + |}] 187 + ;; 188 + ``` 189 + 190 + **Rendering Test Pattern:** 191 + ```ocaml 192 + (* Helper to convert Notty images to strings *) 193 + let image_to_string img = 194 + let buf = Buffer.create 256 in 195 + let w, h = Notty.I.(width img, height img) in 196 + Notty.Render.to_buffer buf Notty.Cap.dumb (0, 0) (w, h) img; 197 + Buffer.contents buf 198 + ;; 199 + 200 + let%expect_test "render_commit" = 201 + let node = make_test_node () in 202 + let img = render_commit_content node in 203 + print_endline (image_to_string img); 204 + [%expect {| ... |}] 205 + ;; 206 + ``` 207 + 208 + **Snapshot Testing:** 209 + - All tests use expect blocks as snapshots 210 + - Workflow: Run tests, review diffs, `dune promote` to accept changes 211 + 212 + ## Test Coverage Summary 213 + 214 + **Well-tested modules:** 215 + - `jj_json.ml` - 290 lines of tests, 45 test cases 216 + - `render_jj_graph.ml` - 848 lines of golden tests 217 + - `ansiReverse.ml` - 298 lines of ANSI parsing tests 218 + - `commit_render.ml` - 189 lines of rendering tests 219 + 220 + **Untested modules:** 221 + - `jj_commands.ml` - No tests for command execution 222 + - `graph_commands.ml` - No tests for command definitions 223 + - `jj_process.ml` - No tests for process execution 224 + - `jj_ui.ml` - No tests for UI orchestration 225 + - `global_funcs.ml` - No tests for state updates 226 + 227 + --- 228 + 229 + *Testing analysis: 2026-01-15* 230 + *Update when test patterns change*
+26
.planning/config.json
··· 1 + { 2 + "mode": "yolo", 3 + "depth": "standard", 4 + "parallelization": { 5 + "enabled": true, 6 + "plan_level": true, 7 + "task_level": false, 8 + "skip_checkpoints": true, 9 + "max_concurrent_agents": 3, 10 + "min_plans_for_parallel": 2 11 + }, 12 + "gates": { 13 + "confirm_project": false, 14 + "confirm_phases": false, 15 + "confirm_roadmap": false, 16 + "confirm_breakdown": false, 17 + "confirm_plan": false, 18 + "execute_next_plan": false, 19 + "issues_review": true, 20 + "confirm_transition": false 21 + }, 22 + "safety": { 23 + "always_confirm_destructive": true, 24 + "always_confirm_external_services": true 25 + } 26 + }
-119
CHANGES_SUMMARY.md
··· 1 - # Changes to Match Original JJ Rendering Format 2 - 3 - ## Goal 4 - Match the original `jj log` output format which displays commit information on two lines: 5 - 6 - **Original jj format:** 7 - ``` 8 - @ ztooztwk eli.jambu@gmail.com 2026-01-15 14:05:59 235795c5 9 - │ (empty) (no description set) 10 - ``` 11 - 12 - ## Changes Made 13 - 14 - ### 1. Updated `render_commit_content` in `graph_view.ml` (lines 19-79) 15 - 16 - **Previous format (single line):** 17 - ``` 18 - change_id author_name timestamp (bookmarks) description 19 - ``` 20 - 21 - **New format (two lines):** 22 - ``` 23 - Line 1: change_id email timestamp [bookmarks] commit_id_short 24 - Line 2: (empty) description 25 - ``` 26 - 27 - **Key changes:** 28 - - Show **full email** instead of extracting name before `@` 29 - - Add **commit_id_short** (8 characters) at end of line 1 30 - - Move **description** to line 2 31 - - Add **(empty)** prefix when `node.empty` is true 32 - - Remove parentheses around bookmarks, show as space-separated list 33 - - Use `I.vcat` to create two-line image 34 - 35 - ### 2. Updated `render_graph_row` in `graph_view.ml` (lines 81-109) 36 - 37 - **Problem:** When content is multi-line, the graph character only appears on the first line with `I.hcat [ graph_img; content_img ]`. 38 - 39 - **Solution:** Detect multi-line content and manually create graph continuation for subsequent lines: 40 - 41 - ```ocaml 42 - if content_height > 1 then 43 - (* Replace node glyphs (○, @, ◌, ◆) with vertical bar │ *) 44 - let graph_continuation = replace_node_glyphs_with_bar row.graph_chars in 45 - (* Create each line with appropriate graph prefix *) 46 - let lines = List.init content_height (fun i -> 47 - let line_img = I.vcrop i 1 content_img in 48 - if i = 0 then I.hcat [ graph_img; line_img ] 49 - else I.hcat [ graph_continuation; line_img ] 50 - ) in 51 - I.vcat lines 52 - else 53 - I.hcat [ graph_img; content_img ] 54 - ``` 55 - 56 - **How it works:** 57 - 1. Check if content height > 1 58 - 2. Create `graph_continuation` by replacing all node glyphs with `│` 59 - 3. For each line: 60 - - Line 0: Use original `graph_chars` (contains node glyph) 61 - - Line 1+: Use `graph_continuation` (node glyph replaced with `│`) 62 - 4. Vertically stack all lines 63 - 64 - ### 3. Color Scheme 65 - 66 - **Line 1:** 67 - - `change_id`: cyan (bold cyan if working_copy, yellow if empty, lightmagenta if immutable) 68 - - `email`: dim white 69 - - `timestamp`: dim white 70 - - `bookmarks`: bold green 71 - - `commit_id_short`: dim cyan 72 - 73 - **Line 2:** 74 - - `description`: white (dim if empty/preview, lightyellow if wip) 75 - 76 - ## Examples 77 - 78 - ### Simple commit (empty) 79 - ``` 80 - @ ztooztwk eli.jambu@gmail.com 2026-01-15 14:05:59 235795c5 81 - │ (empty) (no description set) 82 - ``` 83 - 84 - ### Commit with description 85 - ``` 86 - ○ smqmznlq eli.jambu@gmail.com 2026-01-15 01:40:23 09a9f33f 87 - │ Add new feature 88 - ``` 89 - 90 - ### Commit with bookmarks 91 - ``` 92 - ◆ noszsqtm eli.jambu@gmail.com 2025-11-22 00:26:06 main master 35b532af 93 - │ remove aarch64 linux because it doesn't seem to work 94 - ``` 95 - 96 - ### Complex graph 97 - ``` 98 - │ ○ nkwwwlnw eli.jambu@gmail.com 2026-01-15 00:30:16 89abd641 99 - │ │ rewrite 100 - ``` 101 - 102 - ## Testing 103 - 104 - - ✅ `dune build` - compiles successfully 105 - - ✅ `dune runtest` - all existing tests pass 106 - - ✅ Multi-line rendering works correctly 107 - - ✅ Graph continuation characters display properly 108 - 109 - ## Files Modified 110 - 111 - 1. **`jj_tui/bin/graph_view.ml`** 112 - - `render_commit_content` (lines 19-79): Two-line format 113 - - `render_graph_row` (lines 81-109): Multi-line graph handling 114 - 115 - ## No Breaking Changes 116 - 117 - - All existing functionality preserved 118 - - Tests pass without modification 119 - - Only visual formatting changed
+233
docs/jj_rebase.md
··· 1 + See the sections below for details about the different ways of 2 + specifying 3 + which revisions to rebase where. 4 + 5 + If a working-copy revision gets abandoned, it will be given a new, 6 + empty 7 + revision. This is true in general; it is not specific to this 8 + command. 9 + 10 + ### Specifying which revisions to rebase 11 + 12 + With `--source/-s`, the command rebases the specified revision and 13 + its 14 + descendants to the destination. For example, `jj rebase -s M -o O` 15 + would 16 + transform your history like this (letters followed by an 17 + apostrophe are 18 + post-rebase versions): 19 + 20 + ```text 21 + O N' 22 + | | 23 + | N M' 24 + | | | 25 + | M O 26 + | | => | 27 + | | L | L 28 + | |/ | | 29 + | K | K 30 + |/ |/ 31 + J J 32 + ``` 33 + 34 + Each revision passed to `-s` will become a direct child of the 35 + destination, 36 + so if you instead run `jj rebase -s M -s N -o O` (or `jj rebase -s 37 + 'M|N' -o 38 + O`) in the example above, then N' would instead be a direct child 39 + of O. 40 + 41 + With `--branch/-b`, the command rebases the whole "branch" 42 + containing the 43 + specified revision. A "branch" is the set of revisions that 44 + includes: 45 + 46 + * the specified revision and ancestors that are not also ancestors 47 + of the 48 + destination 49 + * all descendants of those revisions 50 + 51 + In other words, `jj rebase -b X -o Y` rebases revisions in the 52 + revset 53 + `(Y..X)::` (which is equivalent to `jj rebase -s 'roots(Y..X)' -o 54 + Y` for a 55 + single root). For example, either `jj rebase -b L -o O` or `jj 56 + rebase -b M 57 + -o O` would transform your history like this (because `L` and `M` 58 + are on the 59 + same "branch", relative to the destination): 60 + 61 + ```text 62 + O N' 63 + | | 64 + | N M' 65 + | | | 66 + | M | L' 67 + | | => |/ 68 + | | L K' 69 + | |/ | 70 + | K O 71 + |/ | 72 + J J 73 + ``` 74 + 75 + With `--revisions/-r`, the command rebases only the specified 76 + revisions to 77 + the destination. Any "hole" left behind will be filled by rebasing 78 + descendants onto the specified revisions' parent(s). For example, 79 + `jj rebase -r K -o M` would transform your history like this: 80 + 81 + ```text 82 + M K' 83 + | | 84 + | L M 85 + | | => | 86 + | K | L' 87 + |/ |/ 88 + J J 89 + ``` 90 + 91 + Multiple revisions can be specified, and any dependencies (graph 92 + edges) 93 + within the set will be preserved. For example, `jj rebase -r 'K|N' 94 + -o O` 95 + would transform your history like this: 96 + 97 + ```text 98 + O N' 99 + | | 100 + | N K' 101 + | | | 102 + | M O 103 + | | => | 104 + | | L | M' 105 + | |/ |/ 106 + | K | L' 107 + |/ |/ 108 + J J 109 + ``` 110 + 111 + `jj rebase -s X` is similar to `jj rebase -r X::` and will behave 112 + the same 113 + if X is a single revision. However, if X is a set of multiple 114 + revisions, 115 + or if you passed multiple `-s` arguments, then `jj rebase -s` will 116 + make each 117 + of the specified revisions an immediate child of the destination, 118 + while 119 + `jj rebase -r` will preserve dependencies within the set. 120 + 121 + Note that you can create a merge revision by repeating the `-o` 122 + argument. 123 + For example, if you realize that revision L actually depends on 124 + revision M 125 + in order to work (in addition to its current parent K), you can 126 + run `jj 127 + rebase -s L -o K -o M`: 128 + 129 + ```text 130 + M L' 131 + | |\ 132 + | L M | 133 + | | => | | 134 + | K | K 135 + |/ |/ 136 + J J 137 + ``` 138 + 139 + ### Specifying where to rebase the revisions 140 + 141 + With `--onto/-o`, the command rebases the selected revisions onto 142 + the 143 + targets. Existing descendants of the targets will not be affected. 144 + See 145 + the section above for examples. 146 + 147 + With `--insert-after/-A`, the selected revisions will be inserted 148 + after the 149 + targets. This is similar to `-o`, but if the targets have any 150 + existing 151 + descendants, then those will be rebased onto the rebased selected 152 + revisions. 153 + 154 + For example, `jj rebase -r K -A L` will rewrite history like this: 155 + ```text 156 + N N' 157 + | | 158 + | M | M' 159 + |/ |/ 160 + L => K' 161 + | | 162 + | K L 163 + |/ | 164 + J J 165 + ``` 166 + 167 + The `-A` (and `-B`) argument can also be used for reordering 168 + revisions. For 169 + example, `jj rebase -r M -A J` will rewrite history like this: 170 + ```text 171 + M L' 172 + | | 173 + L K' 174 + | => | 175 + K M' 176 + | | 177 + J J 178 + ``` 179 + 180 + With `--insert-before/-B`, the selected revisions will be inserted 181 + before 182 + the targets. This is achieved by rebasing the selected revisions 183 + onto the 184 + target revisions' parents, and then rebasing the target revisions 185 + and their 186 + descendants onto the rebased revisions. 187 + 188 + For example, `jj rebase -r K -B L` will rewrite history like this: 189 + ```text 190 + N N' 191 + | | 192 + | M | M' 193 + |/ |/ 194 + L => L' 195 + | | 196 + | K K' 197 + |/ | 198 + J J 199 + ``` 200 + 201 + The `-A` and `-B` arguments can also be combined, which can be 202 + useful around 203 + merges. For example, you can use `jj rebase -r K -A J -B M` to 204 + create a new 205 + merge (but `jj rebase -r M -o L -o K` might be simpler in this 206 + particular 207 + case): 208 + ```text 209 + M M' 210 + | |\ 211 + L L | 212 + | => | | 213 + | K | K' 214 + |/ |/ 215 + J J 216 + ``` 217 + 218 + To insert a commit inside an existing merge with `jj rebase -r O 219 + -A K -B M`: 220 + ```text 221 + O N' 222 + | |\ 223 + N | M' 224 + |\ | |\ 225 + | M | O'| 226 + | | => |/ / 227 + | L | L 228 + | | | | 229 + K | K | 230 + |/ |/ 231 + J J 232 + ``` 233 +