Skip to content

Add terminal timestamps - #3955

Closed
austinywang wants to merge 39 commits into
mainfrom
issue-3690-terminal-timestamps
Closed

austinywang wants to merge 39 commits into
mainfrom
issue-3690-terminal-timestamps

Conversation

@austinywang

@austinywang austinywang commented May 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • add a toggleable terminal timestamp gutter aligned with terminal output rows
  • wire the setting through Settings, View menu, command palette, keyboard shortcuts, and cmux.json
  • document terminal.showTimestamps and add runtime coverage for timestamp row policy

Closes #3690

Validation

  • jq empty Resources/Localizable.xcstrings web/data/cmux.schema.json
  • git diff --check
  • local test suites not run per project policy; CI will run via PR checks

Note

Medium Risk
Medium risk because it introduces new CircleCI workflows plus a pull_request_target GitHub Action that can approve CI holds based on org/user trust, which impacts CI security posture and execution gating.

Overview
Adds a full .circleci/config.yml with macOS unit-test, debug-build (warning budget), and release universal-build jobs, including SwiftPM/Zig caching and a gated workflow that requires an explicit hold step before running on PRs/tags.

Introduces a pull_request_target GitHub Action (circleci-auto-approve.yml) that runs scripts/circleci_auto_approve.py to automatically approve the CircleCI hold for PRs from trusted org members/users.

Tightens Greptile “no hacky sleeps” rule scoping to repo web/ and scripts/ paths and updates the rule text accordingly; also simplifies the perf activation workflow by removing explicit SwiftPM caching/resolution steps.

Removes the antigravity agent launch sanitization policy and its tests, and deletes related Agent icon assets (including Grok/Antigravity image sets).

Reviewed by Cursor Bugbot for commit 9c1a74e. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Adds an optional left-side timestamp gutter aligned with terminal output rows. Toggle via Settings, View menu, Command Palette, ⌥⌘⇧E, or cmux.json (terminal.showTimestamps, default off). Closes #3690.

  • New Features

    • Timestamp gutter aligned to rows; scales with cell height, has an accessibility label, click focuses terminal, and stays aligned during live, keyboard, and search-driven scroll.
    • TerminalTimestampStore stamps new/visible rows, skips backfill on keyboard-initiated backscroll, prunes to 20k, retains visible rows across viewport changes and after scrollback rebase/shrink, and updates on scroll/setting changes. Settings search, View menu toggle, Command Palette action, shortcut, docs, tests, and localizations added.
  • Bug Fixes

    • Scrollbar sync: added ghostty.scrollbarUpdateIntent and ghostty.scrollbarWasKeyboardInitiated (via GhosttyScrollbarUpdateIntent) to carry intent, explicitly sync viewport during search navigation, coalesce intent across callbacks, and limit keyboard intent to viewport motions.
    • Stability/perf: clamped scrollbar values, bounded prune/growth, avoided prune hot-path copies, and cached gutter draw style.

Written for commit 9c1a74e. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • Per-row terminal timestamp gutter with a toggleable "Show Terminal Timestamps" preference; accessible in Settings, Command Palette, and View menu
    • Default keyboard shortcut: ⌥⌘⇧E
  • Settings

    • Preference persists, configurable via config files/schema, searchable in Settings, and restored by reset
  • Localization

    • English and Japanese UI, menu, shortcut, search, and accessibility strings added
  • Tests & Docs

    • Unit tests added; docs/config sample updated

Review Change Stack

@vercel

vercel Bot commented May 12, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment May 22, 2026 9:14pm
cmux-staging Building Building Preview, Comment May 22, 2026 9:14pm

@coderabbitai

coderabbitai Bot commented May 12, 2026 •

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a toggleable terminal timestamp gutter: data store, runtime setting with persistence/managed-file support, keyboard shortcut and command wiring, gutter UI integrated into the terminal scroll view, Settings/View menu toggles, localization/schema updates, and tests.

Changes

Terminal Timestamps Feature

