Commit graph

127 commits

Author SHA1 Message Date
Lawrence Chen
3566b6ec21
Regenerate app icons from Icon Composer (#1005)
* Add Apple Icon Composer source file

Store the .icon project file in design/cmux.icon so the icon can be
edited in Icon Composer and regenerated from source.

* Regenerate all app icons from Icon Composer

Use ictool to render light/dark icon PNGs from the .icon source file
with proper macOS padding. Updates AppIcon, AppIcon-Debug (with DEV
banner), AppIconLight, and AppIconDark imagesets. Adds AppIcon.icon
to the Xcode project as a resource.

* Address review: fix trailing newline, remove .icon from bundle

- Add trailing newline to icon.json files
- Remove AppIcon.icon from Copy Bundle Resources (design-time only)
2026-03-06 04:30:54 -08:00
Lawrence Chen
29054dc709
Add sidebar help menu to footer (#958)
* Add sidebar help menu

* Fix help menu test wiring

* Fix help menu accessibility

* Use native popup for help menu

* Use icon button for sidebar help

* Add feedback composer and feedback API

* Allow preview builds without feedback env

* Tighten feedback upload limits

* Adjust sidebar footer padding

* Tighten sidebar footer spacing

* Add link affordances to help menu

* Polish sidebar feedback composer

* Move feedback icon to trailing edge

* Normalize help menu trailing icon sizes

* Enlarge help menu trailing icons

* Reduce help menu link icon size

* Shrink help menu link arrow

* Reduce help menu link arrow again

* Fix feedback message editor focus

* Add send feedback keyboard shortcut

* Polish feedback launch and delivery
2026-03-05 21:00:42 -08:00
Lawrence Chen
895fb802c8
Add 16 new languages to localization (#895)
* Add localization for 16 new languages

Add translations for all 637 UI string keys and 3 InfoPlist keys in:
ar, bs, da, de, es, fr, it, ko, nb, pl, pt-BR, ru, th, tr, zh-Hans, zh-Hant

Update AppLanguage enum and knownRegions to include all 18 languages.
Total supported languages: en, ja + 16 new = 18.

* Reorder languages: English first, rest alphabetical, explicit display names

Use "Chinese Simplified" / "Chinese Traditional" naming. Show native script
with English name in parentheses for non-Latin languages.

* Add Chinese native characters to language display names

* Delay language restart dialog until picker dropdown closes

* Fix Arabic bidi rendering in language picker with LTR mark

* Defer AppleLanguages write to app launch, fix picker animation lag

Writing AppleLanguages to UserDefaults triggers synchronous locale
recalculation on the main thread, causing the picker dropdown dismiss
animation to stutter. Since a restart is already required, move the
AppleLanguages write to init() on next launch instead of onChange.

* Fix reset path and add apply() back to delayed onChange

- resetAllSettings() now calls LanguageSettings.apply(.system) and
  shows restart alert if language was changed from launch value
- onChange also calls apply() inside the 0.3s delay block, so
  AppleLanguages is set before restart (avoids two-restart issue)
- init() still calls apply() as belt-and-suspenders for launch

* Fix deferred alert race: re-check current language in closure

If user changes language then changes back within 0.3s, the stale
closure would fire with the old value. Now reads current appLanguage
inside the closure instead of capturing newValue.

* Fix Spanish and Danish translations: restore missing diacritics

Spanish was missing all áéíóúñ characters (now 315 diacritics).
Danish was missing all æøå characters (now 401 diacritics).
Both languages fully retranslated with correct orthography.

* Fix reset restart alert: compare new value against launch language

Was comparing previousLanguage against languageAtLaunch, which would
miss the case where user launched in Spanish and reset to System
(Spanish != Spanish = false, so no alert). Now compares the new
appLanguage (system) against languageAtLaunch.
2026-03-04 18:04:33 -08:00
Ismail Pelaseyed
d72b014d6d
feat: add markdown viewer panel with live file watching (#883)
* Add markdown viewer panel with live file watching

Introduce a new PanelType.markdown that renders .md files in a dedicated
panel using MarkdownUI (SwiftUI), with live file watching via DispatchSource
so content auto-updates when the file changes on disk.

- New MarkdownPanel class with file system watcher (write/delete/rename/extend)
- New MarkdownPanelView with custom cmux theme (headings, code blocks, tables,
  blockquotes, inline code, lists, horizontal rules, light/dark mode)
- Full workspace integration: SurfaceKind, creation methods, tab subscription
- Session persistence: snapshot/restore across app restarts
- V2 socket command: markdown.open (validates path, resolves workspace, splits)
- CLI command: cmux markdown open <path> with routing flags and help text
- Agent skill: skills/cmux-markdown/ with SKILL.md, openai.yaml, and references
- Cross-link from skills/cmux/SKILL.md to the new markdown skill
- SPM dependency: gonzalezreal/swift-markdown-ui 2.4.1

* Fix unreachable guard in markdown subcommand dispatch

Use looksLikePath() to distinguish subcommands from path arguments
so the guard can catch unknown subcommands and future subcommands
are parsed correctly.

* Use .isoLatin1 fallback instead of .ascii for encoding recovery

ASCII is a strict subset of UTF-8, so falling back to .ascii after
UTF-8 fails is dead code. Use .isoLatin1 which accepts all 256 byte
values and covers legacy encodings like Windows-1252.

* Mark fileWatchSource as nonisolated(unsafe) for deinit safety

deinit is not guaranteed to run on the main actor, so accessing
@MainActor-isolated storage is a data race under strict concurrency.
DispatchSource.cancel() is thread-safe, so nonisolated(unsafe) is
sufficient with a documented invariant that writes only occur on main.

* Fix file watcher reattach: retry loop with cancellation guard

- Replace one-shot 500ms retry with up to 6 attempts (3s total window)
  so files that reappear after a slow atomic replace are picked up
- Add isClosed flag checked before each retry to prevent restarting
  the watcher after close()/deinit

* Harden path validation in markdown.open command

Reject directories and non-absolute paths before panel creation
to prevent ambiguous behavior and generic downstream failures.

* Always reattach file watcher on delete/rename events

After an atomic save (delete old + create new), the DispatchSource still
points to the old inode. Previously we only reattached when the file was
unreadable, so successful atomic saves left the watcher on a stale inode
and live updates silently stopped. Now we always stop and reattach:
immediately if the new file is readable, via retry loop if not.

* Restore markdown panels even when file is missing at launch

MarkdownPanel already handles unavailable files gracefully (shows
'file unavailable' UI and retries via the reattach loop). Dropping
the panel on restore lost the user's layout for files that may
reappear shortly after (network drives, build artifacts, etc.).

* Harden markdown CLI parsing and startup reconnect behavior

---------

Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com>
2026-03-04 17:48:28 -08:00
Yoshiki Agatsuma
76bdf7631a
Add find-in-page (Cmd+F) for browser panels (#837) (#875)
JavaScript-based find using TreeWalker + <mark> highlights with
match counter, next/previous navigation, and drag-to-corner overlay
matching the existing terminal find bar.

- BrowserFindJavaScript: JS generation for search/next/prev/clear
- BrowserSearchOverlay: SwiftUI overlay with IME-safe onSubmit
- BrowserSearchState: Observable state (needle/selected/total)
- TabManager routing: Cmd+F/G dispatches to browser when focused
- Visibility filter: skips script/style/hidden/aria-hidden elements
- Stale DOM guard: isConnected check in next/previous scripts
- Navigation cleanup: clears find on didFinish and didFailNavigation

Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com>
2026-03-04 16:15:15 -08:00
atani
2c330efb8a
feat: add Japanese localization with String Catalog (#819)
* Add i18n infrastructure with String Catalog and Japanese translations

Introduce String Catalog (.xcstrings) for localization support:
- Localizable.xcstrings: 195 UI string entries with en and ja translations
- InfoPlist.xcstrings: Info.plist strings (microphone usage, Finder menu items)
- project.pbxproj: add xcstrings to build phase and ja to knownRegions

* Replace hardcoded UI strings with String(localized:defaultValue:)

Migrate all user-facing strings across 11 source files to use
String(localized:defaultValue:) API (macOS 13+). Each string references
a key in Localizable.xcstrings, with the English text preserved as
defaultValue for fallback.

Files modified:
- KeyboardShortcutSettings: 28 shortcut labels
- SocketControlSettings: mode names and descriptions
- TabManager: placement labels, color names, close dialogs
- BrowserPanel/BrowserPanelView: error pages, context menus, tooltips
- UpdateViewModel/UpdatePopoverView/UpdatePill: update UI states
- NotificationsPage: notification panel labels
- SurfaceSearchOverlay: search bar placeholder and tooltips
- AppDelegate: menus, dialogs, command palette items

* Fix localization gaps from review feedback

Address review comments from CodeRabbit, Greptile, and Cubic Dev AI:
- Use interpolated String(localized:) instead of concatenation for
  version/progress strings in UpdateViewModel
- Localize remaining hardcoded strings in AppDelegate: window labels,
  rename dialog, status menu items, unread notification count
- Localize insecure HTTP alert body in BrowserPanel
- Add 12 new entries to Localizable.xcstrings with Japanese translations

* Fix String(localized:defaultValue:) keys to use StaticString

The localized: parameter requires StaticString when defaultValue: is
used. Move string interpolation from the key to defaultValue only,
and revert maxWidthText to plain strings since they are only used for
layout width calculation.

* Localize remaining UI strings across all source files

Add String(localized:defaultValue:) to all user-facing strings in:
- cmuxApp.swift: settings screen, menus, about panel, dialogs (~180 strings)
- ContentView.swift: command palette, sidebar context menu, dialogs (~200 strings)
- Workspace.swift: rename/move/close tab dialogs, tooltips (~20 strings)
- UpdateTitlebarAccessory.swift: titlebar tooltips, notifications popover (~10 strings)
- TerminalNotificationStore.swift: notification permission dialog (4 strings)
- CmuxWebView.swift: browser context menu items (2 strings)
- AppDelegate.swift: CLI install/uninstall alerts (6 strings)

Add 418 new entries to Localizable.xcstrings with Japanese translations.
Extract sidebar context menu into separate @ViewBuilder to fix Swift
type-checker timeout in large body.
Fix xcstrings format specifiers for interpolated strings (%lld, %@).

Total: 624 localization entries covering the full UI.

* Address review feedback: fix missing localizations and terminology

- Localize javaScriptDialogTitle URL branch in BrowserPanel
- Localize cantReach error message in BrowserPanel
- Localize close other tabs dialog message in TabManager
- Localize workspace accessibility label in ContentView
- Fix unread notification singular/plural (split into two keys)
- Fix insecure connection apostrophe inconsistency (unify to U+2019)
- Rename socketControl.fullOpen.description to socketControl.allowAll.description
- Remove dead code: renameTargetNoun function
- Fix terminology inconsistencies in xcstrings:
  - Unify "Developer Tools" to デベロッパツール
  - Unify "Jump to Latest Unread" phrasing
  - Unify "Flash Focused Panel" terminology
  - Fix dialog.enableNotifications.notNow translation

* fix: address remaining PR 819 review feedback

* fix: use a single localized key for close-other-tabs

* fix: avoid inflection markup in close-other-tabs message

* Address review feedback: localize tooltip, fix subtitle concat, unify keys

- Localize menubar tooltip unread count (hardcoded English -> localized)
- Replace subtitle string concatenation anti-pattern with single localized
  keys containing interpolation placeholders
- Unify workspace fallback key to workspace.displayName.fallback
- Remove unused workspace.defaultName key from xcstrings
- Add Japanese translations for new tooltip and subtitle keys
2026-03-04 14:58:28 -08:00
Lawrence Chen
163f8572e4
Replace keychain password storage with file-based storage (#576)
Moves socket control password from the macOS login keychain to a
plain file at ~/Library/Application Support/cmux/socket-control-password.
This eliminates the system keychain prompt that interrupts users on
first launch or after keychain changes.

- Directory created with 0700, file written with 0600 permissions
- One-time migration copies existing keychain password to the file,
  deletes the keychain entry, and records a migration version in
  UserDefaults so it runs only once
- CLI SocketPasswordResolver also reads from the file path
- Security framework import is now conditional (#if canImport)
- Adds SocketControlPasswordStoreTests covering round-trip, env
  priority, path resolution, and migration behavior

Fixes https://github.com/manaflow-ai/cmux/issues/541
2026-02-26 14:29:12 -08:00
Lawrence Chen
a46ee2ba3b
Merge pull request #431 from yasunogithub/fix-ime-ctrl-fastpath
Fix IME key events blocked by ctrl fast path
2026-02-25 02:46:12 -08:00
Lawrence Chen
8caa5e9c91
Bump version to 0.61.0 (#470) 2026-02-25 02:18:51 -08:00
yasunogithub
b6c5e3fe9e Fix IME key events blocked by ctrl fast path and missing layout change detection
The ctrl fast path unconditionally returned after calling ghostty_surface_key,
even when it returned false (e.g. ignore keybindings), preventing IMEs from
receiving Ctrl-modified key events. Now falls through to interpretKeyEvents
when the key is not handled.

Also adds keyboard layout change detection around interpretKeyEvents (matching
Ghostty upstream) so that IME-triggered layout switches cause an early return
instead of sending the key to Ghostty.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 14:36:54 +09:00
Lawrence Chen
915c01f9d0 Add ../../Frameworks rpath for bundled cmux cli 2026-02-24 20:47:01 -08:00
Lawrence Chen
93c167ff02 Add Sentry breadcrumbs for claude-hook socket failures 2026-02-24 20:22:38 -08:00
Lawrence Chen
6505f0c504 Fix tab drag blank state and preserve non-custom titles across window drops 2026-02-24 14:36:12 -08:00
Lawrence Chen
78d1a43733 Persist workspace tab colors across session restore 2026-02-23 19:27:32 -08:00
Lawrence Chen
ea33e3adbd Merge remote-tracking branch 'origin/main' into pr-317-session-persistence
# Conflicts:
#	Sources/AppDelegate.swift
2026-02-23 19:20:56 -08:00
Lawrence Chen
53ef6a5f7d
Upgrade Sentry: tracing, breadcrumbs, dSYM upload (#366)
* Upgrade Sentry: tracing, breadcrumbs, dSYM upload

- Enhanced Sentry SDK init with performance tracing (10% sample),
  explicit app hang timeout, stack trace attachment, and HTTP
  failure capture
- Added breadcrumbs for key user actions: workspace switch/create/close,
  split creation, command palette open/close, app focus — these give
  context to hang/crash reports
- Added dSYM upload step to nightly and release CI workflows so hang
  stacks are fully symbolicated (requires SENTRY_AUTH_TOKEN secret)
- Created SentryHelper.swift with lightweight breadcrumb helper

Closes https://github.com/manaflow-ai/cmux/issues/365

* Remove command palette breadcrumbs

Not useful for hang diagnosis — keep only workspace/tab/split/focus
breadcrumbs that correlate with heavy operations.
2026-02-23 17:11:01 -08:00
Lawrence Chen
6eeca9c5da Merge remote-tracking branch 'origin/main' into pr-317-session-persistence
# Conflicts:
#	Sources/AppDelegate.swift
#	Sources/cmuxApp.swift
2026-02-23 14:58:16 -08:00
sugakoji
2c1fd1f801 Add open wrapper to route URLs to embedded browser
When running `open https://...` inside a cmux terminal, the URL now
opens in the built-in browser panel instead of the system default
browser. Non-URL arguments and explicit flags pass through to
/usr/bin/open unchanged.

Closes #306

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
(cherry picked from commit 174623776eb0baef04f5a9ab49b926427c149acd)
2026-02-22 18:05:43 -08:00
Lawrence Chen
927b0eb2d1 Implement session persistence pass 1 with multi-window restore 2026-02-22 15:39:59 -08:00
Lawrence Chen
71d087db73
Prepare release v0.60.0 (#283)
Bump version to 0.60.0 (build 72) and add changelog entry
covering all changes since v0.59.0.
2026-02-21 15:09:19 -08:00
Lawrence Chen
438b7a6a41 Merge remote-tracking branch 'origin/main' into fix/browser-devtools-shortcuts-pr
# Conflicts:
#	Sources/Panels/BrowserPanel.swift
#	Sources/cmuxApp.swift
#	cmuxTests/CmuxWebViewKeyEquivalentTests.swift
#	vendor/bonsplit
2026-02-20 15:48:27 -08:00
Lawrence Chen
7b2675cd1e
Fix theme initialization to respect configured/system appearance (#161)
* Respect configured appearance before Ghostty initialization

* Apply Ghostty theme colors to cmux titlebar and tab chrome

* Fix builtin theme resolution and tab strip icon contrast

* Alias builtin Solarized names to current Ghostty themes

* Sync tab chrome with active Ghostty theme

* Fix system appearance theme switching for surfaces

* Refresh titlebar on background theme updates

* Refresh split overlay config on appearance change

* Update bonsplit for chrome color review fixes
2026-02-20 04:51:01 -08:00
Lawrence Chen
db66fc4bb0 Stabilize browser portal bounds and log inspector height metrics 2026-02-19 23:19:00 -08:00
Lawrence Chen
463c6baabb
Fix CJK IME input (Korean, Chinese, Japanese) (#125)
* Fix CJK IME input not working (#118)

CJK (Korean, Japanese, Chinese) IME input was completely broken because
cmux never forwarded preedit/composition state to Ghostty's libghostty.

Root causes and fixes:

1. Missing preedit sync: Added syncPreedit() that calls
   ghostty_surface_preedit() to notify Ghostty about IME composition
   text. Called from setMarkedText, unmarkText, and after
   interpretKeyEvents in keyDown.

2. Wrong composing flag: The composing flag on key events now correctly
   accounts for when composition just ended (markedTextBefore was true
   but markedText is now empty), preventing spurious deletions when
   canceling composition.

3. Event interception during IME: Added early exits in
   performKeyEquivalent, the NSWindow swizzle, and the local event
   monitor (handleCustomShortcut) to avoid stealing key events while
   IME has active marked text.

4. IME popup positioning: firstRect(forCharacterRange:) now uses
   ghostty_surface_ime_point() for accurate cursor-relative positioning
   of the IME candidate window.

* Add regression tests for CJK IME composition (#118)

31 tests covering Korean, Japanese, and Chinese IME input scenarios:

- Korean jamo combining: ㅎ -> 하 -> 한 composition lifecycle
- Chinese pinyin: multi-letter marked text and candidate selection
- Japanese hiragana-to-kanji: romaji -> hiragana -> kanji conversion
- insertText correctly commits composed text and clears marked state
- unmarkText properly clears composition state (idempotent)
- performKeyEquivalent returns false during active composition for
  all key types (plain, shift, space, return, escape)
- Shortcut bypass: hasMarkedText gates the handleCustomShortcut bypass
- Multi-syllable sequences, backspace correction, and rapid transitions
- keyTextAccumulator lifecycle tests

Also adds #if DEBUG test accessors for keyTextAccumulator on
GhosttyNSView to enable unit testing the accumulator path.
2026-02-19 22:37:41 -08:00
Lawrence Chen
3972f39e49 Bump version to 0.59.0 2026-02-19 21:29:27 -08:00
Lawrence Chen
9a8e5f9d13 Bump version to 0.58.0 2026-02-19 17:24:10 -08:00
Lawrence Chen
b624c580a7 Bump version to 0.57.0 2026-02-19 16:53:21 -08:00
Lawrence Chen
b2415020ec Bump version to 0.56.0 2026-02-19 04:36:36 -08:00
Lawrence Chen
4f84166e5b Bump version to 0.55.0 2026-02-19 04:25:35 -08:00
Lawrence Chen
9642bb59fc
Move port scanning from shell to app-side with batching (#100)
* Move port scanning from shell to app-side with batching

Replace per-shell `ps -axo + lsof` scanning with a centralized
PortScanner singleton in the app. Each shell now sends lightweight
`report_tty` (once per session) and `ports_kick` (on preexec/precmd)
socket messages. The app coalesces kicks across all panels and runs a
single `ps -t <ttys> + lsof -p <pids>` covering every active panel.

Also fixes a macOS 26 Tahoe regression where `getsockopt(LOCAL_PEERPID)`
returns ENOTCONN on accepted sockets when the peer disconnects before
the handler thread starts. This was silently breaking ALL socket
commands sent via ncat --send-only. The fix captures the peer PID in
the accept loop immediately after accept(), and falls back to
LOCAL_PEERCRED (uid check) when the PID lookup fails.

* Fix PR review feedback: burst timing and auth comment clarity

- P2: burstDelays were accumulating (0.5+1.5+3+... = ~22.5s) instead of
  firing at absolute offsets from burst start. Now uses burstStart anchor
  so scans fire at 0.5s, 1.5s, 3s, 5s, 7.5s, 10s as intended.

- P1: Clarify LOCAL_PEERCRED fallback rationale — same security boundary
  as socket file permissions (0600), does not widen attack surface.
  Long-lived connections still get full descendant check via LOCAL_PEERPID.
2026-02-19 01:04:47 -08:00
Lawrence Chen
e818aa21d7
Bump version to 0.54.0 (#98) 2026-02-18 23:26:56 -08:00
Lawrence Chen
2b026215ca
Bump version to 0.53.0 (#96) 2026-02-18 22:54:26 -08:00
Lawrence Chen
7ac7c37de2
Bump version to 0.52.0 (#95) 2026-02-18 22:34:24 -08:00
Lawrence Chen
d08f28d770
Merge pull request #83 from manaflow-ai/perf/portal-hosting-selected-mount
Reduce terminal input latency via portal hosting + selected-only workspace mounting
2026-02-18 22:31:45 -08:00
Lawrence Chen
75b25217b5
Bump version to 0.51.0 (#94) 2026-02-18 22:11:58 -08:00
Lawrence Chen
442eb1f01d Rename test targets to cmuxTests and cmuxUITests 2026-02-18 21:19:56 -08:00
Austin Wang
0851cff378
Bump version to 0.50.0 (#91)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 21:10:34 -08:00
Lawrence Chen
ed7f6301d0 Improve terminal hosting depth and workspace mount policy 2026-02-18 19:55:41 -08:00
Lawrence Chen
9e3f5830a8
Bump version to 0.49.0 (#84) 2026-02-18 19:54:58 -08:00
Lawrence Chen
fe082cd213
Bump version to 0.48.0 (#80) 2026-02-18 17:56:22 -08:00
Lawrence Chen
2dd4a3c6b2
Bump version to 0.47.0 (#77) 2026-02-18 17:22:46 -08:00
Lawrence Chen
cf0f08f0e2
Bump version to 0.46.0 (#75) 2026-02-18 16:49:22 -08:00
Lawrence Chen
9105ecbf03 Bump version to 0.45.0 2026-02-18 16:27:15 -08:00
Austin Wang
adac50c5b9
Bump version to 0.44.0 (#70)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 14:41:20 -08:00
Lawrence Chen
fdd8029c00 Bump version to 0.43.0 2026-02-18 02:19:30 -08:00
Lawrence Chen
fb93a9f5ef Bump version to 0.42.0 2026-02-18 01:11:18 -08:00
Lawrence Chen
4d6a3f81bf Bump version to 0.41.0 2026-02-17 22:23:12 -08:00
Lawrence Chen
5f314cd6a7 Bump version to 0.40.0 2026-02-17 22:00:47 -08:00
Lawrence Chen
55437871d7 Bump version to 0.39.0 2026-02-17 18:43:23 -08:00
Lawrence Chen
6d6efb6b60 Reversion all 1.x.x to 0.x.x for pre-launch versioning 2026-02-17 18:31:05 -08:00