diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5b233d0d..282b59c0 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -62,8 +62,15 @@ jobs:
- uses: Swatinem/rust-cache@v2
+ # `--locked` on the build so a Cargo.lock that disagrees with Cargo.toml
+ # fails here instead of being silently rewritten. Without it the drift is
+ # invisible to CI and lands on contributors instead: every local `cargo`
+ # run rewrites the lock, leaving a permanently dirty working tree that has
+ # to be re-discarded before every commit. The release workflow locks its
+ # build too; only nightly stays unlocked, because it stamps Cargo.toml's
+ # version and relies on cargo refreshing the lock's own root entry.
- name: Build
- run: cargo build --target ${{ matrix.target }}
+ run: cargo build --locked --target ${{ matrix.target }}
- name: Test
- run: cargo test --target ${{ matrix.target }}
+ run: cargo test --locked --target ${{ matrix.target }}
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
index 475df898..4631de9e 100644
--- a/.github/workflows/nightly.yml
+++ b/.github/workflows/nightly.yml
@@ -150,7 +150,7 @@ jobs:
# Same glob list as release.yml's Release step: the bundle scripts leave
# intermediates in dist/ (tty7.app, entitlements.plist, the Windows
# staging dir) that must not reach the release assets.
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@v7
with:
name: nightly-${{ matrix.os }}-${{ matrix.arch }}
path: |
@@ -173,7 +173,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- - uses: actions/download-artifact@v4
+ - uses: actions/download-artifact@v8
with:
path: dist
merge-multiple: true
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index eaf1657e..82c1a8bc 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -62,9 +62,13 @@ jobs:
with:
workspaces: tty7
+ # `--locked` because a release must ship the dependency set the tag
+ # recorded, not whatever cargo would re-resolve at build time. Safe here
+ # (unlike nightly) precisely because nothing rewrites Cargo.toml: this is
+ # a plain checkout of the tagged commit.
- name: Build
working-directory: tty7
- run: cargo build --release --target ${{ matrix.target }}
+ run: cargo build --release --locked --target ${{ matrix.target }}
# ---- Packaging: one step per OS ----------------------------------------
# macOS gets a signed + notarized drag-to-Applications DMG. Windows gets
diff --git a/.gitignore b/.gitignore
index 2a91e011..2e73c3e6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,8 +8,9 @@
.brooks-lint-history.json
openwiki/.last-update.json
-# dev-build throwaway config dir (cargo dev)
-.tty7-dev/
+# dev-build throwaway config dirs (`cargo dev`, plus per-branch ones passed as
+# --config-dir so a test run can't disturb a real profile)
+.tty7-dev*/
# Claude Code agent worktrees (transient)
.claude/worktrees/
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bfa6f405..3fd170ba 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,99 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+## [26.7.2] - 2026-07-21
+
+### Added
+
+- **WSL shell integration** — prompt marks, cwd tracking, and agent
+ detection now work inside WSL distros. The integration tags the shell
+ it actually launches, never blocks the spawn path while probing the
+ distro's shell, and declines untranslatable cwds rather than
+ misreporting them. (#134)
+- **Git Bash shell integration on Windows** — Git Bash panes get the
+ full integration, reporting proper Windows paths for cwd-dependent
+ features. (#130)
+- **Smart double-click selection** — double-click selects the word under
+ the cursor with language-aware boundaries, including CJK segmentation
+ (the OS tokenizer on macOS, jieba elsewhere); angle-bracket pairs must
+ hug their contents and contraction apostrophes stay out of quote
+ pairing. (#128)
+- **Configurable file-link command** — file links can open with a custom
+ command instead of the default editor. Contributed by @ayamir. (#143)
+- **Agent resume keeps launch flags** — resuming an agent session
+ carries the flags the agent was originally launched with onto the
+ resume command. (#144)
+- **Sidebar git line follows the agent's cwd** — the branch/status line
+ under an agent tab tracks the directory the agent is actually working
+ in, not just the pane's shell. (#127)
+
+### Changed
+
+- **Tab close button floats over the label** — the close affordance no
+ longer reserves a slot in every tab, so labels get the full width
+ until hovered. (#126)
+- **Dependency updates** — resvg 0.47, sha2 0.11, a cargo minor-patch
+ group bump, and newer CI artifact actions. (#137, #138, #139, #140,
+ #141)
+
+### Fixed
+
+- **Tab completion falls through to the shell** — a Tab tty7 has no
+ candidates for now hands the line to the shell's own completion
+ instead of being swallowed (remote panes included); `cd`/`pushd` stop
+ offering files; and the whole feature can be turned off with
+ `tab_completion` in config or Settings → Terminal → Keyboard. (#146)
+- **Remote panes never leak local filesystem operations** — a remote
+ pane's cwd is no longer used for local path lookups, and the agent-cwd
+ bypass validates inherited directories. (#133)
+- **macOS text input goes through the IME** — synthesized keystrokes
+ keep their text (remote/automated input no longer degrades), and Kitty
+ full mode stays off the IME path. (#132)
+- **No more console flashes on Windows git probes** — git status probes
+ and ssh ProxyCommand children no longer flash console windows. (#129)
+- **Windows titlebar menu spacing** — the titlebar "..." aligns with the
+ window-control rhythm. (#131)
+- **Codex avatar and macOS tray sizing** — the Codex tab avatar uses its
+ black brand field, and the tray icon renders at 22pt instead of the
+ hardcoded 18pt. (#142)
+- **Agents settings layout** — rows stay aligned and notes terse. (#125)
+
+## [26.7.1] - 2026-07-17
+
+### Added
+
+- **Follow the OS appearance** — a "Sync with system" mode with separate
+ light and dark theme slots: the theme flips live when the OS switches
+ appearance, native chrome follows along, and picking a theme while
+ syncing writes the slot matching the current mode. Old configs are
+ unchanged (sync defaults off). (#121)
+- **Mark as Unread on tabs** — the tab context menu can re-flag a finished
+ agent result you've already looked at, re-arming the unread badge on the
+ Done dot. Agent tabs only; disabled while the agent is still working.
+ (#120)
+
+### Changed
+
+- **"Duo" logo refresh** — a new brand mark (two offset session panes,
+ mint behind ink, with a prompt chevron) replaces the orange window
+ identity across every icon asset: app icon, logo, tray glyph, favicon,
+ and social preview. Bare macOS binaries (`cargo run`) now show the icon
+ in the Dock too. (#124)
+
+### Fixed
+
+- **Linked git worktrees group under their main repository** — the sidebar
+ keys groups on the repository home instead of each worktree's own root,
+ so a repo and its worktrees share one header while branch status stays
+ per-worktree. (#118)
+- **macOS tray icon stays a template image in every state** — the
+ attention state no longer swaps in a grey non-template glyph that was
+ illegible on many menu-bar appearances; agent status lives in the
+ tooltip and tray menu. (#122)
+- **No more console-window flashes from Windows agent hooks** — each hook
+ emitter frees its throwaway console before it can paint (debug builds
+ only; release builds were unaffected). (#119)
+
## [26.7.0] - 2026-07-16
First CalVer release: versions are now `YY.M.PATCH`, so the number says when
diff --git a/Cargo.lock b/Cargo.lock
index da8718df..8143651e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -116,6 +116,12 @@ version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
+[[package]]
+name = "adler32"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
+
[[package]]
name = "aead"
version = "0.6.1"
@@ -246,9 +252,9 @@ dependencies = [
[[package]]
name = "anyhow"
-version = "1.0.103"
+version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
+checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470"
[[package]]
name = "apple-native-keyring-store"
@@ -1007,6 +1013,12 @@ version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
+[[package]]
+name = "bytecount"
+version = "0.6.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e"
+
[[package]]
name = "bytemuck"
version = "1.25.0"
@@ -1152,6 +1164,15 @@ dependencies = [
"shlex 2.0.1",
]
+[[package]]
+name = "cedarwood"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0524a528a6a0288df1863c3c20fe92c301875b4941e7b6c4b394ab08c5a4c55"
+dependencies = [
+ "smallvec",
+]
+
[[package]]
name = "cesu8"
version = "1.1.0"
@@ -1814,6 +1835,12 @@ dependencies = [
"syn 2.0.118",
]
+[[package]]
+name = "dary_heap"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b1e3a325bc115f096c8b77bbf027a7c2592230e70be2d985be950d3d5e60ebe"
+
[[package]]
name = "dashmap"
version = "6.2.1"
@@ -4065,6 +4092,39 @@ version = "1.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89194689a993ab15268672e99e7b0e19da2da3268ac682e8f02d29d4d1434cd7"
+[[package]]
+name = "include-flate"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48f173716febb1ad596c16ea5637b5f1790ea32de8e627493ff82bc73b0876ce"
+dependencies = [
+ "include-flate-codegen",
+ "include-flate-compress",
+]
+
+[[package]]
+name = "include-flate-codegen"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a7875b62a72ad3f3203cdd8950d4cf9947db036030b974b8b37ceae90c8d8c0"
+dependencies = [
+ "include-flate-compress",
+ "proc-macro-error3",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "include-flate-compress"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44fbb9c5ccb9a5b67b4afa2974c27e5507ea1bf6d22828cef418e4dfaeca51dd"
+dependencies = [
+ "libflate",
+ "zstd",
+]
+
[[package]]
name = "indexmap"
version = "2.14.0"
@@ -4251,6 +4311,30 @@ version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
+[[package]]
+name = "jieba-macros"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38fc0f3831de71556de69643b80a08a5c8cd260a23c6b8dbeb7cd923c779cac5"
+dependencies = [
+ "phf_codegen 0.13.1",
+]
+
+[[package]]
+name = "jieba-rs"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb5bdea4dc241d589e179f39d2a778f31490f3370aa2f626223dbd930ebc5c9d"
+dependencies = [
+ "bytecount",
+ "cedarwood",
+ "include-flate",
+ "jieba-macros",
+ "phf 0.13.1",
+ "regex",
+ "rustc-hash 2.1.2",
+]
+
[[package]]
name = "jni"
version = "0.21.1"
@@ -4349,9 +4433,9 @@ dependencies = [
[[package]]
name = "keyring"
-version = "4.1.4"
+version = "4.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6ee8d4dae108d4177d0a0ce241f98acc1ef28e20837bdef43cff4d160cf70fe"
+checksum = "0298a59b384c540e408a600c8b375a09b49c3f97debc080e2c30675d79a6368a"
dependencies = [
"apple-native-keyring-store",
"keyring-core",
@@ -4506,6 +4590,30 @@ version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
+[[package]]
+name = "libflate"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd96e993e5f3368b0cb8497dae6c860c22af8ff18388c61c6c0b86c58d86b5df"
+dependencies = [
+ "adler32",
+ "crc32fast",
+ "dary_heap",
+ "libflate_lz77",
+ "no_std_io2",
+]
+
+[[package]]
+name = "libflate_lz77"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff7a10e427698aef6eef269482776debfef63384d30f13aad39a1a95e0e098fd"
+dependencies = [
+ "hashbrown 0.16.1",
+ "no_std_io2",
+ "rle-decode-fast",
+]
+
[[package]]
name = "libfuzzer-sys"
version = "0.4.13"
@@ -4788,7 +4896,7 @@ checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45"
dependencies = [
"log",
"phf 0.11.3",
- "phf_codegen",
+ "phf_codegen 0.11.3",
"string_cache",
"string_cache_codegen",
"tendril",
@@ -5980,6 +6088,16 @@ dependencies = [
"phf_shared 0.11.3",
]
+[[package]]
+name = "phf_codegen"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1"
+dependencies = [
+ "phf_generator 0.13.1",
+ "phf_shared 0.13.1",
+]
+
[[package]]
name = "phf_generator"
version = "0.11.3"
@@ -6400,6 +6518,16 @@ dependencies = [
"quote",
]
+[[package]]
+name = "proc-macro-error-attr3"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34e4dd828515431dd6c4a030d26f7eaed7dd4778226e9d2bb968d65ca4ec3d4d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+]
+
[[package]]
name = "proc-macro-error2"
version = "2.0.1"
@@ -6412,6 +6540,18 @@ dependencies = [
"syn 2.0.118",
]
+[[package]]
+name = "proc-macro-error3"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ee475e440453418ff1335189eddf7101ba502cd818ab7ae04209bc83aa925aa"
+dependencies = [
+ "proc-macro-error-attr3",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
[[package]]
name = "proc-macro2"
version = "1.0.106"
@@ -6885,9 +7025,9 @@ dependencies = [
[[package]]
name = "regex"
-version = "1.12.4"
+version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba"
+checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d"
dependencies = [
"aho-corasick",
"memchr",
@@ -6897,9 +7037,9 @@ dependencies = [
[[package]]
name = "regex-automata"
-version = "0.4.14"
+version = "0.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
+checksum = "8fcfdb36bda0c880c5931cdc7a2bcdc8ba4556847b9d912bca70bc94708711ad"
dependencies = [
"aho-corasick",
"memchr",
@@ -6986,6 +7126,12 @@ dependencies = [
"windows-sys 0.52.0",
]
+[[package]]
+name = "rle-decode-fast"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422"
+
[[package]]
name = "ropey"
version = "2.0.0-beta.1"
@@ -7605,9 +7751,9 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.228"
+version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
dependencies = [
"serde_core",
"serde_derive",
@@ -7625,22 +7771,22 @@ dependencies = [
[[package]]
name = "serde_core"
-version = "1.0.228"
+version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.228"
+version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
+checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.118",
+ "syn 3.0.2",
]
[[package]]
@@ -7665,9 +7811,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.150"
+version = "1.0.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
+checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
dependencies = [
"indexmap",
"itoa",
@@ -8382,6 +8528,17 @@ dependencies = [
"unicode-ident",
]
+[[package]]
+name = "syn"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a207d6d6a2b7fc470b80443726053f18a2481b7e1eee970597051596567987a3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
[[package]]
name = "sync_wrapper"
version = "1.0.2"
@@ -8713,9 +8870,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
-version = "1.52.3"
+version = "1.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe"
+checksum = "d988bcd52dbe076d3d46903332f58c912b87a2c49b1428419a5845154762ffee"
dependencies = [
"bytes",
"libc",
@@ -9382,10 +9539,11 @@ dependencies = [
[[package]]
name = "tty7"
-version = "26.7.0"
+version = "26.7.2"
dependencies = [
"alacritty_terminal",
"anyhow",
+ "core-foundation 0.10.0",
"getrandom 0.3.4",
"gpui",
"gpui-component",
@@ -9393,6 +9551,7 @@ dependencies = [
"gpui_platform",
"ignore",
"image",
+ "jieba-rs",
"keyring",
"ksni",
"libc",
@@ -9404,8 +9563,10 @@ dependencies = [
"notify-rust",
"objc2 0.6.4",
"objc2-app-kit 0.3.2",
+ "objc2-foundation 0.3.2",
"plist",
"portable-pty",
+ "regex",
"reqwest_client",
"resvg",
"ropey",
@@ -9662,9 +9823,9 @@ dependencies = [
[[package]]
name = "uuid"
-version = "1.23.4"
+version = "1.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53"
+checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239"
dependencies = [
"getrandom 0.4.3",
"js-sys",
@@ -11473,6 +11634,34 @@ version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
+[[package]]
+name = "zstd"
+version = "0.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
+dependencies = [
+ "zstd-safe",
+]
+
+[[package]]
+name = "zstd-safe"
+version = "7.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
+dependencies = [
+ "zstd-sys",
+]
+
+[[package]]
+name = "zstd-sys"
+version = "2.0.16+zstd.1.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748"
+dependencies = [
+ "cc",
+ "pkg-config",
+]
+
[[package]]
name = "ztracing"
version = "0.1.0"
diff --git a/Cargo.toml b/Cargo.toml
index 929936bb..65198a07 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "tty7"
-version = "26.7.0"
+version = "26.7.2"
edition = "2024"
description = "A terminal workbench: shells, persistent sessions, SSH, coding agents — GPU-rendered on Zed's gpui, pure Rust"
repository = "https://github.com/l0ng-ai/tty7"
@@ -21,6 +21,9 @@ gpui-component-assets = { workspace = true }
anyhow.workspace = true
log.workspace = true
+# Smart double-click selection patterns (URL/email/path). Already in the tree
+# transitively, so pinning it here adds no new native code.
+regex = "1"
smol.workspace = true
smallvec.workspace = true
serde = { workspace = true }
@@ -183,8 +186,25 @@ winresource = "0.1"
# app appearance to match the active theme (see `ui::theme::sync_native_appearance`)
# so the native traffic-light buttons render in the right light/dark style.
[target.'cfg(target_os = "macos")'.dependencies]
+# CFStringTokenizer FFI for dictionary-based CJK word segmentation on
+# double-click (`terminal::smart_select`). Already in the tree transitively,
+# and it makes jieba unnecessary here — see the non-macos section below.
+core-foundation = "0.10"
objc2 = "0.6"
-objc2-app-kit = { version = "0.3", features = ["NSApplication", "NSResponder", "NSAppearance", "NSGraphics"] }
+objc2-app-kit = { version = "0.3", features = ["NSApplication", "NSResponder", "NSAppearance", "NSGraphics", "NSImage"] }
+# NSData feeds the runtime Dock icon for bare (non-bundled) binaries — see
+# `set_dock_icon_for_bare_binary` in main.rs.
+objc2-foundation = { version = "0.3", features = ["NSData"] }
+
+# Dictionary-based Chinese word segmentation for double-click selection
+# (`terminal::smart_select`), as a *fallback* where the OS has no tokenizer of
+# its own. macOS is excluded on purpose: CFStringTokenizer segments Chinese
+# about as well (and Japanese/Korean far better) at zero cost, while jieba's
+# table costs ~55 MB resident once built and ~2 MB of binary for the embedded
+# dictionary. Keeping the dep off macOS means that dictionary isn't even
+# linked into the build that can't use it.
+[target.'cfg(not(target_os = "macos"))'.dependencies]
+jieba-rs = "0.10"
# x11/wayland are the Linux windowing backends; only pull them on Linux. The
# Windows backend (`gpui_windows`) and macOS backend are selected by gpui_platform
diff --git a/README.md b/README.md
index 7352b5cd..15278946 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@
[](https://github.com/l0ng-ai/tty7/actions/workflows/ci.yml)
-[](https://github.com/l0ng-ai/tty7/releases)
+[](https://github.com/l0ng-ai/tty7/releases)
[](LICENSE)
[](https://discord.gg/s3dethqz2V)
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 4ef795ea..91be1423 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -11,7 +11,7 @@
[](https://github.com/l0ng-ai/tty7/actions/workflows/ci.yml)
-[](https://github.com/l0ng-ai/tty7/releases)
+[](https://github.com/l0ng-ai/tty7/releases)
[](LICENSE)
[](https://discord.gg/s3dethqz2V)
diff --git a/assets/app-icon.png b/assets/app-icon.png
index 322eb4c7..1dfc4225 100644
Binary files a/assets/app-icon.png and b/assets/app-icon.png differ
diff --git a/assets/app-icon.svg b/assets/app-icon.svg
index 4bccf439..2b53f763 100644
--- a/assets/app-icon.svg
+++ b/assets/app-icon.svg
@@ -1,6 +1,11 @@
-