Layer / File(s) Summary
Timestamp store and tests
Sources/TerminalTimestampStore.swift, cmuxTests/GhosttyTerminalViewVisibilityPolicyTests.swift
Core types (TerminalTimestampScrollbarState, TerminalTimestampVisibleRow, TerminalTimestampStore) implement per-row timestamps with scrollbar-aware record/backfill/prune/retention logic; tests validate growth, visible-window mapping, pruning, and preservation of marked-visible rows.
Settings persistence & file-store
Sources/App/WorkspaceRuntimeSettings.swift, Sources/CmuxSettingsJSONPathSupport.swift, Sources/KeyboardShortcutSettingsFileStore.swift, Sources/KeyboardShortcutSettingsFileStore+Template.swift, cmuxTests/KeyboardShortcutSettingsFileStoreStartupTests.swift
TerminalTimestampsSettings provides read/set/toggle/notify APIs backed by UserDefaults; settings-file parsing reads terminal.showTimestamps, templates include the field, managed-default updates trigger notifications, and a startup test verifies file-applied value.
Shortcut action & command palette
Sources/KeyboardShortcutSettings.swift, Sources/ContentView.swift, Sources/ContentView+RightSidebarCommandPalette.swift, Sources/AppDelegate.swift
Adds KeyboardShortcutSettings.Action.toggleTerminalTimestamps with localized label and default ⌥⌘⇧E; ContentView command palette contribution appears for terminal panels and toggles the setting; AppDelegate routes the shortcut action to toggle.
Gutter UI and scroll integration
Sources/GhosttyTerminalView.swift
Adds TerminalTimestampGutterView and integrates it into GhosttySurfaceScrollView: reserves gutter width, lays out gutter and terminal content, refreshes gutter on geometry/scroll/scrollbar updates, records scrollbar state into timestampStore, and responds to preference changes.
App menu and Settings UI
Sources/cmuxApp.swift
Adds a View menu command to toggle timestamps, @AppStorage-backed showTerminalTimestamps and binding that notifies on changes, a labeled Settings toggle row with on/off subtitle, and reset behavior to restore defaults and notify.
Localization, docs, shortcuts data, search & schema
Resources/Localizable.xcstrings, Sources/SettingsNavigation.swift, Sources/SettingsSearchAliases.swift, web/app/[locale]/docs/configuration/page.tsx, web/data/cmux-shortcuts.ts, web/data/cmux.schema.json
Adds English/Japanese localization for settings/menu/command/accessibility/search tokens, settings navigation entry and anchor mapping, a commented config example line in docs, shortcut metadata, and terminal.showTimestamps boolean in the JSON schema (default false).
Xcode project wiring
GhosttyTabs.xcodeproj/project.pbxproj
Adds TerminalTimestampStore.swift to the project and GhosttyTabs target (PBXBuildFile, PBXFileReference, Sources group, and PBXSourcesBuildPhase).

Sequence Diagram

sequenceDiagram
  participant User
  participant AppMenu as App Menu / Shortcut
  participant Settings as SettingsView
  participant Surface as GhosttySurfaceScrollView
  participant Store as TerminalTimestampStore
  participant Gutter as TerminalTimestampGutterView

  User->>AppMenu: invoke "Toggle Terminal Timestamps"
  AppMenu->>Settings: TerminalTimestampsSettings.toggle()
  Settings->>Surface: didChange notification
  Surface->>Store: record(scrollbar:at:markVisibleRows: true)
  Surface->>Gutter: refreshTimestampGutter()
  Gutter->>Store: visibleRows(for: scrollbarState)
  Store->>Gutter: TerminalTimestampVisibleRow[]
  User->>Surface: scroll / scrollbar update
  Surface->>Store: record(scrollbar:at:markVisibleRows: false)
  Surface->>Gutter: refreshTimestampGutter()
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • manaflow-ai/cmux#819: touches localization and shortcut-related code paths similar to this PR.
  • manaflow-ai/cmux#2389: also expands KeyboardShortcutSettings.Action cases and default shortcut mappings.
  • manaflow-ai/cmux#2729: overlaps terminal geometry/layout reconciliation that reserves side UI space used by the gutter.

Poem

🐰 I scratched a little gutter bright,
Where terminal times now come to light.
Each row keeps track of when it spoke,
A tiny tick beside the yoke.
Hop, tap, timestamp—soft as smoke.

