CLIState | cli_providers/states.py | State enum (idle, running, needs_permission, needs_input, interrupted) |
CLIProvider | cli_providers/base.py | Abstract base for CLI backends (patterns, hooks, input) |
ClaudeProvider | cli_providers/claude.py | Claude Code CLI (Ink TUI, numbered menus, Notification + PermissionRequest hooks) |
CodexProvider | cli_providers/codex.py | OpenAI Codex CLI (Ratatui TUI, y/n approval, Stop hook only) |
CursorAgentProvider | cli_providers/cursor_agent.py | Cursor Agent CLI (Ink TUI, menu approval, Stop hook only) |
GeminiProvider | cli_providers/gemini.py | Gemini CLI (Ink TUI, radio-button approval, AfterAgent/Notification hooks) |
get_provider() | cli_providers/registry.py | Provider lookup by name ('claude', 'codex', 'cursor-agent', 'gemini') |
LeapServer | server/server.py | Orchestrates PTY, socket, queue, metadata |
LeapClient | client/client.py | Interactive client with image support |
SocketClient | client/socket_client.py | Client-side socket communication (shared _send_request) |
MonitorWindow | monitor/app.py | PyQt5 GUI core window (uses mixins for methods) |
ServerLauncher | monitor/server_launcher.py | PR server clone/force-align/start flow (gates dirty managed clones on a 3-way dialog: Clone-into-next / Discard / Cancel) |
_dirty_files() | monitor/server_launcher.py | Returns the list of local files a force-align would discard (git status --porcelain); None on scan failure so the consent gate stays armed |
_commits_ahead_of_origin() | monitor/server_launcher.py | Counts commits on HEAD not in origin/<branch> (git rev-list --count origin/<branch>..HEAD); None on scan failure |
_detached_head_sha() | monitor/server_launcher.py | Returns the short SHA if HEAD is detached, else None — surfaced in the dialog so commit-URL re-opens don't read as "you have N new commits" |
_dir_index() | monitor/server_launcher.py | Numeric suffix of a managed-clone dir name (<name> → 0, <name>_1 → 1, …) — drives the "next slot" logic |
GitLabProvider | monitor/pr_tracking/gitlab_provider.py | GitLab PR thread tracking + user notifications |
GitHubProvider | monitor/pr_tracking/github_provider.py | GitHub PR thread tracking + user notifications |
ActionsMenuMixin | monitor/_mixins/actions_menu_mixin.py | Git menu + Path menu (Open in Terminal / Open in IDE / Move session to IDE) |
detect_supported_ide_for_move() | monitor/navigation.py | Classify a .app for Move-to-IDE: a canonical JetBrains key / 'VS Code' / 'Cursor' (VS Code fork, driven via the cursor CLI through _open_vscode_terminal) / None |
GitChangesDialog | monitor/dialogs/git_changes_dialog.py | Git diff viewer (local, commit, vs main) |
CommitListDialog | monitor/dialogs/git_changes_dialog.py | Commit picker for diff comparison (More-info button lazy-fetches full body) |
WhatsNewDialog | monitor/dialogs/whats_new_dialog.py | Read-only commit viewer for HEAD..origin/main, launched from update banner |
BranchPickerDialog | monitor/dialogs/branch_picker_dialog.py | Branch picker for difftool comparison |
QueueEditDialog | monitor/dialogs/queue_edit_dialog.py | View/edit queued messages for a session |
NotesDialog | monitor/dialogs/notes_dialog.py | Notes with folders, search, text/checklist, DnD reorder, save as preset, run in session |
ImageTextEdit | monitor/ui/image_text_edit.py | QTextEdit with clipboard image paste → [Image #N] placeholders |
SendMessageDialog | monitor/ui/image_text_edit.py | Message dialog with image paste + Next/To-End queue-position toggle |
SendPresetDialog | monitor/ui/image_text_edit.py | Picker for a message-bundle preset + Next/To-End queue-position toggle |
SendCommentsDialog | monitor/dialogs/send_comments_dialog.py | PR-comments picker (filter / mode / context preset) |
ResumeSessionDialog | monitor/dialogs/resume_session_dialog.py | GUI leap --resume picker — returns (cli, tag, SessionRecord) |
_TagSessionPicker | monitor/dialogs/resume_session_dialog.py | Sub-dialog for tags with >1 recorded session |
SCMSetupDialog | monitor/dialogs/scm_setup_dialog.py | Abstract base: Save / Connect-Disconnect / Cancel actions |
ColorPickerPopup | monitor/ui/table_helpers.py | Row color picker popup (grid of swatches + clear) |
COLUMNS / ColumnSpec | monitor/columns.py | Single source of truth for session-table layout; MonitorWindow.COL_*, _HEADER_LABELS, _CENTER_COLS/_MONO_COLS, and COLUMN_GROUPS all derive from it |
DockBadge | monitor/ui/dock_badge.py | Dock icon badge overlay + notification event detection |
Theme / current_theme() | monitor/themes.py | Theme dataclass + manager API (9 built-in themes) |
ensure_contrast() | monitor/themes.py | WCAG contrast safety-net (returns black/white if ratio < 4.5:1) |
SleepGuard | monitor/sleep_guard.py | Holds caffeinate -i -w <monitor-pid> child while any session is RUNNING |
LidCloseGuard | monitor/sleep_guard.py | Optional companion to SleepGuard — also runs sudo pmset -a disablesleep 1/0 |
SudoManager | monitor/sudo_manager.py | Saved sudo password helpers (.storage/sudo_pass.b64, base64 mode 0600) |
SlackBot | slack/bot.py | Main Slack bot (Socket Mode + event handlers) |
OutputCapture | slack/output_capture.py | Read hook response from signal file, write .last_response |
LineBuffer | utils/line_buffer.py | Cursor-aware line editing buffer (insert, delete, move, home/end, delete-word) |
extract_menu_options() | utils/menu.py | Numbered-menu parser shared by server auto-approve and monitor permission menu |
relocation.py primitives | utils/relocation.py | Shared cross-cwd move primitives (signals_blocked, stage/commit, verify, snapshot) |
relocate_claude_session() | utils/claude_session_move.py | Claude transcript move (jsonl + optional sidecar dir) |
relocate_gemini_session() | utils/gemini_session_move.py | Gemini transcript move (jsonl + projects.json registry) |
relocate_cursor_session() | utils/cursor_session_move.py | Cursor chat-dir move; also exposes find_chat_dir() for session_exists |
relocate_records() | utils/resume_store.py | Rewrites transcript paths in cli_sessions/<cli>/*.json after a cross-cwd move |
CLIProvider.requires_cwd_bound_resume | cli_providers/base.py | True for Claude/Gemini/Cursor (cwd-derived storage); False for Codex |
CLIProvider.session_exists() | cli_providers/base.py | Existence check for the picker (default: transcript_path; Cursor scans chat dir) |
CLIProvider.relocate_session() | cli_providers/base.py | Optional hook — implemented by Claude/Gemini/Cursor; Codex inherits None |
CLIProvider.hooks_installed() | cli_providers/base.py | Whether Leap's hooks are wired up; gate-checked at session start; must never raise |
CLIProvider.input_history() | cli_providers/base.py | Returns the CLI's persisted ↑-recall history for cwd, ordered oldest→newest; None opts out → passthrough |
_handle_history_recall() | server/server.py | Drives ↑/↓ recall: reads provider history, clears CLI input, injects recalled text, keeps mirror in sync |
CLIProvider.base_type | cli_providers/base.py | Built-in CLI this provider is a variant of; custom providers inherit via __getattribute__ |
atomic_write_json() | utils/atomic_write.py | Write JSON to a temp file in the same dir, fsync, atomic rename |
_enforce_hooks_installed_or_exit() | server/server.py | Session-start gate — exits with code 1 if hooks_installed() returns False |
_resolve_cli_flags() | server/pty_handler.py | Merge stored/env-var default flags with explicit CLI flags |
send_socket_request() | utils/socket_utils.py | Shared Unix socket send/recv utility |
resolve_scm_token() | monitor/pr_tracking/config.py | Resolve token from config (supports env var mode) |
normalize_github_api_url() | monitor/pr_tracking/config.py | Canonicalize a GitHub base URL (GitHub Enterprise → /api/v3; github.com/api.github.com → default). Applied in-memory on load_github_config (no write-back — runs on poll-worker threads) and persisted on save_github_config |
find_latest_closed_pr() | monitor/pr_tracking/base.py | Most-recent closed/merged PR for a branch (ClosedPRInfo); powers the Track-PR "no open PR found" fallback's "Open in Browser" button. Default returns None; GitLab/GitHub override |
parse_pr_url() | monitor/pr_tracking/git_utils.py | Parse GitLab/GitHub PR URLs |
send_to_leap_session() | monitor/leap_sender.py | Send message to Leap session (prepends PR context) |
scan_open_cursor_agents() | monitor/cursor_gui_scan.py | Read-only scan of Cursor editor Agent tabs (workspace.json + workspace/global state.vscdb) -> one synthetic row_type='cursor_agent_gui' row per open tab (status from generatingBubbleIds/hasUnreadMessages/status) |
focus_cursor_window() | monitor/navigation.py | "Jump": raise the Cursor window matching a folder via the System Events AX bridge, then (if a composer_id is given) write focusComposer:<id> to ~/.leap-terminal-request (via _write_terminal_request, atomic temp+os.replace) for the Leap Cursor extension to focus that exact Agent tab |
_write_terminal_request() | monitor/navigation.py | Atomic (temp file + os.replace) write of a request line to ~/.leap-terminal-request. Atomicity matters: the extension reads with a plain readFileSync on an fs.watch + 500 ms poll, so a non-atomic truncate-then-write could be read half-formed - missing the focusComposer:/closeComposer: prefix, falling through to the extension's catch-all "select terminal by name", and getting unlink-ed (silently dropping the request). Used by focus_cursor_window/close_cursor_composer |
_build_cursor_gui_row() | monitor/_mixins/table_builder_mixin.py | Renders a Cursor-GUI overlay row (all columns painted explicitly; alias-aware Tag cell; QUEUE = mono dimmed "N/A"; CLI badge "Cursor Editor"; Server cell = close-"×" + "Open" jump, mirroring a running row's `[× |
_reconcile_cursor_gui_rows() | monitor/_mixins/table_builder_mixin.py | Sets _cursor_gui_rows from a fresh scan + synthesizes a _tab_closed row (from _cursor_row_cache) for each tracked Cursor tag whose tab is gone, so a PR-tracked tab survives being closed (like a dead-but-tracked regular row); prunes per-tag PR state + the row cache for tags no longer shown/tracked. Pure transform, unit-tested |
configure_hooks.py | scripts/configure_hooks.py | Unified hook config (iterates providers, calls provider.configure_hooks()) |