🚥 Pre-merge checks | ✅ 13 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive PR description includes summary of changes and validation steps, but is missing required testing details and checklist items from template. Add explicit testing details (how locally tested, what manually verified) and complete the checklist with specific checks confirmed. Note about CI running tests is insufficient without local testing confirmation.
✅ Passed checks (13 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add terminal timestamps' clearly and concisely describes the main feature being added, matching the primary change across the entire changeset.
Linked Issues check ✅ Passed The PR successfully implements all core requirements from #3690: per-line timestamps in terminal view, toggleable via Settings/View menu/command palette/keyboard shortcut, configured via cmux.json and Settings UI, with proper retention/pruning and accessibility support.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the terminal timestamps feature (#3690): gutter rendering, timestamp storage, settings integration, UI/menu/shortcut wiring, schema/docs updates, and tests. No unrelated modifications detected.
Cmux Swift Actor Isolation ✅ Passed TerminalTimestampStore correctly @MainActor. Helper structs nonisolated Sendable. TerminalTimestampsSettings follows existing pattern. All uses in MainActor contexts. No isolation violations.
Cmux Swift Blocking Runtime ✅ Passed No blocking primitives introduced. TerminalTimestampStore uses @MainActor; settings use NotificationCenter. Zero new sleeps, semaphores, locks, or asyncAfter patterns in diff.
Cmux No Hacky Sleeps ✅ Passed Terminal timestamps PR changes are Swift (excluded), localization, and web data/docs. No sleep(), setTimeout, setInterval, polling, or timing workarounds in modified TS/JS/shell files.
Cmux Swift Concurrency ✅ Passed No legacy async patterns detected. TerminalTimestampStore uses @MainActor. NotificationCenter observer pattern allowed at AppKit boundary. No new Combine state or fire-and-forget Tasks introduced.
Cmux Swift @Concurrent ✅ Passed All new Swift code follows proper concurrency patterns. TerminalTimestampStore correctly uses @MainActor for UI-bound state. No missing/invalid @concurrent, no async boundary violations.
Cmux Swift File And Package Boundaries ✅ Passed Changes comply with boundaries rules. New file (232 lines, single responsibility), oversized files <250 lines added, no mixed responsibilities, appropriate UI glue.
Cmux Swift Logging ✅ Passed All code changes comply with logging rules. AppDelegate's new logging uses cmuxDebugLog wrapped in #if DEBUG. No unguarded print/NSLog/debugPrint/dump found in production code.
Cmux Swiftui State Layout ✅ Passed No SwiftUI state layout violations. TerminalTimestampStore properly @MainActor-isolated; uses @AppStorage for settings; NSView gutter; no @Published/@StateObject new patterns.
Cmux Architecture Rethink ✅ Passed Clear architecture with single state owner (UserDefaults), no timing repairs/sleeps/polling, no split lifecycle. Uses standard NotificationCenter pattern matching TerminalScrollBarSettings precedent.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR adds no standalone windows. Only TerminalTimestampGutterView (NSView subview in terminal pane), which is explicitly allowed. No NSWindowController, NSPanel, or window identifier changes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-3690-terminal-timestamps

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps

greptile-apps Bot commented May 12, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a toggleable terminal timestamp gutter that stamps per-row output times, wired through Settings, View menu, command palette (⌥⌘⇧E), cmux.json, and full localization across all 19 supported locales. It also refines scrollbar intent propagation to distinguish keyboard/search scrolls from passive output so the timestamp store never backfills user-revealed scrollback.

  • TerminalTimestampStore (new file) is @MainActor-isolated, prunes to 20 k rows with an advancing cursor and rowsBelowRetention set, and handles scrollback-shrink resets correctly; comprehensive unit tests cover growth, shrink, pruning, and backfill-prevention.
  • Scrollbar intent replaces the former thread-local keyboard marker with a lock-guarded _pendingScrollbarActionIntent / _scrollbarActionIntentStack pair; the carry-across mechanism makes the intent sticky for the duration of a key event and correctly handles output arriving between keydown and the main-thread flush.
  • TerminalTimestampGutterView caches DrawStyle keyed by font size and invalidates on effective-appearance change; the gutter is 88 px wide, has an accessibility label, and delegates mouse-down to focus the terminal.

Confidence Score: 5/5

Safe to merge; all previous review findings are addressed and no new issues were found.

All eight previously flagged issues were resolved in prior iterations. The lock-guarded intent stack correctly handles the I/O-thread boundary and sticky keyboard flag across coalesced output events. All 8 new string keys carry translations for all 19 supported locales. The TerminalTimestampStore pruning logic is bounded and correctly avoids hot-path reallocations. No new logic, isolation, or localization defects were found.

No files require special attention.

Important Files Changed

Filename Overview
Sources/GhosttyTerminalView.swift Adds GhosttyScrollbarUpdateIntent, lock-guarded intent stack/pending fields, TerminalTimestampGutterView with cached DrawStyle, and gutter layout integration. Scrollbar intent propagation through keyboard copy-mode actions and raw Page Up/Down is correctly handled.
Sources/TerminalTimestampStore.swift New @mainactor store with advancing prune cursor, rowsBelowRetention set, and bounds tracking. Record, prune, and visibleRows paths all look correct; bounded O(maxRetainedRows) per scrollbar event.
Resources/Localizable.xcstrings All 8 new string keys each carry translations for all 19 supported locales (ar, bs, da, de, en, es, fr, it, ja, ko, nb, pl, pt-BR, ru, th, tr, uk, zh-Hans, zh-Hant). No missing locales.
Sources/cmuxApp.swift Adds showTerminalTimestampsBinding, Settings row with localized subtitle variants, View menu item, and reset-to-defaults handling — all following the existing showScrollBar pattern.
Sources/App/WorkspaceRuntimeSettings.swift TerminalTimestampsSettings enum follows the established TerminalScrollBarSettings pattern exactly: isVisible, setVisible with guard, toggle, notifyDidChange.
cmuxTests/TerminalAndGhosttyTests.swift Integration tests cover keyboard backscroll no-backfill and search-driven explicit-sync after keyboard backscroll; uses debug-only injection API to simulate intent propagation across thread boundary.
cmuxTests/GhosttyTerminalViewVisibilityPolicyTests.swift 10 new @mainactor unit tests cover store growth, shrink/clear, pruning window, visible-row preservation, advancing prune cursor, and no-backfill on user scroll. Coverage is thorough.

Sequence Diagram

sequenceDiagram
    participant KB as Keyboard Event (Main)
    participant NSView as GhosttyNSView (Main)
    participant Lock as _scrollbarLock
    participant IO as Ghostty I/O Thread
    participant Main as Main Thread Flush
    participant Store as TerminalTimestampStore

    KB->>NSView: keyDown (PageUp/PageDown or copy-mode)
    NSView->>Lock: beginScrollbarActionIntent([.keyboardInitiated, .explicitSync])
    Note over Lock: _scrollbarActionIntentStack += intent<br/>_pendingScrollbarActionIntent |= intent

    IO->>NSView: GHOSTTY_ACTION_SCROLLBAR
    NSView->>Lock: consumeScrollbarActionIntent()
    Lock-->>NSView: [.keyboardInitiated, .explicitSync]
    NSView->>Main: enqueueScrollbarUpdate(scrollbar, intent)

    Note over IO: New output line arrives
    IO->>NSView: GHOSTTY_ACTION_SCROLLBAR (output)
    NSView->>Lock: consumeScrollbarActionIntent()
    Note over Lock: _pendingScrollbarActionIntent=[]<br/>but stack still has entry: sticky!
    Lock-->>NSView: [.keyboardInitiated, .explicitSync]
    NSView->>Main: enqueueScrollbarUpdate(coalesced)

    KB->>NSView: keyUp: endScrollbarActionIntent()
    Lock->>Lock: pop _scrollbarActionIntentStack

    Main->>Main: flushPendingScrollbar()
    Main->>Store: record(scrollbar, markVisibleRows: false)
    Note over Store: isUserInitiatedScroll=true<br/>no timestamp backfill
    Main->>Main: synchronizeScrollView() + refreshTimestampGutter()
Loading

Reviews (27): Last reviewed commit: "Add terminal timestamp localizations" | Re-trigger Greptile

Comment thread Sources/GhosttyTerminalView.swift Outdated
Comment thread Sources/GhosttyTerminalView.swift Outdated
Comment thread Sources/GhosttyTerminalView.swift
Comment thread Sources/GhosttyTerminalView.swift Outdated
Comment thread Sources/GhosttyTerminalView.swift Outdated
Comment thread Sources/TerminalTimestampStore.swift Outdated
Comment thread Sources/GhosttyTerminalView.swift
Comment thread Sources/TerminalTimestampStore.swift
Comment thread Sources/TerminalTimestampStore.swift Outdated
Comment thread Sources/TerminalTimestampStore.swift
Comment thread Sources/GhosttyTerminalView.swift

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 22 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="Sources/GhosttyTerminalView.swift">

<violation number="1" location="Sources/GhosttyTerminalView.swift:7808">
P2: Keyboard scroll intent detection is too broad: Ctrl/Option+PageUp/PageDown can leave a stale pending keyboard-scroll flag and misclassify the next passive scrollbar update.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
Re-trigger cubic

Comment thread Sources/GhosttyTerminalView.swift Outdated
Comment thread Sources/GhosttyTerminalView.swift
Comment thread Sources/GhosttyTerminalView.swift Outdated
Comment thread Resources/Localizable.xcstrings
Comment thread Sources/GhosttyTerminalView.swift

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 9c1a74e. Configure here.

case "gemini":
return preserveOptions(args, policy: geminiPolicy)
case "antigravity":
return preserveOptions(args, policy: antigravityPolicy)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed sanitizer policy breaks antigravity agent launch and resume

High Severity

The "antigravity" case and antigravityPolicy were removed from preservedArguments(kind:args:), but CLI/cmux.swift still routes antigravity agents through preservedArguments(kind: "antigravity", ...) for both launch sanitization and session resume. The default case now returns nil, which silently rejects all antigravity agent launches (treated as unsafe) and prevents session resume. This is a silent functional regression for any existing antigravity users.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 9c1a74e. Configure here.

@lawrencecchen lawrencecchen added the stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening. label Sep 23, 2026
@github-project-automation github-project-automation Bot moved this from Todo to Done in cmux backlog Sep 23, 2026

This branch was successfully deployed

1 active deployment
Preview – cmux — 9c1a74e8 Deployed May 22, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: Toggleable timestamps in terminal view (similar to iTerm2)

3 participants