Vectrum
Sign In

Merge the T3 Code settings view

Brings in settings rebuilt after T3 Code: its flat navigation and search,
every page's sections and rows with T3's wording and defaults (General,
Appearance with the theme cards, Keybindings, Providers in two panes with
the Add provider wizard, Integrations, Source Control, Storage,
Connections, Archive, Usage, Diagnostics, Open source licenses), per-row
resets and Restore device defaults.

On top of the merge, the settings it added now take effect: the send
shortcut (Enter, Ctrl+Enter for multiline prompts, Ctrl+Enter always),
chat width, models hidden from the picker, diff colors in the commit
dialog and the panel, sound-only notifications, and the double-press quit
message. Project grouping keeps the sidebar's three-way rule behind T3's
switch, and Unarchive restores the thread to the sidebar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
JjohannSocommitted 2 parents f3585a5 511a677commit6d816d7

Showing 34 changed files with 7054 additions and 2619 deletions.

Merge commit — showing changes against the first parent.

+46−21README.mdView File
@@ -125,7 +125,7 @@ Gruvbox, Rosé Pine, Solarized and Dracula.
125125 branch is then renamed after the first message (Settings → Source Control → Worktree
126126 branch naming: a prefix plus a few words, a semantic prefix like `feat/`, or your own
127127 instructions). Ctrl+Shift+L starts in the project's previous worktree instead.
128- - Thread titles written by a small model from the first message (Settings → Text generation).
128+ - Thread titles written by a small model from the first message (Settings → General → Text generation).
129129 - Pin threads to the top, snooze them until later, rename them, archive them to Settings →
130130 Archive. Working threads can fold into a Working shelf until they need you.
131131 - When a usage limit stops a thread, it can snooze until the limit resets and continue then.
@@ -140,27 +140,47 @@ Gruvbox, Rosé Pine, Solarized and Dracula.
140140 another. The host's projects and threads appear in the sidebar tagged with its name; open,
141141 continue or start threads there and they run on the host. The connection is a WebSocket
142142 guarded by the key but not encrypted, so use it on trusted networks or over a VPN.
143- - A settings view (Ctrl+, or **Settings** in the sidebar), laid out like T3 Code's:
144- - **General**: what new threads start with (model, reasoning, permissions, workspace,
145- submodules), the text generation model, projects and threads, organization of the
146- sidebar, and confirmations (unpin, settle, delete, and the quit shortcut).
147- - **Behavior**: notifications (desktop, with sound, in-app), time format, response
148- streaming, turn folding and costs, proactive diffs, diff defaults, the composer (skills in
149- the `/` menu, collapsing on scroll, send key, follow-up behavior), update checks,
150- continuing after restarts, background activity, and the editor "Open in" uses.
151- - **Appearance**: comfortable or compact thread cards.
152- - **Themes**: Light, Dark or System mode (System follows the desktop), and a light and a
153- dark theme picked from live previews: Bone and Graphite; Tokyo Night (Night, Storm, Day);
154- Catppuccin (Mocha, Macchiato, Frappé, Latte); GitHub (Dark, Dark Dimmed, Light); One Dark
155- and One Light; Nord; Gruvbox Dark and Light; Rosé Pine (Main, Moon, Dawn); Solarized Dark
156- and Light; and Dracula.
143+ - A settings view (Ctrl+, or **Settings** in the sidebar), laid out like T3 Code's: a
144+ search field over the pages (press `/` to search, ↑/↓ and Enter to jump to a setting,
145+ which scrolls into view and pulses), a "Settings / Page" breadcrumb, and every setting as
146+ a row with its description, its control and, once changed, a button that resets it.
147+ **Restore device defaults** on General lists what it will reset before it does.
148+ - **General**: New threads (model and reasoning, permissions, workspace, submodules);
149+ Organization (project grouping and order, auto-resume and snooze for usage-limited
150+ threads, the Working section, auto-settling merged and inactive threads); Behavior
151+ (thread notifications off, as notifications, as sound or both, in-app notifications, time
152+ format, response streaming by token, paragraph or whole turn, turn folding and costs, diff
153+ whitespace, file state and Stacked or Split layout, proactive panels, skills in the `/`
154+ menu, the rich text composer, collapsing on scroll, the send shortcut (Enter, Ctrl+Enter
155+ for multiline prompts, or Ctrl+Enter always), follow-up behavior, update checks,
156+ continuing after restarts, background activity); Projects & threads; Confirmations
157+ (unpin, archive, delete, and the quit shortcut: Direct, Hold or Double press); the text
158+ generation model; the version; Diagnostics (CPU, memory and every process the app
159+ started, with interrupt and kill buttons) and the open source licenses; and the folded
160+ Legacy features (plan mode, the context window ring, the per-project sidebar).
161+ - **Appearance**: System, Light or Dark (System follows the desktop), and a card per theme
162+ family whose swatches set the light and the dark theme: Vectrum (Bone and Graphite); Tokyo
163+ Night (Day, Night, Storm); Catppuccin (Latte, Mocha, Macchiato, Frappé); GitHub (Light,
164+ Dark, Dark Dimmed); One; Nord; Gruvbox; Rosé Pine (Dawn, Main, Moon); Solarized; and
165+ Dracula. Then diff colors (red and green, or blue and orange), composer context, chat
166+ width and thread cards.
167+ - **Keybindings**: the app's shortcuts in T3 Code's groups, searchable, read from the live
168+ keymap, with when each applies.
157169 - **Providers**: every agent instance (several Claude, Pi or jcode instances side by side,
158- say two accounts), each with a switch, its version, login and plan, display name, binary, config
159- folder, launch arguments and environment variables, plus updates and the health check
160- interval, and usage hubs (CLIProxyAPI servers, with their management key).
170+ say two accounts) in a list with its status and a switch, and an editor for the selected
171+ one: display name and accent color, account, binary, home folder, Claude's auto-compact
172+ threshold, launch arguments, environment variables (sensitive ones are kept in a
173+ `secrets.json` only you can read), and its models: favorites, which ones the picker
174+ shows, their order, and custom models. **Add provider** walks through kind, identity and
175+ configuration. Below: usage hubs (CLIProxyAPI servers) and the health check interval.
176+ - **Integrations**: whether agents may use the shared browser, and the editor "Open in" uses.
177+ - **Source Control**: the git and GitHub CLI found on this machine, and how worktree
178+ branches are named (a static prefix, a prefix the model picks, or your instructions).
179+ - **Storage**: where new worktrees go, and the app's folders.
180+ - **Connections**: remote connections to and from other devices.
181+ - **Archive**: settled threads by project, with Unarchive (and Delete on right-click).
161182 - **Usage**: cost, tokens and plan limits over the past day, week, month or quarter, read
162183 from Claude Code's and Pi's local logs and any usage hubs, by provider, model and day.
163- - **Connections**, **Keybindings**, an **Archive** of settled threads, and **About**.
164184
165185 ## Requirements
166186
@@ -241,7 +261,12 @@ in its `scratch` folder.
241261 - `src/ui/chat.rs`: start screen, transcript (with turn folding), tool cards, permission bar
242262 and composer.
243263 - `src/ui/pickers.rs`: the model, reasoning and access pickers.
244- - `src/ui/settings.rs`: the settings view and its pages.
264+ - `src/ui/settings/`: the settings view (`mod.rs`: nav, search, top bar), the row and
265+ section building blocks (`widgets.rs`), the search catalog (`search.rs`) and a file per
266+ page.
267+ - `assets/licenses.tsv`: the crates the app is built from, with their licenses, for the
268+ Open source licenses page (regenerate it from `cargo metadata` after changing
269+ dependencies).
245270 - `src/ui/changes.rs`: the per-turn change overview and the diff view.
246271 - `src/ui/workspace.rs`: window root: thread sidebar, top bar and project panel, plus the
247272 git and editor helpers behind it. Its submodules hold the sidebar (`sidebar.rs`, and the
@@ -252,7 +277,7 @@ in its `scratch` folder.
252277 MetalUI's CSS, the theme mapping for the stock widgets, and the primitives (caps, wells,
253278 keycaps, status LEDs, segmented switch).
254279 - `src/ui/themes.rs`: the color schemes, the palette builder that turns each into a full
255- MetalUI palette, the light/dark/system selection, and the Themes page.
280+ MetalUI palette, the light/dark/system selection, and the theme families.
256281 - `assets/fonts/`: Geist, Geist Mono and Geist Pixel, embedded in the binary
257282 (SIL Open Font License, see `assets/fonts/OFL.txt`).
258283
+609−0assets/licenses.tsvaddedView File
@@ -0,0 +1,609 @@
1+ # Crates compiled into Vectrum Code: name, version, license, repository.
2+ # Regenerate with cargo metadata (see src/ui/settings/licenses.rs).
3+ accesskit 0.24.1 MIT OR Apache-2.0 https://github.com/AccessKit/accesskit
4+ accesskit_atspi_common 0.19.1 MIT OR Apache-2.0 https://github.com/AccessKit/accesskit
5+ accesskit_consumer 0.38.0 MIT OR Apache-2.0 https://github.com/AccessKit/accesskit
6+ accesskit_unix 0.22.1 MIT OR Apache-2.0 https://github.com/AccessKit/accesskit
7+ addr2line 0.25.1 Apache-2.0 OR MIT https://github.com/gimli-rs/addr2line
8+ adler2 2.0.1 0BSD OR MIT OR Apache-2.0 https://github.com/oyvindln/adler2
9+ aes 0.8.4 MIT OR Apache-2.0 https://github.com/RustCrypto/block-ciphers
10+ ahash 0.8.12 MIT OR Apache-2.0 https://github.com/tkaitchuck/ahash
11+ aho-corasick 1.1.5 Unlicense OR MIT https://github.com/BurntSushi/aho-corasick
12+ aligned 0.4.3 MIT OR Apache-2.0 https://github.com/rust-embedded-community/aligned
13+ aligned-vec 0.6.4 MIT https://github.com/sarah-ek/aligned-vec/
14+ allocator-api2 0.2.21 MIT OR Apache-2.0 https://github.com/zakarumych/allocator-api2
15+ annotate-snippets 0.12.16 MIT OR Apache-2.0 https://github.com/rust-lang/annotate-snippets-rs
16+ anstyle 1.0.14 MIT OR Apache-2.0 https://github.com/rust-cli/anstyle.git
17+ anyhow 1.0.104 MIT OR Apache-2.0 https://github.com/dtolnay/anyhow
18+ arc-swap 1.9.2 MIT OR Apache-2.0 https://github.com/vorner/arc-swap
19+ arg_enum_proc_macro 0.3.4 MIT https://github.com/lu-zero/arg_enum_proc_macro
20+ arraydeque 0.5.1 MIT OR Apache-2.0 https://github.com/andylokandy/arraydeque
21+ arrayref 0.3.9 BSD-2-Clause https://github.com/droundy/arrayref
22+ arrayvec 0.7.8 MIT OR Apache-2.0 https://github.com/bluss/arrayvec
23+ as-raw-xcb-connection 1.0.1 MIT OR Apache-2.0 https://github.com/psychon/as-raw-xcb-connection
24+ as-slice 0.2.1 MIT OR Apache-2.0 https://github.com/japaric/as-slice
25+ ash 0.38.0+1.3.281 MIT OR Apache-2.0 https://github.com/ash-rs/ash
26+ ashpd 0.13.13 MIT https://github.com/bilelmoussaoui/ashpd
27+ async-broadcast 0.7.2 MIT OR Apache-2.0 https://github.com/smol-rs/async-broadcast
28+ async-channel 2.5.0 Apache-2.0 OR MIT https://github.com/smol-rs/async-channel
29+ async-compression 0.4.50 MIT OR Apache-2.0 https://github.com/Nullus157/async-compression
30+ async-executor 1.14.0 Apache-2.0 OR MIT https://github.com/smol-rs/async-executor
31+ async-fs 2.2.0 Apache-2.0 OR MIT https://github.com/smol-rs/async-fs
32+ async-io 2.6.0 Apache-2.0 OR MIT https://github.com/smol-rs/async-io
33+ async-lock 3.4.2 Apache-2.0 OR MIT https://github.com/smol-rs/async-lock
34+ async-net 2.0.0 Apache-2.0 OR MIT https://github.com/smol-rs/async-net
35+ async-process 2.5.0 Apache-2.0 OR MIT https://github.com/smol-rs/async-process
36+ async-recursion 1.2.0 MIT OR Apache-2.0 https://github.com/dcchut/async-recursion
37+ async-signal 0.2.14 Apache-2.0 OR MIT https://github.com/smol-rs/async-signal
38+ async-task 4.7.1 Apache-2.0 OR MIT https://github.com/smol-rs/async-task
39+ async-trait 0.1.92 MIT OR Apache-2.0 https://github.com/dtolnay/async-trait
40+ atomic 0.5.3 Apache-2.0 OR MIT https://github.com/Amanieu/atomic-rs
41+ atomic-waker 1.1.2 Apache-2.0 OR MIT https://github.com/smol-rs/atomic-waker
42+ atspi 0.29.0 Apache-2.0 OR MIT https://github.com/odilia-app/atspi
43+ atspi-common 0.13.0 Apache-2.0 OR MIT https://github.com/odilia-app/atspi
44+ atspi-proxies 0.13.0 Apache-2.0 OR MIT https://github.com/odilia-app/atspi
45+ autocfg 1.5.1 Apache-2.0 OR MIT https://github.com/cuviper/autocfg
46+ av-scenechange 0.14.1 MIT https://github.com/rust-av/av-scenechange
47+ av1-grain 0.2.5 BSD-2-Clause https://github.com/rust-av/av1-grain
48+ avif-serialize 0.8.9 BSD-3-Clause https://github.com/kornelski/avif-serialize
49+ backtrace 0.3.76 MIT OR Apache-2.0 https://github.com/rust-lang/backtrace-rs
50+ base62 2.2.6 MIT https://github.com/fbernier/base62
51+ base64 0.22.1 MIT OR Apache-2.0 https://github.com/marshallpierce/rust-base64
52+ base64 0.23.1 MIT OR Apache-2.0 https://github.com/marshallpierce/rust-base64
53+ bit-set 0.9.1 Apache-2.0 OR MIT https://github.com/contain-rs/bit-set
54+ bit-vec 0.9.1 Apache-2.0 OR MIT https://github.com/contain-rs/bit-vec
55+ bit_field 0.10.3 Apache-2.0 OR MIT https://github.com/phil-opp/rust-bit-field
56+ bitflags 1.3.2 MIT OR Apache-2.0 https://github.com/bitflags/bitflags
57+ bitflags 2.13.2 MIT OR Apache-2.0 https://github.com/bitflags/bitflags
58+ bitstream-io 4.10.0 MIT OR Apache-2.0 https://github.com/tuffy/bitstream-io
59+ block-buffer 0.10.4 MIT OR Apache-2.0 https://github.com/RustCrypto/utils
60+ block-buffer 0.12.1 MIT OR Apache-2.0 https://github.com/RustCrypto/utils
61+ block-padding 0.3.3 MIT OR Apache-2.0 https://github.com/RustCrypto/utils
62+ blocking 1.7.0 Apache-2.0 OR MIT https://github.com/smol-rs/blocking
63+ bstr 1.13.1 MIT OR Apache-2.0 https://github.com/BurntSushi/bstr
64+ built 0.8.1 MIT https://github.com/lukaslueg/built
65+ bumpalo 3.20.3 MIT OR Apache-2.0 https://github.com/fitzgen/bumpalo
66+ bytemuck 1.25.2 Zlib OR Apache-2.0 OR MIT https://github.com/Lokathor/bytemuck
67+ bytemuck_derive 1.12.1 Zlib OR Apache-2.0 OR MIT https://github.com/Lokathor/bytemuck
68+ byteorder 1.5.0 Unlicense OR MIT https://github.com/BurntSushi/byteorder
69+ byteorder-lite 0.1.0 Unlicense OR MIT https://github.com/image-rs/byteorder-lite
70+ bytes 1.12.1 MIT https://github.com/tokio-rs/bytes
71+ bzip2 0.6.1 MIT OR Apache-2.0 https://github.com/trifectatechfoundation/bzip2-rs
72+ calloop 0.14.5 MIT https://github.com/Smithay/calloop
73+ calloop-wayland-source 0.4.1 MIT https://github.com/smithay/calloop-wayland-source
74+ cbc 0.1.2 MIT OR Apache-2.0 https://github.com/RustCrypto/block-modes
75+ cc 1.6.0 MIT OR Apache-2.0 https://github.com/rust-lang/cc-rs
76+ cfg-if 1.0.5 MIT OR Apache-2.0 https://github.com/rust-lang/cfg-if
77+ cfg_aliases 0.2.2 MIT https://github.com/katharostech/cfg_aliases
78+ chacha20 0.10.2 MIT OR Apache-2.0 https://github.com/RustCrypto/stream-ciphers
79+ chrono 0.4.45 MIT OR Apache-2.0 https://github.com/chronotope/chrono
80+ cipher 0.4.4 MIT OR Apache-2.0 https://github.com/RustCrypto/traits
81+ codespan-reporting 0.13.1 Apache-2.0 https://github.com/brendanzab/codespan
82+ color_quant 1.1.0 MIT https://github.com/image-rs/color_quant.git
83+ compression-codecs 0.4.45 MIT OR Apache-2.0 https://github.com/Nullus157/async-compression
84+ compression-core 0.4.33 MIT OR Apache-2.0 https://github.com/Nullus157/async-compression
85+ concurrent-queue 2.5.0 Apache-2.0 OR MIT https://github.com/smol-rs/concurrent-queue
86+ const-oid 0.10.2 Apache-2.0 OR MIT https://github.com/RustCrypto/formats
87+ const-random 0.1.18 MIT OR Apache-2.0 https://github.com/tkaitchuck/constrandom
88+ const-random-macro 0.1.16 MIT OR Apache-2.0 https://github.com/tkaitchuck/constrandom
89+ convert_case 0.10.0 MIT https://github.com/rutrum/convert-case
90+ core_detect 1.0.0 MIT OR Apache-2.0 https://github.com/thomcc/core_detect
91+ core_maths 0.1.1 MIT https://github.com/robertbastian/core_maths
92+ cosmic-text 0.19.0 MIT OR Apache-2.0 https://github.com/pop-os/cosmic-text
93+ cpufeatures 0.2.17 MIT OR Apache-2.0 https://github.com/RustCrypto/utils
94+ cpufeatures 0.3.1 MIT OR Apache-2.0 https://github.com/RustCrypto/utils
95+ crc32fast 1.5.2 MIT OR Apache-2.0 https://github.com/srijs/rust-crc32fast
96+ crossbeam-deque 0.8.8 MIT OR Apache-2.0 https://github.com/crossbeam-rs/crossbeam
97+ crossbeam-epoch 0.9.21 MIT OR Apache-2.0 https://github.com/crossbeam-rs/crossbeam
98+ crossbeam-queue 0.3.14 MIT OR Apache-2.0 https://github.com/crossbeam-rs/crossbeam
99+ crossbeam-utils 0.8.23 MIT OR Apache-2.0 https://github.com/crossbeam-rs/crossbeam
100+ crunchy 0.2.4 MIT https://github.com/eira-fransham/crunchy
101+ crypto-common 0.1.7 MIT OR Apache-2.0 https://github.com/RustCrypto/traits
102+ crypto-common 0.2.2 MIT OR Apache-2.0 https://github.com/RustCrypto/traits
103+ ctor 1.0.13 Apache-2.0 OR MIT https://github.com/mmastrac/linktime
104+ data-encoding 2.11.1 MIT https://github.com/ia0/data-encoding
105+ data-url 0.3.2 MIT OR Apache-2.0 https://github.com/servo/rust-url
106+ derive_more 2.1.1 MIT https://github.com/JelteF/derive_more
107+ derive_more-impl 2.1.1 MIT https://github.com/JelteF/derive_more
108+ digest 0.10.7 MIT OR Apache-2.0 https://github.com/RustCrypto/traits
109+ digest 0.11.3 MIT OR Apache-2.0 https://github.com/RustCrypto/traits
110+ dirs 5.0.1 MIT OR Apache-2.0 https://github.com/soc/dirs-rs
111+ dirs 6.0.0 MIT OR Apache-2.0 https://github.com/soc/dirs-rs
112+ dirs-sys 0.4.1 MIT OR Apache-2.0 https://github.com/dirs-dev/dirs-sys-rs
113+ dirs-sys 0.5.0 MIT OR Apache-2.0 https://github.com/dirs-dev/dirs-sys-rs
114+ displaydoc 0.2.7 MIT OR Apache-2.0 https://github.com/yaahc/displaydoc
115+ dlib 0.5.3 MIT https://github.com/elinorbgr/dlib
116+ document-features 0.2.12 MIT OR Apache-2.0 https://github.com/slint-ui/document-features
117+ downcast-rs 1.2.1 MIT OR Apache-2.0 https://github.com/marcianx/downcast-rs
118+ dyn-clone 1.0.20 MIT OR Apache-2.0 https://github.com/dtolnay/dyn-clone
119+ either 1.19.0 MIT OR Apache-2.0 https://github.com/rayon-rs/either
120+ embed-resource 3.0.12 MIT https://github.com/nabijaczleweli/rust-embed-resource
121+ encoding_rs 0.8.42 (Apache-2.0 OR MIT) AND BSD-3-Clause https://github.com/hsivonen/encoding_rs
122+ encoding_rs_io 0.1.8 MIT OR Apache-2.0 https://github.com/BurntSushi/encoding_rs_io
123+ endi 1.1.1 MIT https://github.com/zeenix/endi
124+ enum-iterator 2.3.0 0BSD https://github.com/stephaneyfx/enum-iterator.git
125+ enum-iterator-derive 1.5.0 0BSD https://github.com/stephaneyfx/enum-iterator.git
126+ enumflags2 0.7.12 MIT OR Apache-2.0 https://github.com/meithecatte/enumflags2
127+ enumflags2_derive 0.7.12 MIT OR Apache-2.0 https://github.com/meithecatte/enumflags2
128+ enumn 0.1.14 MIT OR Apache-2.0 https://github.com/dtolnay/enumn
129+ equator 0.4.2 MIT https://github.com/sarah-ek/equator/
130+ equator-macro 0.4.2 MIT https://github.com/sarah-ek/equator/
131+ equivalent 1.0.2 Apache-2.0 OR MIT https://github.com/indexmap-rs/equivalent
132+ erased-serde 0.4.10 MIT OR Apache-2.0 https://github.com/dtolnay/erased-serde
133+ errno 0.3.14 MIT OR Apache-2.0 https://github.com/lambda-fairy/rust-errno
134+ etagere 0.2.15 MIT OR Apache-2.0 https://github.com/nical/etagere
135+ euclid 0.22.14 MIT OR Apache-2.0 https://github.com/servo/euclid
136+ event-listener 5.4.2 Apache-2.0 OR MIT https://github.com/smol-rs/event-listener
137+ event-listener-strategy 0.5.4 Apache-2.0 OR MIT https://github.com/smol-rs/event-listener-strategy
138+ exr 1.74.2 BSD-3-Clause https://github.com/johannesvollmer/exrs
139+ fastrand 2.5.0 Apache-2.0 OR MIT https://github.com/smol-rs/fastrand
140+ fax 0.2.7 MIT https://github.com/pdf-rs/fax
141+ fdeflate 0.3.7 MIT OR Apache-2.0 https://github.com/image-rs/fdeflate
142+ filedescriptor 0.8.3 MIT https://github.com/wezterm/wezterm
143+ find-msvc-tools 0.1.14 MIT OR Apache-2.0 https://github.com/rust-lang/cc-rs
144+ fixedbitset 0.5.7 MIT OR Apache-2.0 https://github.com/petgraph/fixedbitset
145+ flate2 1.1.10 MIT OR Apache-2.0 https://github.com/rust-lang/flate2-rs
146+ float-cmp 0.9.0 MIT https://github.com/mikedilger/float-cmp
147+ float-ord 0.3.2 MIT OR Apache-2.0 https://github.com/notriddle/rust-float-ord
148+ float_next_after 1.0.0 MIT https://gitlab.com/bronsonbdevost/next_afterf
149+ fluent-uri 0.1.4 MIT https://github.com/yescallop/fluent-uri-rs
150+ flume 0.12.0 Apache-2.0 OR MIT https://github.com/zesterer/flume
151+ foldhash 0.1.5 Zlib https://github.com/orlp/foldhash
152+ foldhash 0.2.0 Zlib https://github.com/orlp/foldhash
153+ font-types 0.11.3 MIT OR Apache-2.0 https://github.com/googlefonts/fontations
154+ font-types 0.12.6 MIT OR Apache-2.0 https://github.com/googlefonts/fontations
155+ fontconfig-parser 0.5.8 MIT https://github.com/Riey/fontconfig-parser
156+ fontdb 0.23.0 MIT https://github.com/RazrFalcon/fontdb
157+ form_urlencoded 1.2.2 MIT OR Apache-2.0 https://github.com/servo/rust-url
158+ freetype-sys 0.20.1 MIT https://github.com/PistonDevelopers/freetype-sys.git
159+ futf 0.1.5 MIT OR Apache-2.0 https://github.com/servo/futf
160+ futures 0.3.34 MIT OR Apache-2.0 https://github.com/rust-lang/futures-rs
161+ futures-channel 0.3.34 MIT OR Apache-2.0 https://github.com/rust-lang/futures-rs
162+ futures-concurrency 7.7.1 MIT OR Apache-2.0 https://github.com/yoshuawuyts/futures-concurrency
163+ futures-core 0.3.34 MIT OR Apache-2.0 https://github.com/rust-lang/futures-rs
164+ futures-executor 0.3.34 MIT OR Apache-2.0 https://github.com/rust-lang/futures-rs
165+ futures-io 0.3.34 MIT OR Apache-2.0 https://github.com/rust-lang/futures-rs
166+ futures-lite 2.6.1 Apache-2.0 OR MIT https://github.com/smol-rs/futures-lite
167+ futures-macro 0.3.34 MIT OR Apache-2.0 https://github.com/rust-lang/futures-rs
168+ futures-sink 0.3.34 MIT OR Apache-2.0 https://github.com/rust-lang/futures-rs
169+ futures-task 0.3.34 MIT OR Apache-2.0 https://github.com/rust-lang/futures-rs
170+ futures-util 0.3.34 MIT OR Apache-2.0 https://github.com/rust-lang/futures-rs
171+ generic-array 0.14.7 MIT https://github.com/fizyk20/generic-array.git
172+ gethostname 1.1.0 Apache-2.0 https://codeberg.org/swsnr/gethostname.rs.git
173+ getrandom 0.2.17 MIT OR Apache-2.0 https://github.com/rust-random/getrandom
174+ getrandom 0.3.4 MIT OR Apache-2.0 https://github.com/rust-random/getrandom
175+ getrandom 0.4.3 MIT OR Apache-2.0 https://github.com/rust-random/getrandom
176+ gif 0.14.2 MIT OR Apache-2.0 https://github.com/image-rs/image-gif
177+ gimli 0.32.3 MIT OR Apache-2.0 https://github.com/gimli-rs/gimli
178+ glob 0.3.4 MIT OR Apache-2.0 https://github.com/rust-lang/glob
179+ globset 0.4.20 Unlicense OR MIT https://github.com/BurntSushi/ripgrep/tree/master/crates/globset
180+ globwalk 0.8.1 MIT https://github.com/gilnaa/globwalk
181+ glow 0.17.0 MIT OR Apache-2.0 OR Zlib https://github.com/grovesNL/glow
182+ gpu-allocator 0.28.0 MIT OR Apache-2.0 https://github.com/Traverse-Research/gpu-allocator
183+ gpu-descriptor 0.3.2 MIT OR Apache-2.0 https://github.com/zakarumych/gpu-descriptor
184+ gpu-descriptor-types 0.2.0 MIT OR Apache-2.0 https://github.com/zakarumych/gpu-descriptor
185+ gpui-base 0.7.1 Apache-2.0 https://github.com/longbridge/gpui-kit
186+ gpui-component 0.7.1 Apache-2.0 https://github.com/longbridge/gpui-kit
187+ gpui-component-macros 0.7.1 Apache-2.0
188+ gpui-kit 0.7.1 Apache-2.0 https://github.com/longbridge/gpui-kit
189+ gpui-kit-assets 0.7.1 Apache-2.0 https://github.com/longbridge/gpui-kit
190+ gpui-pre 0.3.8 Apache-2.0 https://github.com/zed-industries/zed
191+ gpui-pre-collections 0.3.8 Apache-2.0 https://github.com/zed-industries/zed
192+ gpui-pre-derive-refineable 0.3.8 Apache-2.0 https://github.com/zed-industries/zed
193+ gpui-pre-http-client 0.3.8 Apache-2.0 https://github.com/zed-industries/zed
194+ gpui-pre-linux 0.3.8 Apache-2.0 https://github.com/zed-industries/zed
195+ gpui-pre-macros 0.3.8 Apache-2.0 https://github.com/zed-industries/zed
196+ gpui-pre-perf 0.3.8 Apache-2.0 https://github.com/zed-industries/zed
197+ gpui-pre-platform 0.3.8 Apache-2.0 https://github.com/zed-industries/zed
198+ gpui-pre-refineable 0.3.8 Apache-2.0 https://github.com/zed-industries/zed
199+ gpui-pre-scheduler 0.3.8 Apache-2.0 https://github.com/zed-industries/zed
200+ gpui-pre-shared-string 0.3.8 Apache-2.0 https://github.com/zed-industries/zed
201+ gpui-pre-sum-tree 0.3.8 Apache-2.0 https://github.com/zed-industries/zed
202+ gpui-pre-util 0.3.8 Apache-2.0 https://github.com/zed-industries/zed
203+ gpui-pre-util-macros 0.3.8 Apache-2.0 https://github.com/zed-industries/zed
204+ gpui-pre-wgpu 0.3.8 Apache-2.0 https://github.com/zed-industries/zed
205+ gpui-pre-zlog 0.3.8 Apache-2.0 https://github.com/zed-industries/zed
206+ gpui-pre-ztracing 0.3.8 Apache-2.0 https://github.com/zed-industries/zed
207+ gpui-pre-ztracing-macro 0.3.8 Apache-2.0 https://github.com/zed-industries/zed
208+ granit-parser 1.3.0 MIT OR Apache-2.0 https://github.com/bourumir-wyngs/granit-parser
209+ half 2.7.1 MIT OR Apache-2.0 https://github.com/VoidStarKat/half-rs
210+ harfrust 0.5.2 MIT https://github.com/harfbuzz/harfrust
211+ hash32 0.3.1 MIT OR Apache-2.0 https://github.com/japaric/hash32
212+ hashbrown 0.14.5 MIT OR Apache-2.0 https://github.com/rust-lang/hashbrown
213+ hashbrown 0.15.5 MIT OR Apache-2.0 https://github.com/rust-lang/hashbrown
214+ hashbrown 0.16.1 MIT OR Apache-2.0 https://github.com/rust-lang/hashbrown
215+ hashbrown 0.17.1 MIT OR Apache-2.0 https://github.com/rust-lang/hashbrown
216+ heapless 0.9.3 MIT OR Apache-2.0 https://github.com/rust-embedded/heapless
217+ heck 0.5.0 MIT OR Apache-2.0 https://github.com/withoutboats/heck
218+ hex 0.4.3 MIT OR Apache-2.0 https://github.com/KokaKiwi/rust-hex
219+ hexf-parse 0.2.1 CC0-1.0 https://github.com/lifthrasiir/hexf
220+ hkdf 0.12.4 MIT OR Apache-2.0 https://github.com/RustCrypto/KDFs/
221+ hmac 0.12.1 MIT OR Apache-2.0 https://github.com/RustCrypto/MACs
222+ html5ever 0.27.0 MIT OR Apache-2.0 https://github.com/servo/html5ever
223+ http 1.5.0 MIT OR Apache-2.0 https://github.com/hyperium/http
224+ http-body 1.1.0 MIT https://github.com/hyperium/http-body
225+ httparse 1.10.1 MIT OR Apache-2.0 https://github.com/seanmonstar/httparse
226+ hybrid-array 0.4.15 MIT OR Apache-2.0 https://github.com/RustCrypto/hybrid-array
227+ iana-time-zone 0.1.65 MIT OR Apache-2.0 https://github.com/strawlab/iana-time-zone
228+ icu_collections 2.3.0 Unicode-3.0 https://github.com/unicode-org/icu4x
229+ icu_locale_core 2.3.0 Unicode-3.0 https://github.com/unicode-org/icu4x
230+ icu_normalizer 2.3.0 Unicode-3.0 https://github.com/unicode-org/icu4x
231+ icu_normalizer_data 2.3.0 Unicode-3.0 https://github.com/unicode-org/icu4x
232+ icu_properties 2.3.0 Unicode-3.0 https://github.com/unicode-org/icu4x
233+ icu_properties_data 2.3.0 Unicode-3.0 https://github.com/unicode-org/icu4x
234+ icu_provider 2.3.1 Unicode-3.0 https://github.com/unicode-org/icu4x
235+ idna 1.1.0 MIT OR Apache-2.0 https://github.com/servo/rust-url/
236+ idna_adapter 1.2.2 Apache-2.0 OR MIT https://github.com/hsivonen/idna_adapter
237+ ignore 0.4.33 Unlicense OR MIT https://github.com/BurntSushi/ripgrep/tree/master/crates/ignore
238+ image 0.25.10 MIT OR Apache-2.0 https://github.com/image-rs/image
239+ image-webp 0.2.4 MIT OR Apache-2.0 https://github.com/image-rs/image-webp
240+ imagesize 0.14.0 MIT https://github.com/Roughsketch/imagesize
241+ imgref 1.12.3 CC0-1.0 OR Apache-2.0 https://github.com/kornelski/imgref
242+ indexmap 2.14.2 Apache-2.0 OR MIT https://github.com/indexmap-rs/indexmap
243+ inotify 0.11.5 ISC https://github.com/hannobraun/inotify-rs
244+ inotify-sys 0.1.8 ISC https://github.com/hannobraun/inotify-sys
245+ inout 0.1.4 MIT OR Apache-2.0 https://github.com/RustCrypto/utils
246+ instant 0.1.13 BSD-3-Clause https://github.com/sebcrozet/instant
247+ inventory 0.3.25 MIT OR Apache-2.0 https://github.com/dtolnay/inventory
248+ is-docker 0.2.0 MIT https://github.com/TheLarkInn/is-docker
249+ is-wsl 0.4.0 MIT https://github.com/TheLarkInn/is-wsl
250+ itertools 0.11.0 MIT OR Apache-2.0 https://github.com/rust-itertools/itertools
251+ itertools 0.13.0 MIT OR Apache-2.0 https://github.com/rust-itertools/itertools
252+ itertools 0.14.0 MIT OR Apache-2.0 https://github.com/rust-itertools/itertools
253+ itoa 1.0.18 MIT OR Apache-2.0 https://github.com/dtolnay/itoa
254+ jobserver 0.1.35 MIT OR Apache-2.0 https://github.com/rust-lang/jobserver-rs
255+ khronos-egl 6.0.0 MIT OR Apache-2.0 https://github.com/timothee-haudebourg/khronos-egl
256+ kurbo 0.13.1 Apache-2.0 OR MIT https://github.com/linebender/kurbo
257+ lazy_static 1.5.1 MIT OR Apache-2.0 https://github.com/rust-lang-nursery/lazy-static.rs
258+ lebe 0.5.3 BSD-3-Clause https://github.com/johannesvollmer/lebe
259+ libbz2-rs-sys 0.2.5 bzip2-1.0.6 https://github.com/trifectatechfoundation/libbzip2-rs
260+ libc 0.2.190 MIT OR Apache-2.0 https://github.com/rust-lang/libc
261+ libloading 0.8.9 ISC https://github.com/nagisa/rust_libloading/
262+ libm 0.2.16 MIT https://github.com/rust-lang/compiler-builtins
263+ linebender_resource_handle 0.1.1 Apache-2.0 OR MIT https://github.com/linebender/raw_resource_handle
264+ link-section 0.19.3 Apache-2.0 OR MIT https://github.com/mmastrac/linktime
265+ linktime-proc-macro 0.2.3 Apache-2.0 OR MIT https://github.com/mmastrac/linktime
266+ linux-raw-sys 0.12.1 Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT https://github.com/sunfishcode/linux-raw-sys
267+ litemap 0.8.3 Unicode-3.0 https://github.com/unicode-org/icu4x
268+ litrs 1.0.0 MIT OR Apache-2.0 https://github.com/LukasKalbertodt/litrs
269+ lock_api 0.4.14 MIT OR Apache-2.0 https://github.com/Amanieu/parking_lot
270+ log 0.4.34 MIT OR Apache-2.0 https://github.com/rust-lang/log
271+ loop9 0.1.5 MIT https://gitlab.com/kornelski/loop9.git
272+ lsp-types 0.97.0 MIT https://github.com/gluon-lang/lsp-types
273+ lyon 1.0.19 MIT OR Apache-2.0 https://github.com/nical/lyon
274+ lyon_algorithms 1.0.21 MIT OR Apache-2.0 https://github.com/nical/lyon
275+ lyon_geom 1.0.19 MIT OR Apache-2.0 https://github.com/nical/lyon
276+ lyon_path 1.0.19 MIT OR Apache-2.0 https://github.com/nical/lyon
277+ lyon_tessellation 1.0.22 MIT OR Apache-2.0 https://github.com/nical/lyon
278+ mac 0.1.1 MIT OR Apache-2.0 https://github.com/reem/rust-mac.git
279+ markdown 1.0.0 MIT https://github.com/wooorm/markdown-rs
280+ markup5ever 0.12.1 MIT OR Apache-2.0 https://github.com/servo/html5ever
281+ markup5ever_rcdom 0.3.0 MIT OR Apache-2.0 https://github.com/servo/html5ever
282+ maybe-rayon 0.1.1 MIT https://github.com/shssoichiro/maybe-rayon
283+ md-5 0.10.6 MIT OR Apache-2.0 https://github.com/RustCrypto/hashes
284+ memchr 2.8.3 Unlicense OR MIT https://github.com/BurntSushi/memchr
285+ memmap2 0.9.11 MIT OR Apache-2.0 https://github.com/RazrFalcon/memmap2-rs
286+ mime 0.3.17 MIT OR Apache-2.0 https://github.com/hyperium/mime
287+ mime_guess 2.0.5 MIT https://github.com/abonander/mime_guess
288+ miniz_oxide 0.8.9 MIT OR Zlib OR Apache-2.0 https://github.com/Frommi/miniz_oxide/tree/master/miniz_oxide
289+ miniz_oxide 0.9.1 MIT OR Zlib OR Apache-2.0 https://github.com/Frommi/miniz_oxide/tree/master/miniz_oxide
290+ mio 1.2.4 MIT https://github.com/tokio-rs/mio
291+ moxcms 0.8.1 BSD-3-Clause OR Apache-2.0 https://github.com/awxkee/moxcms.git
292+ multiversion_no_op 1.0.0 Apache-2.0 OR MIT https://github.com/hsivonen/multiversion_no_op
293+ naga 29.0.4 MIT OR Apache-2.0 https://github.com/gfx-rs/wgpu
294+ new_debug_unreachable 1.0.6 MIT https://github.com/mbrubeck/rust-debug-unreachable
295+ no_std_io2 0.9.4 Apache-2.0 OR MIT https://github.com/wcampbell0x2a/no-std-io2
296+ nohash-hasher 0.2.0 Apache-2.0 OR MIT https://github.com/paritytech/nohash-hasher
297+ nom 8.0.0 MIT https://github.com/rust-bakery/nom
298+ noop_proc_macro 0.3.0 MIT https://github.com/lu-zero/noop_proc_macro
299+ normpath 1.5.2 MIT OR Apache-2.0 https://github.com/dylni/normpath
300+ notify 8.2.0 CC0-1.0 https://github.com/notify-rs/notify.git
301+ notify-rust 4.18.2 MIT OR Apache-2.0 https://github.com/hoodie/notify-rust
302+ notify-types 2.1.0 MIT OR Apache-2.0 https://github.com/notify-rs/notify.git
303+ nu-ansi-term 0.50.3 MIT https://github.com/nushell/nu-ansi-term
304+ num 0.4.3 MIT OR Apache-2.0 https://github.com/rust-num/num
305+ num-bigint 0.4.8 MIT OR Apache-2.0 https://github.com/rust-num/num-bigint
306+ num-bigint-dig 0.9.1 MIT OR Apache-2.0 https://github.com/dignifiedquire/num-bigint
307+ num-complex 0.4.6 MIT OR Apache-2.0 https://github.com/rust-num/num-complex
308+ num-derive 0.4.2 MIT OR Apache-2.0 https://github.com/rust-num/num-derive
309+ num-integer 0.1.47 MIT OR Apache-2.0 https://github.com/rust-num/num-integer
310+ num-iter 0.1.46 MIT OR Apache-2.0 https://github.com/rust-num/num-iter
311+ num-rational 0.4.2 MIT OR Apache-2.0 https://github.com/rust-num/num-rational
312+ num-traits 0.2.19 MIT OR Apache-2.0 https://github.com/rust-num/num-traits
313+ num_cpus 1.17.0 MIT OR Apache-2.0 https://github.com/seanmonstar/num_cpus
314+ object 0.37.3 Apache-2.0 OR MIT https://github.com/gimli-rs/object
315+ once_cell 1.21.4 MIT OR Apache-2.0 https://github.com/matklad/once_cell
316+ oo7 0.6.0 MIT https://github.com/linux-credentials/oo7
317+ open 5.4.4 MIT https://github.com/Byron/open-rs
318+ option-ext 0.2.0 MPL-2.0 https://github.com/soc/option-ext.git
319+ ordered-float 5.5.0 MIT https://github.com/reem/rust-ordered-float
320+ ordered-stream 0.2.0 MIT OR Apache-2.0 https://github.com/danieldg/ordered-stream
321+ parking 2.2.1 Apache-2.0 OR MIT https://github.com/smol-rs/parking
322+ parking_lot 0.12.5 MIT OR Apache-2.0 https://github.com/Amanieu/parking_lot
323+ parking_lot_core 0.9.12 MIT OR Apache-2.0 https://github.com/Amanieu/parking_lot
324+ paste 1.0.15 MIT OR Apache-2.0 https://github.com/dtolnay/paste
325+ pastey 0.1.1 MIT OR Apache-2.0 https://github.com/as1100k/pastey
326+ pathfinder_geometry 0.5.1 MIT OR Apache-2.0 https://github.com/servo/pathfinder
327+ pathfinder_simd 0.5.6 MIT OR Apache-2.0 https://github.com/servo/pathfinder
328+ pbkdf2 0.12.2 MIT OR Apache-2.0 https://github.com/RustCrypto/password-hashes/tree/master/pbkdf2
329+ percent-encoding 2.3.2 MIT OR Apache-2.0 https://github.com/servo/rust-url/
330+ phf 0.11.3 MIT https://github.com/rust-phf/rust-phf
331+ phf 0.13.1 MIT https://github.com/rust-phf/rust-phf
332+ phf_codegen 0.11.3 MIT https://github.com/rust-phf/rust-phf
333+ phf_generator 0.11.3 MIT https://github.com/rust-phf/rust-phf
334+ phf_generator 0.13.1 MIT https://github.com/rust-phf/rust-phf
335+ phf_macros 0.13.1 MIT https://github.com/rust-phf/rust-phf
336+ phf_shared 0.11.3 MIT https://github.com/rust-phf/rust-phf
337+ phf_shared 0.13.1 MIT https://github.com/rust-phf/rust-phf
338+ pico-args 0.5.0 MIT https://github.com/RazrFalcon/pico-args
339+ pin-project 1.1.13 Apache-2.0 OR MIT https://github.com/taiki-e/pin-project
340+ pin-project-internal 1.1.13 Apache-2.0 OR MIT https://github.com/taiki-e/pin-project
341+ pin-project-lite 0.2.17 Apache-2.0 OR MIT https://github.com/taiki-e/pin-project-lite
342+ piper 0.2.5 MIT OR Apache-2.0 https://github.com/smol-rs/piper
343+ pkg-config 0.3.34 MIT OR Apache-2.0 https://github.com/rust-lang/pkg-config-rs
344+ png 0.17.16 MIT OR Apache-2.0 https://github.com/image-rs/image-png
345+ png 0.18.1 MIT OR Apache-2.0 https://github.com/image-rs/image-png
346+ polling 3.11.0 Apache-2.0 OR MIT https://github.com/smol-rs/polling
347+ pollster 0.2.5 Apache-2.0 OR MIT https://github.com/zesterer/pollster
348+ pollster 0.4.0 Apache-2.0 OR MIT https://github.com/zesterer/pollster
349+ polycool 0.4.0 MIT OR Apache-2.0 https://github.com/linebender/kurbo
350+ postage 0.5.0 MIT https://github.com/austinjones/postage-rs
351+ potential_utf 0.1.6 Unicode-3.0 https://github.com/unicode-org/icu4x
352+ ppv-lite86 0.2.21 MIT OR Apache-2.0 https://github.com/cryptocorrosion/cryptocorrosion
353+ precomputed-hash 0.1.1 MIT https://github.com/emilio/precomputed-hash
354+ presser 0.3.1 MIT OR Apache-2.0 https://github.com/EmbarkStudios/presser
355+ proc-macro-crate 3.5.0 MIT OR Apache-2.0 https://github.com/bkchr/proc-macro-crate
356+ proc-macro2 1.0.107 MIT OR Apache-2.0 https://github.com/dtolnay/proc-macro2
357+ profiling 1.0.18 MIT OR Apache-2.0 https://github.com/aclysma/profiling
358+ profiling-procmacros 1.0.18 MIT OR Apache-2.0 https://github.com/aclysma/profiling
359+ pulp 0.22.3 MIT https://github.com/sarah-quinones/pulp/
360+ pulp-wasm-simd-flag 0.1.1 MIT https://github.com/sarah-quinones/pulp/
361+ pxfm 0.1.30 BSD-3-Clause OR Apache-2.0 https://github.com/awxkee/pxfm
362+ qoi 0.4.1 MIT OR Apache-2.0 https://github.com/aldanor/qoi-rust
363+ quick-error 2.0.1 MIT OR Apache-2.0 http://github.com/tailhook/quick-error
364+ quick-xml 0.41.0 MIT https://github.com/tafia/quick-xml
365+ quote 1.0.47 MIT OR Apache-2.0 https://github.com/dtolnay/quote
366+ rand 0.10.3 MIT OR Apache-2.0 https://github.com/rust-random/rand
367+ rand 0.8.8 MIT OR Apache-2.0 https://github.com/rust-random/rand
368+ rand 0.9.5 MIT OR Apache-2.0 https://github.com/rust-random/rand
369+ rand_chacha 0.3.1 MIT OR Apache-2.0 https://github.com/rust-random/rand
370+ rand_chacha 0.9.0 MIT OR Apache-2.0 https://github.com/rust-random/rand
371+ rand_core 0.10.1 MIT OR Apache-2.0 https://github.com/rust-random/rand_core
372+ rand_core 0.6.4 MIT OR Apache-2.0 https://github.com/rust-random/rand
373+ rand_core 0.9.5 MIT OR Apache-2.0 https://github.com/rust-random/rand
374+ rangemap 1.8.0 MIT OR Apache-2.0 https://github.com/jeffparsons/rangemap
375+ rav1e 0.8.1 BSD-2-Clause https://github.com/xiph/rav1e/
376+ ravif 0.13.0 BSD-3-Clause https://github.com/kornelski/cavif-rs
377+ raw-cpuid 11.6.0 MIT https://github.com/gz/rust-cpuid
378+ raw-window-handle 0.6.2 MIT OR Apache-2.0 OR Zlib https://github.com/rust-windowing/raw-window-handle
379+ rayon 1.12.0 MIT OR Apache-2.0 https://github.com/rayon-rs/rayon
380+ rayon-core 1.13.0 MIT OR Apache-2.0 https://github.com/rayon-rs/rayon
381+ read-fonts 0.37.0 MIT OR Apache-2.0 https://github.com/googlefonts/fontations
382+ read-fonts 0.41.0 MIT OR Apache-2.0 https://github.com/googlefonts/fontations
383+ reborrow 0.5.5 MIT https://github.com/sarah-ek/reborrow/
384+ ref-cast 1.0.27 MIT OR Apache-2.0 https://github.com/dtolnay/ref-cast
385+ ref-cast-impl 1.0.27 MIT OR Apache-2.0 https://github.com/dtolnay/ref-cast
386+ regex 1.13.1 MIT OR Apache-2.0 https://github.com/rust-lang/regex
387+ regex-automata 0.4.18 MIT OR Apache-2.0 https://github.com/rust-lang/regex
388+ regex-syntax 0.8.11 MIT OR Apache-2.0 https://github.com/rust-lang/regex
389+ renderdoc-sys 1.1.0 MIT OR Apache-2.0 https://github.com/ebkalderon/renderdoc-rs
390+ resvg 0.46.0 Apache-2.0 OR MIT https://github.com/linebender/resvg
391+ rgb 0.8.53 MIT https://github.com/kornelski/rust-rgb
392+ ring 0.17.14 Apache-2.0 AND ISC https://github.com/briansmith/ring
393+ ropey 2.0.0-beta.1 MIT OR Apache-2.0 https://github.com/cessen/ropey
394+ roxmltree 0.20.0 MIT OR Apache-2.0 https://github.com/RazrFalcon/roxmltree
395+ roxmltree 0.21.1 MIT OR Apache-2.0 https://github.com/RazrFalcon/roxmltree
396+ rust-embed 8.13.0 MIT https://pyrossh.dev/repos/rust-embed
397+ rust-embed-impl 8.13.0 MIT https://pyrossh.dev/repos/rust-embed
398+ rust-embed-utils 8.13.0 MIT https://pyrossh.dev/repos/rust-embed
399+ rust-i18n 4.2.4 MIT https://github.com/longbridge/rust-i18n
400+ rust-i18n-macro 4.2.4 MIT https://github.com/longbridge/rust-i18n
401+ rust-i18n-support 4.2.4 MIT https://github.com/longbridge/rust-i18n
402+ rustc-demangle 0.1.28 MIT OR Apache-2.0 https://github.com/rust-lang/rustc-demangle
403+ rustc-hash 1.1.0 Apache-2.0 OR MIT https://github.com/rust-lang-nursery/rustc-hash
404+ rustc-hash 2.1.3 Apache-2.0 OR MIT https://github.com/rust-lang/rustc-hash
405+ rustc_version 0.4.1 MIT OR Apache-2.0 https://github.com/djc/rustc-version-rs
406+ rustix 1.1.5 Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT https://github.com/bytecodealliance/rustix
407+ rustls 0.23.45 Apache-2.0 OR ISC OR MIT https://github.com/rustls/rustls
408+ rustls-pki-types 1.15.1 MIT OR Apache-2.0 https://github.com/rustls/pki-types
409+ rustls-webpki 0.103.15 ISC https://github.com/rustls/webpki
410+ rustversion 1.0.23 MIT OR Apache-2.0 https://github.com/dtolnay/rustversion
411+ rustybuzz 0.20.1 MIT https://github.com/harfbuzz/rustybuzz
412+ ryu 1.0.23 Apache-2.0 OR BSL-1.0 https://github.com/dtolnay/ryu
413+ same-file 1.0.6 Unlicense OR MIT https://github.com/BurntSushi/same-file
414+ schemars 1.2.2 MIT https://github.com/GREsau/schemars
415+ schemars_derive 1.2.2 MIT https://github.com/GREsau/schemars
416+ scoped-tls 1.0.1 MIT OR Apache-2.0 https://github.com/alexcrichton/scoped-tls
417+ scopeguard 1.2.0 MIT OR Apache-2.0 https://github.com/bluss/scopeguard
418+ seahash 4.1.0 MIT https://gitlab.redox-os.org/redox-os/seahash
419+ self_cell 1.3.0 Apache-2.0 OR GPL-2.0-only https://github.com/Voultapher/self_cell
420+ semver 1.0.28 MIT OR Apache-2.0 https://github.com/dtolnay/semver
421+ serde 1.0.229 MIT OR Apache-2.0 https://github.com/serde-rs/serde
422+ serde-saphyr 1.3.0 MIT OR Apache-2.0 https://github.com/bourumir-wyngs/serde-saphyr
423+ serde_bytes 0.11.19 MIT OR Apache-2.0 https://github.com/serde-rs/bytes
424+ serde_core 1.0.229 MIT OR Apache-2.0 https://github.com/serde-rs/serde
425+ serde_derive 1.0.229 MIT OR Apache-2.0 https://github.com/serde-rs/serde
426+ serde_derive_internals 0.30.0 MIT OR Apache-2.0 https://github.com/serde-rs/serde
427+ serde_fmt 1.1.0 Apache-2.0 OR MIT https://github.com/KodrAus/serde_fmt.git
428+ serde_json 1.0.151 MIT OR Apache-2.0 https://github.com/serde-rs/json
429+ serde_repr 0.1.21 MIT OR Apache-2.0 https://github.com/dtolnay/serde-repr
430+ serde_spanned 0.6.9 MIT OR Apache-2.0 https://github.com/toml-rs/toml
431+ serde_spanned 1.1.2 MIT OR Apache-2.0 https://github.com/toml-rs/toml
432+ serde_urlencoded 0.7.1 MIT OR Apache-2.0 https://github.com/nox/serde_urlencoded
433+ sha1 0.11.0 MIT OR Apache-2.0 https://github.com/RustCrypto/hashes
434+ sha1_smol 1.0.1 BSD-3-Clause https://github.com/mitsuhiko/sha1-smol
435+ sha2 0.10.9 MIT OR Apache-2.0 https://github.com/RustCrypto/hashes
436+ sha2 0.11.0 MIT OR Apache-2.0 https://github.com/RustCrypto/hashes
437+ sharded-slab 0.1.7 MIT https://github.com/hawkw/sharded-slab
438+ shellexpand 3.1.2 MIT OR Apache-2.0 https://gitlab.com/ijackson/rust-shellexpand
439+ shlex 2.0.1 MIT OR Apache-2.0 https://github.com/comex/rust-shlex
440+ signal-hook-registry 1.4.8 MIT OR Apache-2.0 https://github.com/vorner/signal-hook
441+ simd-adler32 0.3.10 MIT https://github.com/mcountryman/simd-adler32
442+ simd_helpers 0.1.0 MIT https://github.com/lu-zero/simd_helpers
443+ simdutf8 0.1.5 MIT OR Apache-2.0 https://github.com/rusticstuff/simdutf8
444+ simplecss 0.2.2 Apache-2.0 OR MIT https://github.com/linebender/simplecss
445+ siphasher 1.0.4 MIT OR Apache-2.0 https://github.com/jedisct1/rust-siphash
446+ skrifa 0.40.0 MIT OR Apache-2.0 https://github.com/googlefonts/fontations
447+ skrifa 0.44.0 MIT OR Apache-2.0 https://github.com/googlefonts/fontations
448+ slab 0.4.12 MIT https://github.com/tokio-rs/slab
449+ slotmap 1.1.1 Zlib https://github.com/orlp/slotmap
450+ smallvec 1.16.2 MIT OR Apache-2.0 https://github.com/servo/rust-smallvec
451+ smol 2.0.2 Apache-2.0 OR MIT https://github.com/smol-rs/smol
452+ smol_str 0.3.6 MIT OR Apache-2.0 https://github.com/rust-lang/rust-analyzer/tree/master/lib/smol_str
453+ spin 0.10.1 MIT https://github.com/mvdnes/spin-rs.git
454+ spin 0.9.9 MIT https://github.com/mvdnes/spin-rs.git
455+ spirv 0.4.0+sdk-1.4.341.0 Apache-2.0 https://github.com/gfx-rs/rspirv
456+ stable_deref_trait 1.2.1 MIT OR Apache-2.0 https://github.com/storyyeller/stable_deref_trait
457+ static_assertions 1.1.0 MIT OR Apache-2.0 https://github.com/nvzqz/static-assertions-rs
458+ str_indices 0.4.4 MIT OR Apache-2.0 https://github.com/cessen/str_indices
459+ strict-num 0.1.1 MIT https://github.com/RazrFalcon/strict-num
460+ string_cache 0.8.9 MIT OR Apache-2.0 https://github.com/servo/string-cache
461+ string_cache_codegen 0.5.4 MIT OR Apache-2.0 https://github.com/servo/string-cache
462+ strum 0.28.0 MIT https://github.com/Peternator7/strum
463+ strum_macros 0.28.0 MIT https://github.com/Peternator7/strum
464+ subtle 2.6.1 BSD-3-Clause https://github.com/dalek-cryptography/subtle
465+ sval 2.22.0 Apache-2.0 OR MIT https://github.com/sval-rs/sval
466+ sval_buffer 2.22.0 Apache-2.0 OR MIT https://github.com/sval-rs/sval
467+ sval_dynamic 2.22.0 Apache-2.0 OR MIT https://github.com/sval-rs/sval
468+ sval_fmt 2.22.0 Apache-2.0 OR MIT https://github.com/sval-rs/sval
469+ sval_json 2.22.0 Apache-2.0 OR MIT https://github.com/sval-rs/sval
470+ sval_nested 2.22.0 Apache-2.0 OR MIT https://github.com/sval-rs/sval
471+ sval_ref 2.22.0 Apache-2.0 OR MIT https://github.com/sval-rs/sval
472+ sval_serde 2.22.0 Apache-2.0 OR MIT https://github.com/sval-rs/sval
473+ svg_fmt 0.4.5 MIT OR Apache-2.0 https://github.com/nical/rust_debug
474+ svgtypes 0.16.1 Apache-2.0 OR MIT https://github.com/linebender/svgtypes
475+ swash 0.2.10 Apache-2.0 OR MIT https://github.com/dfrg/swash
476+ syn 2.0.119 MIT OR Apache-2.0 https://github.com/dtolnay/syn
477+ syn 3.0.6 MIT OR Apache-2.0 https://github.com/dtolnay/syn
478+ synstructure 0.14.0 MIT https://github.com/mystor/synstructure
479+ sys-locale 0.3.2 MIT OR Apache-2.0 https://github.com/1Password/sys-locale
480+ sysinfo 0.31.4 MIT https://github.com/GuillaumeGomez/sysinfo
481+ taffy 0.13.0 MIT https://github.com/DioxusLabs/taffy
482+ tendril 0.4.3 MIT OR Apache-2.0 https://github.com/servo/tendril
483+ termcolor 1.4.1 Unlicense OR MIT https://github.com/BurntSushi/termcolor
484+ thiserror 1.0.69 MIT OR Apache-2.0 https://github.com/dtolnay/thiserror
485+ thiserror 2.0.21 MIT OR Apache-2.0 https://github.com/dtolnay/thiserror
486+ thiserror-impl 1.0.69 MIT OR Apache-2.0 https://github.com/dtolnay/thiserror
487+ thiserror-impl 2.0.21 MIT OR Apache-2.0 https://github.com/dtolnay/thiserror
488+ thread_local 1.1.10 MIT OR Apache-2.0 https://github.com/Amanieu/thread_local-rs
489+ tiff 0.11.3 MIT https://github.com/image-rs/image-tiff
490+ tiny-keccak 2.0.2 CC0-1.0
491+ tiny-skia 0.11.4 BSD-3-Clause https://github.com/RazrFalcon/tiny-skia
492+ tiny-skia-path 0.11.4 BSD-3-Clause https://github.com/RazrFalcon/tiny-skia/tree/master/path
493+ tinystr 0.8.4 Unicode-3.0 https://github.com/unicode-org/icu4x
494+ tinyvec 1.13.3 Zlib OR Apache-2.0 OR MIT https://github.com/Lokathor/tinyvec
495+ toml 0.8.23 MIT OR Apache-2.0 https://github.com/toml-rs/toml
496+ toml 1.1.8+spec-1.1.0 MIT OR Apache-2.0 https://github.com/toml-rs/toml
497+ toml_datetime 0.6.11 MIT OR Apache-2.0 https://github.com/toml-rs/toml
498+ toml_datetime 1.1.2+spec-1.1.0 MIT OR Apache-2.0 https://github.com/toml-rs/toml
499+ toml_edit 0.22.27 MIT OR Apache-2.0 https://github.com/toml-rs/toml
500+ toml_edit 0.25.17+spec-1.1.0 MIT OR Apache-2.0 https://github.com/toml-rs/toml
501+ toml_parser 1.1.5+spec-1.1.0 MIT OR Apache-2.0 https://github.com/toml-rs/toml
502+ toml_write 0.1.2 MIT OR Apache-2.0 https://github.com/toml-rs/toml
503+ toml_writer 1.1.3+spec-1.1.0 MIT OR Apache-2.0 https://github.com/toml-rs/toml
504+ tracing 0.1.44 MIT https://github.com/tokio-rs/tracing
505+ tracing-attributes 0.1.31 MIT https://github.com/tokio-rs/tracing
506+ tracing-core 0.1.36 MIT https://github.com/tokio-rs/tracing
507+ tracing-log 0.2.0 MIT https://github.com/tokio-rs/tracing
508+ tracing-subscriber 0.3.23 MIT https://github.com/tokio-rs/tracing
509+ triomphe 0.1.16 MIT OR Apache-2.0 https://github.com/Manishearth/triomphe
510+ ttf-parser 0.25.1 MIT OR Apache-2.0 https://github.com/harfbuzz/ttf-parser
511+ tungstenite 0.30.0 MIT OR Apache-2.0 https://github.com/snapview/tungstenite-rs
512+ typeid 1.0.3 MIT OR Apache-2.0 https://github.com/dtolnay/typeid
513+ typenum 1.20.1 MIT OR Apache-2.0 https://github.com/paholg/typenum
514+ unicase 2.10.0 MIT OR Apache-2.0 https://github.com/seanmonstar/unicase
515+ unicode-bidi 0.3.18 MIT OR Apache-2.0 https://github.com/servo/unicode-bidi
516+ unicode-bidi-mirroring 0.4.0 MIT OR Apache-2.0 https://github.com/RazrFalcon/unicode-bidi-mirroring
517+ unicode-ccc 0.4.0 MIT OR Apache-2.0 https://github.com/RazrFalcon/unicode-ccc
518+ unicode-id 0.3.7 MIT OR Apache-2.0 https://github.com/Boshen/unicode-id
519+ unicode-ident 1.0.26 (MIT OR Apache-2.0) AND Unicode-3.0 https://github.com/dtolnay/unicode-ident
520+ unicode-linebreak 0.1.5 Apache-2.0 https://github.com/axelf4/unicode-linebreak
521+ unicode-properties 0.1.4 MIT OR Apache-2.0 https://github.com/unicode-rs/unicode-properties
522+ unicode-script 0.5.8 MIT OR Apache-2.0 https://github.com/unicode-rs/unicode-script
523+ unicode-segmentation 1.13.3 MIT OR Apache-2.0 https://github.com/unicode-rs/unicode-segmentation
524+ unicode-vo 0.1.0 MIT OR Apache-2.0 https://github.com/RazrFalcon/unicode-vo
525+ unicode-width 0.2.2 MIT OR Apache-2.0 https://github.com/unicode-rs/unicode-width
526+ unicode-xid 0.2.6 MIT OR Apache-2.0 https://github.com/unicode-rs/unicode-xid
527+ untrusted 0.9.0 ISC https://github.com/briansmith/untrusted
528+ ureq 2.12.1 MIT OR Apache-2.0 https://github.com/algesten/ureq
529+ url 2.5.8 MIT OR Apache-2.0 https://github.com/servo/rust-url
530+ usvg 0.46.0 Apache-2.0 OR MIT https://github.com/linebender/resvg
531+ utf-8 0.7.6 MIT OR Apache-2.0 https://github.com/SimonSapin/rust-utf8
532+ utf8_iter 1.0.4 Apache-2.0 OR MIT https://github.com/hsivonen/utf8_iter
533+ uuid 1.27.0 Apache-2.0 OR MIT https://github.com/uuid-rs/uuid
534+ v_frame 0.3.9 BSD-2-Clause https://github.com/rust-av/v_frame
535+ value-bag 1.14.1 Apache-2.0 OR MIT https://github.com/sval-rs/value-bag
536+ value-bag-serde1 1.14.1 Apache-2.0 OR MIT
537+ value-bag-sval2 1.14.1 Apache-2.0 OR MIT
538+ version_check 0.9.5 MIT OR Apache-2.0 https://github.com/SergioBenitez/version_check
539+ waker-fn 1.2.0 Apache-2.0 OR MIT https://github.com/smol-rs/waker-fn
540+ walkdir 2.5.0 Unlicense OR MIT https://github.com/BurntSushi/walkdir
541+ wasm-bindgen 0.2.129 MIT OR Apache-2.0 https://github.com/wasm-bindgen/wasm-bindgen
542+ wasm-bindgen-macro 0.2.129 MIT OR Apache-2.0 https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/macro
543+ wasm-bindgen-macro-support 0.2.129 MIT OR Apache-2.0 https://github.com/wasm-bindgen/wasm-bindgen/tree/main/crates/macro-support
544+ wasm-bindgen-shared 0.2.129 MIT OR Apache-2.0 https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/shared
545+ wayland-backend 0.3.17 MIT https://github.com/smithay/wayland-rs
546+ wayland-client 0.31.15 MIT https://github.com/smithay/wayland-rs
547+ wayland-cursor 0.31.14 MIT https://github.com/smithay/wayland-rs
548+ wayland-protocols 0.32.13 MIT https://github.com/smithay/wayland-rs
549+ wayland-protocols-plasma 0.3.12 MIT https://github.com/smithay/wayland-rs
550+ wayland-protocols-wlr 0.3.12 MIT https://github.com/smithay/wayland-rs
551+ wayland-scanner 0.31.11 MIT https://github.com/smithay/wayland-rs
552+ wayland-sys 0.31.11 MIT https://github.com/smithay/wayland-rs
553+ web-time 1.1.0 MIT OR Apache-2.0 https://github.com/daxpedda/web-time
554+ webpki-roots 0.26.11 CDLA-Permissive-2.0 https://github.com/rustls/webpki-roots
555+ webpki-roots 1.0.9 CDLA-Permissive-2.0 https://github.com/rustls/webpki-roots
556+ weezl 0.1.12 MIT OR Apache-2.0 https://github.com/image-rs/weezl
557+ wgpu 29.0.4 MIT OR Apache-2.0 https://github.com/gfx-rs/wgpu
558+ wgpu-core 29.0.4 MIT OR Apache-2.0 https://github.com/gfx-rs/wgpu
559+ wgpu-core-deps-windows-linux-android 29.0.4 MIT OR Apache-2.0 https://github.com/gfx-rs/wgpu
560+ wgpu-hal 29.0.4 MIT OR Apache-2.0 https://github.com/gfx-rs/wgpu
561+ wgpu-naga-bridge 29.0.4 MIT OR Apache-2.0 https://github.com/gfx-rs/wgpu
562+ wgpu-types 29.0.4 MIT OR Apache-2.0 https://github.com/gfx-rs/wgpu
563+ winnow 0.7.15 MIT https://github.com/winnow-rs/winnow
564+ winnow 1.0.4 MIT https://github.com/winnow-rs/winnow
565+ writeable 0.6.4 Unicode-3.0 https://github.com/unicode-org/icu4x
566+ x11 2.21.0 MIT https://github.com/AltF02/x11-rs.git
567+ x11rb 0.13.2 MIT OR Apache-2.0 https://github.com/psychon/x11rb
568+ x11rb-protocol 0.13.2 MIT OR Apache-2.0 https://github.com/psychon/x11rb
569+ xcb 1.7.1 MIT https://github.com/rust-x-bindings/rust-xcb
570+ xcursor 0.3.11 MIT https://github.com/esposm03/xcursor-rs
571+ xim-ctext 0.3.0 MIT https://github.com/Riey/xim-rs
572+ xim-parser 0.2.2 MIT https://github.com/Riey/xim-rs
573+ xkbcommon 0.8.0 MIT https://github.com/rust-x-bindings/xkbcommon-rs
574+ xkeysym 0.2.1 MIT OR Apache-2.0 OR Zlib https://github.com/notgull/xkeysym
575+ xml5ever 0.18.1 MIT OR Apache-2.0 https://github.com/servo/html5ever
576+ xmlwriter 0.1.0 MIT https://github.com/RazrFalcon/xmlwriter
577+ y4m 0.8.0 MIT https://github.com/image-rs/y4m.git
578+ yazi 0.2.1 Apache-2.0 OR MIT https://github.com/dfrg/yazi
579+ yeslogic-fontconfig-sys 6.0.1 MIT https://github.com/yeslogic/fontconfig-rs
580+ yoke 0.8.3 Unicode-3.0 https://github.com/unicode-org/icu4x
581+ yoke-derive 0.8.4 Unicode-3.0 https://github.com/unicode-org/icu4x
582+ zbus 5.19.0 MIT https://github.com/z-galaxy/zbus/
583+ zbus-lockstep 0.5.2 MIT https://github.com/luukvanderduim/zbus-lockstep
584+ zbus-lockstep-macros 0.5.2 MIT https://github.com/luukvanderduim/zbus-lockstep
585+ zbus_macros 5.19.0 MIT https://github.com/z-galaxy/zbus/
586+ zbus_names 4.3.4 MIT https://github.com/z-galaxy/zbus/
587+ zbus_xml 5.2.1 MIT https://github.com/z-galaxy/zbus/
588+ zcheapstr 1.1.0 MIT https://github.com/z-galaxy/zcheapstr/
589+ zed-font-kit 0.14.1-zed MIT OR Apache-2.0 https://github.com/servo/font-kit
590+ zed-scap 0.0.8-zed MIT https://github.com/helmerapp/scap
591+ zed-xim 0.4.0-zed MIT https://github.com/Riey/xim-rs
592+ zeno 0.3.3 Apache-2.0 OR MIT https://github.com/dfrg/zeno
593+ zerocopy 0.8.62 BSD-2-Clause OR Apache-2.0 OR MIT https://github.com/google/zerocopy
594+ zerocopy-derive 0.8.62 BSD-2-Clause OR Apache-2.0 OR MIT https://github.com/google/zerocopy
595+ zerofrom 0.1.8 Unicode-3.0 https://github.com/unicode-org/icu4x
596+ zerofrom-derive 0.1.8 Unicode-3.0 https://github.com/unicode-org/icu4x
597+ zeroize 1.9.1 Apache-2.0 OR MIT https://github.com/RustCrypto/utils
598+ zeroize_derive 1.5.0 Apache-2.0 OR MIT https://github.com/RustCrypto/utils
599+ zerotrie 0.2.5 Unicode-3.0 https://github.com/unicode-org/icu4x
600+ zerovec 0.11.8 Unicode-3.0 https://github.com/unicode-org/icu4x
601+ zerovec-derive 0.11.6 Unicode-3.0 https://github.com/unicode-org/icu4x
602+ zlib-rs 0.6.8 Zlib https://github.com/trifectatechfoundation/zlib-rs
603+ zmij 1.0.23 MIT https://github.com/dtolnay/zmij
604+ zune-core 0.5.3 MIT OR Apache-2.0 OR Zlib https://github.com/etemesi254/zune-image
605+ zune-inflate 0.2.54 MIT OR Apache-2.0 OR Zlib
606+ zune-jpeg 0.5.15 MIT OR Apache-2.0 OR Zlib https://github.com/etemesi254/zune-image/tree/dev/crates/zune-jpeg
607+ zvariant 5.15.0 MIT https://github.com/z-galaxy/zbus/
608+ zvariant_derive 5.15.0 MIT https://github.com/z-galaxy/zbus/
609+ zvariant_utils 4.2.0 MIT https://github.com/z-galaxy/zbus/
+22−5src/claude.rsView File
@@ -328,10 +328,20 @@ fn claude_command(config: &LaunchConfig) -> Result<(PathBuf, Command)> {
328328 if let Some(session_id) = &config.resume {
329329 command.args(["--resume", session_id]);
330330 }
331+ if let Some(window) = auto_compact_window(&config.instance.auto_compact) {
332+ command.args(["--settings", &format!(r#"{{"autoCompactWindow":{window}}}"#)]);
333+ }
331334 command.args(split_args(&config.instance.args));
332335 Ok((binary, command))
333336 }
334337
338+ /// The "Auto-compact after" field as a token count, if it's one Claude
339+ /// takes: 100,000 to 1,000,000.
340+ pub fn auto_compact_window(text: &str) -> Option<u64> {
341+ let digits: String = text.chars().filter(|c| !matches!(c, ',' | '_' | ' ')).collect();
342+ digits.parse::<u64>().ok().filter(|tokens| (100_000..=1_000_000).contains(tokens))
343+ }
344+
335345 fn pi_command(config: &LaunchConfig) -> Result<(PathBuf, Command)> {
336346 let (binary, mut command) = base_command(&config.instance)?;
337347 command.args(["--mode", "rpc"]).current_dir(&config.cwd);
@@ -403,10 +413,8 @@ pub fn base_command(instance: &ProviderInstance) -> Result<(PathBuf, Command)> {
403413 }
404414 command.env(home_var(instance.kind), home);
405415 }
406- for var in &instance.env {
407- if !var.key.trim().is_empty() {
408- command.env(var.key.trim(), &var.value);
409- }
416+ for (key, value) in instance.env_vars() {
417+ command.env(key, value);
410418 }
411419 // Pi is a Node script; a desktop launcher's PATH may not reach the Node it
412420 // was installed with, which usually sits next to it.
@@ -508,7 +516,16 @@ pub fn is_executable(path: &Path) -> bool {
508516
509517 #[cfg(test)]
510518 mod tests {
511- use super::split_args;
519+ use super::{auto_compact_window, split_args};
520+
521+ #[::core::prelude::v1::test]
522+ fn auto_compact_takes_claudes_range() {
523+ assert_eq!(auto_compact_window("300000"), Some(300_000));
524+ assert_eq!(auto_compact_window("1,000,000"), Some(1_000_000));
525+ assert_eq!(auto_compact_window("99999"), None);
526+ assert_eq!(auto_compact_window("2000000"), None);
527+ assert_eq!(auto_compact_window(""), None);
528+ }
512529
513530 #[::core::prelude::v1::test]
514531 fn splits_like_a_shell() {
+5−1src/main.rsView File
@@ -165,7 +165,11 @@ fn quit(_: &Quit, cx: &mut App) {
165165 *first = Some(Instant::now());
166166 if let Some(window) = cx.active_window() {
167167 let _ = window.update(cx, |_, window, cx| {
168- window.push_notification(Notification::info("Hold Ctrl+Q, or press it again, to quit."), cx);
168+ let message = match settings::get(|settings| settings.quit_shortcut) {
169+ settings::QuitShortcut::Double => "Press Ctrl+Q again to quit.",
170+ _ => "Hold Ctrl+Q, or press it again, to quit.",
171+ };
172+ window.push_notification(Notification::info(message), cx);
169173 });
170174 }
171175 }
+63−4src/models.rsView File
@@ -164,7 +164,11 @@ pub struct InstanceState {
164164 pub status: ProbeStatus,
165165 /// A check is running; the fields keep the previous one's findings.
166166 pub checking: bool,
167+ /// The models the agent offers plus the custom ones, in the order the
168+ /// settings put them.
167169 pub models: Vec<ModelEntry>,
170+ /// The models as the agent reported them.
171+ reported: Vec<ModelEntry>,
168172 /// Claude's `default` entry, which the picker shows as the model it resolves to.
169173 pub default: Option<ModelEntry>,
170174 /// The signed-in account (Claude's email).
@@ -187,6 +191,7 @@ impl InstanceState {
187191 config,
188192 checking: false,
189193 models: Vec::new(),
194+ reported: Vec::new(),
190195 default: None,
191196 account: None,
192197 plan: None,
@@ -217,6 +222,44 @@ impl InstanceState {
217222 _ => false,
218223 }
219224 }
225+
226+ /// Whether a model was added by hand rather than reported by the agent.
227+ pub fn is_custom(&self, model: &ModelEntry) -> bool {
228+ self.config.custom_models.iter().any(|custom| custom.slug == model.id)
229+ && !self.reported.iter().any(|reported| reported.id == model.id)
230+ }
231+
232+ /// Takes the agent's model list, adding the custom models and putting
233+ /// them in the settings' order.
234+ fn set_reported(&mut self, models: Vec<ModelEntry>) {
235+ self.reported = models;
236+ self.arrange();
237+ }
238+
239+ fn arrange(&mut self) {
240+ let mut models = self.reported.clone();
241+ for custom in &self.config.custom_models {
242+ if custom.slug.trim().is_empty() || models.iter().any(|model| model.id == custom.slug) {
243+ continue;
244+ }
245+ models.push(ModelEntry {
246+ provider: self.config.kind,
247+ instance: self.config.id.clone(),
248+ id: custom.slug.clone(),
249+ resolved: custom.slug.clone(),
250+ name: if custom.name.trim().is_empty() { custom.slug.clone() } else { custom.name.trim().to_string() },
251+ detail: "Custom".into(),
252+ legacy: false,
253+ efforts: Vec::new(),
254+ fast_mode: false,
255+ auto_mode: false,
256+ context_window: None,
257+ });
258+ }
259+ let order = settings::get(|settings| settings.model_order.clone());
260+ models.sort_by_key(|model| order.iter().position(|key| *key == model.key()).unwrap_or(usize::MAX));
261+ self.models = models;
262+ }
220263 }
221264
222265 pub struct Catalog {
@@ -266,6 +309,7 @@ impl Catalog {
266309 if state.config != config {
267310 let enabled = config.enabled;
268311 state.config = config;
312+ state.arrange();
269313 if !enabled {
270314 state.status = ProbeStatus::Disabled;
271315 }
@@ -341,7 +385,7 @@ impl Catalog {
341385 Ok(probe) => {
342386 state.status = ProbeStatus::Ready;
343387 if !probe.models.is_empty() || state.config.kind != Provider::Claude {
344- state.models = probe.models;
388+ state.set_reported(probe.models);
345389 state.default = probe.default;
346390 }
347391 state.account = probe.account.or(state.account.take());
@@ -359,7 +403,7 @@ impl Catalog {
359403 state.status = status;
360404 }
361405 if state.config.kind != Provider::Claude {
362- state.models.clear();
406+ state.set_reported(Vec::new());
363407 }
364408 }
365409 }
@@ -401,8 +445,8 @@ impl Catalog {
401445 state.plan = probe.plan;
402446 changed = true;
403447 }
404- if !probe.models.is_empty() && state.models != probe.models {
405- state.models = probe.models;
448+ if !probe.models.is_empty() && state.reported != probe.models {
449+ state.set_reported(probe.models);
406450 state.default = probe.default;
407451 changed = true;
408452 }
@@ -446,6 +490,21 @@ impl Catalog {
446490 self.instance(instance).map(|state| state.commands.as_slice()).unwrap_or_default()
447491 }
448492
493+ /// Puts every instance's models in the order the settings give them,
494+ /// after that order changed.
495+ pub fn rearrange(cx: &mut App) {
496+ for state in &mut cx.global_mut::<Catalog>().instances {
497+ state.arrange();
498+ }
499+ cx.refresh_windows();
500+ }
501+
502+ /// Whether the settings hide a model from the model picker.
503+ pub fn is_hidden(&self, model: &ModelEntry) -> bool {
504+ let key = model.key();
505+ settings::get(|settings| settings.hidden_models.contains(&key))
506+ }
507+
449508 pub fn is_favorite(&self, model: &ModelEntry) -> bool {
450509 self.favorites.contains(&model.key())
451510 }
+17−5src/session.rsView File
@@ -720,7 +720,7 @@ impl Session {
720720 permission_mode: self.permission_mode,
721721 effort: self.reasoning.effort(),
722722 resume: resume.clone(),
723- browser_session: Some(browser::session_name(&self.id)),
723+ browser_session: settings::get(|settings| settings.agent_browser).then(|| browser::session_name(&self.id)),
724724 };
725725 let process = match AgentProcess::spawn(&config, tx) {
726726 Ok(process) => process,
@@ -760,6 +760,7 @@ impl Session {
760760 Provider::Jcode => {
761761 self.jcode = JcodeLink {
762762 browser_note: browser::find_binary()
763+ .filter(|_| config.browser_session.is_some())
763764 .map(|binary| browser::jcode_prompt(&browser::session_name(&self.id), &binary)),
764765 ..JcodeLink::default()
765766 };
@@ -2992,15 +2993,26 @@ impl Session {
29922993 /// Adds streamed text to an answer. With "Show finished paragraphs" on,
29932994 /// the view only takes whole paragraphs and code blocks.
29942995 fn append_text(&mut self, ix: usize, delta: &str, cx: &mut Context<Self>) {
2995- let paragraphs = settings::get(|settings| settings.streaming == Streaming::Paragraphs);
2996+ let streaming = settings::get(|settings| settings.streaming);
29962997 let Some(ChatItem::Assistant(answer)) = self.items.get_mut(ix) else { return };
29972998 answer.text.push_str(delta);
2998- let target = if paragraphs { finished_prefix(&answer.text) } else { answer.text.len() };
2999+ let target = match streaming {
3000+ Streaming::Tokens => answer.text.len(),
3001+ Streaming::Paragraphs => finished_prefix(&answer.text),
3002+ Streaming::Turn => return,
3003+ };
29993004 answer.show(target, cx);
30003005 }
30013006
3002- /// Shows the rest of an answer's text.
3007+ /// Shows the rest of an answer's text once its message is complete,
3008+ /// unless answers wait for the end of the turn.
30033009 fn flush_item(&mut self, ix: usize, cx: &mut Context<Self>) {
3010+ if settings::get(|settings| settings.streaming) != Streaming::Turn {
3011+ self.show_all(ix, cx);
3012+ }
3013+ }
3014+
3015+ fn show_all(&mut self, ix: usize, cx: &mut Context<Self>) {
30043016 if let Some(ChatItem::Assistant(answer)) = self.items.get_mut(ix) {
30053017 let end = answer.text.len();
30063018 answer.show(end, cx);
@@ -3009,7 +3021,7 @@ impl Session {
30093021
30103022 fn flush_text(&mut self, cx: &mut Context<Self>) {
30113023 for ix in 0..self.items.len() {
3012- self.flush_item(ix, cx);
3024+ self.show_all(ix, cx);
30133025 }
30143026 }
30153027
+278−16src/settings.rsView File
@@ -45,11 +45,47 @@ pub enum BranchNaming {
4545 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
4646 #[serde(rename_all = "snake_case")]
4747 pub enum QuitShortcut {
48- /// One press quits.
48+ /// One press quits ("Direct").
4949 Press,
5050 /// Holding the keys, or pressing them twice quickly, quits.
5151 #[default]
5252 Hold,
53+ /// Two quick presses quit.
54+ Double,
55+ }
56+
57+ /// Which keys send a prompt from the composer.
58+ #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
59+ #[serde(rename_all = "snake_case")]
60+ pub enum SendShortcut {
61+ /// Enter sends, Shift+Enter starts a new line.
62+ #[default]
63+ Enter,
64+ /// Enter sends a one-line prompt; once the prompt has several lines,
65+ /// Enter starts a new line and Ctrl+Enter sends.
66+ ModEnterMultiline,
67+ /// Ctrl+Enter sends, Enter starts a new line.
68+ ModEnter,
69+ }
70+
71+ /// The colors diffs and change counts use for additions and deletions.
72+ #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
73+ #[serde(rename_all = "snake_case")]
74+ pub enum DiffColors {
75+ #[default]
76+ RedGreen,
77+ /// Easier to tell apart with red-green color blindness.
78+ BlueOrange,
79+ }
80+
81+ /// How wide the conversation and the composer may grow on large screens.
82+ #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
83+ #[serde(rename_all = "snake_case")]
84+ pub enum ChatWidth {
85+ #[default]
86+ Comfortable,
87+ Wide,
88+ Full,
5389 }
5490
5591 /// How projects are ordered in the sidebar and the project menus.
@@ -136,10 +172,13 @@ pub enum TimeFormat {
136172 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
137173 #[serde(rename_all = "snake_case")]
138174 pub enum Streaming {
139- #[default]
175+ /// Every token as it arrives.
140176 Tokens,
141177 /// Each paragraph or code block once it's complete.
178+ #[default]
142179 Paragraphs,
180+ /// The whole answer once the turn ends.
181+ Turn,
143182 }
144183
145184 /// What a message sent while the agent works does.
@@ -147,9 +186,9 @@ pub enum Streaming {
147186 #[serde(rename_all = "snake_case")]
148187 pub enum FollowUp {
149188 /// Hand it to the agent at once, so it can change course mid-turn.
150- #[default]
151189 Steer,
152190 /// Hold it until the turn ends.
191+ #[default]
153192 Queue,
154193 }
155194
@@ -170,7 +209,22 @@ pub enum BackgroundActivity {
170209 #[serde(default)]
171210 pub struct EnvVar {
172211 pub key: String,
212+ /// Empty for a sensitive variable: its value lives in the secrets file.
173213 pub value: String,
214+ /// Kept out of `settings.json`, in a file only this user can read, and
215+ /// never shown again once saved.
216+ pub sensitive: bool,
217+ }
218+
219+ /// A model added by hand to an instance's list, for models the agent
220+ /// doesn't report.
221+ #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
222+ #[serde(default)]
223+ pub struct CustomModel {
224+ /// What the agent is launched with: `claude-sonnet-5`, `anthropic/claude-sonnet-5`.
225+ pub slug: String,
226+ /// Empty shows the slug.
227+ pub name: String,
174228 }
175229
176230 /// One configured agent: Claude Code or Pi, with its own binary, home
@@ -193,6 +247,13 @@ pub struct ProviderInstance {
193247 /// Extra arguments, split like a shell would.
194248 pub args: String,
195249 pub env: Vec<EnvVar>,
250+ /// A hex color (`#3e9bfa`) marking the instance in lists and pickers;
251+ /// empty for none.
252+ pub accent: String,
253+ /// Claude: compact the conversation after this many tokens (100,000 to
254+ /// 1,000,000); empty keeps Claude's default.
255+ pub auto_compact: String,
256+ pub custom_models: Vec<CustomModel>,
196257 }
197258
198259 impl Default for ProviderInstance {
@@ -212,12 +273,33 @@ impl ProviderInstance {
212273 home: String::new(),
213274 args: String::new(),
214275 env: Vec::new(),
276+ accent: String::new(),
277+ auto_compact: String::new(),
278+ custom_models: Vec::new(),
215279 }
216280 }
217281
218282 pub fn label(&self) -> String {
219283 if self.name.trim().is_empty() { self.kind.label().to_string() } else { self.name.trim().to_string() }
220284 }
285+
286+ /// The variables the agent runs with, sensitive values read from the
287+ /// secrets file.
288+ pub fn env_vars(&self) -> Vec<(String, String)> {
289+ let secrets = if self.env.iter().any(|var| var.sensitive) { read_secrets() } else { Default::default() };
290+ self.env
291+ .iter()
292+ .filter(|var| !var.key.trim().is_empty())
293+ .map(|var| {
294+ let key = var.key.trim().to_string();
295+ let value = match var.sensitive {
296+ true => secrets.get(&secret_key(&self.id, &key)).cloned().unwrap_or_default(),
297+ false => var.value.clone(),
298+ };
299+ (key, value)
300+ })
301+ .collect()
302+ }
221303 }
222304
223305 /// Another device's app this one connects to.
@@ -261,6 +343,11 @@ pub struct Settings {
261343 /// Model keys (`claude:opus`, `pi:anthropic/claude-sonnet-5-5`), in the
262344 /// order they were starred.
263345 pub favorites: Vec<String>,
346+ /// Model keys the model picker leaves out.
347+ pub hidden_models: Vec<String>,
348+ /// Model keys in the order the picker lists them; models not in it
349+ /// follow in the agent's order.
350+ pub model_order: Vec<String>,
264351
265352 // ---- new threads ----
266353 /// The model key new threads start on. `None` follows the open thread.
@@ -305,7 +392,9 @@ pub struct Settings {
305392 pub fold_turns: bool,
306393 /// Show what threads and turns cost.
307394 pub show_costs: bool,
308- /// Send with Ctrl+Enter, so Enter starts a new line.
395+ pub send_shortcut: SendShortcut,
396+ /// Send with Ctrl+Enter, so Enter starts a new line. Follows
397+ /// `send_shortcut` (true for [`SendShortcut::ModEnter`]).
309398 pub send_with_ctrl_enter: bool,
310399 pub follow_up: FollowUp,
311400 pub streaming: Streaming,
@@ -324,6 +413,10 @@ pub struct Settings {
324413 pub diff_collapsed: bool,
325414 pub diff_side_by_side: bool,
326415
416+ // ---- appearance ----
417+ pub diff_colors: DiffColors,
418+ pub chat_width: ChatWidth,
419+
327420 // ---- sidebar ----
328421 /// T3 Code's legacy sidebar: threads in per-project trees instead of the
329422 /// default flat inbox.
@@ -338,8 +431,7 @@ pub struct Settings {
338431 pub project_grouping_overrides: std::collections::BTreeMap<String, ProjectGrouping>,
339432 /// One-line thread cards in the sidebar.
340433 pub compact_threads: bool,
341- /// Group sidebar threads under their project: turns on the legacy
342- /// sidebar, like `legacy_sidebar`.
434+ /// Group sidebar threads under their project. Follows `legacy_sidebar`.
343435 pub group_by_project: bool,
344436 pub project_order: ProjectOrder,
345437 /// Fold working threads into their own section until they need you.
@@ -379,6 +471,8 @@ pub struct Settings {
379471 pub health_check_secs: u64,
380472
381473 // ---- integrations ----
474+ /// Let agents use the browser panel's shared browser.
475+ pub agent_browser: bool,
382476 /// The editor "Open in" uses, by name (`Zed`).
383477 pub editor: Option<String>,
384478 pub providers: Vec<ProviderInstance>,
@@ -410,12 +504,14 @@ impl Default for Settings {
410504 light_theme: "bone".into(),
411505 dark_theme: "graphite".into(),
412506 favorites: Vec::new(),
507+ hidden_models: Vec::new(),
508+ model_order: Vec::new(),
413509 default_model: None,
414510 default_reasoning: None,
415511 default_access: None,
416512 workspace: WorkspaceMode::Local,
417513 submodules: Submodules::Recursive,
418- start_from_origin: false,
514+ start_from_origin: true,
419515 branch_naming: BranchNaming::Static,
420516 branch_prefix: "vectrum".into(),
421517 branch_instructions: String::new(),
@@ -428,17 +524,20 @@ impl Default for Settings {
428524 text_reasoning: Some("low".into()),
429525 fold_turns: true,
430526 show_costs: true,
527+ send_shortcut: SendShortcut::Enter,
431528 send_with_ctrl_enter: false,
432- follow_up: FollowUp::Steer,
433- streaming: Streaming::Tokens,
529+ follow_up: FollowUp::Queue,
530+ streaming: Streaming::Paragraphs,
434531 slash_skills: true,
435532 rich_composer: true,
436- collapse_composer: false,
533+ collapse_composer: true,
437534 time_format: TimeFormat::System,
438535 proactive_panels: false,
439536 hide_whitespace: true,
440- diff_collapsed: false,
537+ diff_collapsed: true,
441538 diff_side_by_side: false,
539+ diff_colors: DiffColors::RedGreen,
540+ chat_width: ChatWidth::Comfortable,
442541 legacy_sidebar: false,
443542 thread_order: ThreadOrder::LastMessage,
444543 visible_threads: 6,
@@ -462,9 +561,10 @@ impl Default for Settings {
462561 notify_sound: false,
463562 in_app_notifications: false,
464563 continue_after_restart: false,
465- update_checks: false,
564+ update_checks: true,
466565 background_activity: BackgroundActivity::Balanced,
467566 health_check_secs: 300,
567+ agent_browser: true,
468568 editor: None,
469569 providers: Vec::new(),
470570 usage_hubs: Vec::new(),
@@ -497,6 +597,77 @@ impl Settings {
497597 self.providers.push(instance);
498598 }
499599 }
600+ // Fields older code reads, kept in step with the ones replacing them.
601+ self.send_with_ctrl_enter = self.send_shortcut == SendShortcut::ModEnter;
602+ self.group_by_project = self.legacy_sidebar;
603+ }
604+
605+ /// The settings "Restore device defaults" would change, by their
606+ /// labels on the settings pages, in the order T3 Code lists them.
607+ pub fn differing_defaults(&self) -> Vec<&'static str> {
608+ let d = Settings::default();
609+ let theme = (self.theme_mode, &self.light_theme, &self.dark_theme) != (d.theme_mode, &d.light_theme, &d.dark_theme);
610+ [
611+ ("Theme", theme),
612+ ("Diff colors", self.diff_colors != d.diff_colors),
613+ ("Chat width", self.chat_width != d.chat_width),
614+ ("Time format", self.time_format != d.time_format),
615+ ("Thread notifications", (self.notify, self.notify_sound) != (d.notify, d.notify_sound)),
616+ ("In-app notifications", self.in_app_notifications != d.in_app_notifications),
617+ ("Project Grouping", self.project_grouping != d.project_grouping),
618+ ("Project order", self.project_order != d.project_order),
619+ ("Working section", self.working_section != d.working_section),
620+ (
621+ "Auto-settle inactive threads",
622+ (self.auto_settle_inactive, self.inactive_days) != (d.auto_settle_inactive, d.inactive_days),
623+ ),
624+ ("Auto-settle merged threads", self.auto_settle_merged != d.auto_settle_merged),
625+ ("Auto-resume limited threads", self.auto_resume_limited != d.auto_resume_limited),
626+ ("Snooze limited threads", self.snooze_limited != d.snooze_limited),
627+ ("Composer context", self.composer_context != d.composer_context),
628+ ("Thread cards", self.compact_threads != d.compact_threads),
629+ ("Default diff file state", self.diff_collapsed != d.diff_collapsed),
630+ ("Diff whitespace changes", self.hide_whitespace != d.hide_whitespace),
631+ ("Diff layout", self.diff_side_by_side != d.diff_side_by_side),
632+ ("Proactive panels", self.proactive_panels != d.proactive_panels),
633+ ("Show skills in slash menu", self.slash_skills != d.slash_skills),
634+ ("Collapse composer on scroll", self.collapse_composer != d.collapse_composer),
635+ ("Rich text composer", self.rich_composer != d.rich_composer),
636+ ("Send shortcut", self.send_shortcut != d.send_shortcut),
637+ ("Follow-up behavior", self.follow_up != d.follow_up),
638+ ("Context window indicator", self.context_meter != d.context_meter),
639+ ("Plan mode", self.plan_mode != d.plan_mode),
640+ ("Sidebar", self.legacy_sidebar != d.legacy_sidebar),
641+ ("Response streaming", self.streaming != d.streaming),
642+ ("Fold finished turns", self.fold_turns != d.fold_turns),
643+ ("Show costs", self.show_costs != d.show_costs),
644+ ("Provider update checks", self.update_checks != d.update_checks),
645+ ("Continue threads after restarts", self.continue_after_restart != d.continue_after_restart),
646+ ("Background activity", self.background_activity != d.background_activity),
647+ ("Health check interval", self.health_check_secs != d.health_check_secs),
648+ ("Default model", (&self.default_model, &self.default_reasoning) != (&d.default_model, &d.default_reasoning)),
649+ ("Permissions", self.default_access != d.default_access),
650+ ("New thread mode", self.workspace != d.workspace),
651+ ("Submodules", self.submodules != d.submodules),
652+ ("New worktrees start from origin", self.start_from_origin != d.start_from_origin),
653+ ("Add project base directory", self.add_project_dir != d.add_project_dir),
654+ ("Unpin confirmation", self.confirm_unpin != d.confirm_unpin),
655+ ("Archive confirmation", self.confirm_settle != d.confirm_settle),
656+ ("Delete confirmation", self.confirm_delete != d.confirm_delete),
657+ ("Quit shortcut", self.quit_shortcut != d.quit_shortcut),
658+ ("Text generation model", (&self.text_model, &self.text_reasoning) != (&d.text_model, &d.text_reasoning)),
659+ (
660+ "Worktree branch naming",
661+ (self.branch_naming, &self.branch_prefix, &self.branch_instructions)
662+ != (d.branch_naming, &d.branch_prefix, &d.branch_instructions),
663+ ),
664+ ("Worktree location", self.worktrees_dir != d.worktrees_dir),
665+ ("Agent browser access", self.agent_browser != d.agent_browser),
666+ ("Open in", self.editor != d.editor),
667+ ]
668+ .into_iter()
669+ .filter_map(|(label, differs)| differs.then_some(label))
670+ .collect()
500671 }
501672
502673 pub fn instance(&self, id: &str) -> Option<&ProviderInstance> {
@@ -519,7 +690,16 @@ fn read_file() -> Settings {
519690
520691 /// Reads a settings file's text, falling back to the defaults.
521692 fn parse(text: &str) -> Settings {
522- let mut settings: Settings = serde_json::from_str(text).unwrap_or_default();
693+ let raw: serde_json::Value = serde_json::from_str(text).unwrap_or_default();
694+ let mut settings: Settings = serde_json::from_value(raw.clone()).unwrap_or_default();
695+ // Carry settings over from the fields that came before these.
696+ let missing = |key: &str| raw.get(key).is_none();
697+ if missing("send_shortcut") && settings.send_with_ctrl_enter {
698+ settings.send_shortcut = SendShortcut::ModEnter;
699+ }
700+ if missing("legacy_sidebar") {
701+ settings.legacy_sidebar = settings.group_by_project;
702+ }
523703 settings.normalize();
524704 settings
525705 }
@@ -564,12 +744,14 @@ pub fn update(edit: impl FnOnce(&mut Settings)) {
564744 }
565745 }
566746
567- /// Puts everything but favorites, agents, usage hubs and remote connections
568- /// back to its default.
747+ /// Puts everything but favorites and model preferences, agents, usage hubs
748+ /// and remote connections back to its default.
569749 pub fn restore_defaults() {
570750 update(|settings| {
571751 let kept = Settings {
572752 favorites: std::mem::take(&mut settings.favorites),
753+ hidden_models: std::mem::take(&mut settings.hidden_models),
754+ model_order: std::mem::take(&mut settings.model_order),
573755 providers: std::mem::take(&mut settings.providers),
574756 usage_hubs: std::mem::take(&mut settings.usage_hubs),
575757 remote_server: settings.remote_server,
@@ -582,6 +764,64 @@ pub fn restore_defaults() {
582764 });
583765 }
584766
767+ // ---- secrets ---------------------------------------------------------------
768+
769+ /// Where sensitive environment variables are kept: next to the settings,
770+ /// readable by this user only.
771+ fn secrets_path() -> Option<PathBuf> {
772+ Some(path()?.with_file_name("secrets.json"))
773+ }
774+
775+ fn secret_key(instance: &str, var: &str) -> String {
776+ format!("{instance}/{var}")
777+ }
778+
779+ fn read_secrets() -> std::collections::BTreeMap<String, String> {
780+ secrets_path()
781+ .and_then(|path| std::fs::read_to_string(path).ok())
782+ .and_then(|text| serde_json::from_str(&text).ok())
783+ .unwrap_or_default()
784+ }
785+
786+ /// Whether a sensitive variable has a stored value.
787+ pub fn has_secret(instance: &str, var: &str) -> bool {
788+ read_secrets().contains_key(&secret_key(instance, var.trim()))
789+ }
790+
791+ /// Stores a sensitive variable's value, or forgets it with `None`.
792+ pub fn set_secret(instance: &str, var: &str, value: Option<&str>) {
793+ let mut secrets = read_secrets();
794+ let key = secret_key(instance, var.trim());
795+ match value {
796+ Some(value) => secrets.insert(key, value.to_string()),
797+ None => secrets.remove(&key),
798+ };
799+ write_secrets(&secrets);
800+ }
801+
802+ /// Keeps a sensitive variable's value when the variable is renamed.
803+ pub fn rename_secret(instance: &str, from: &str, to: &str) {
804+ let mut secrets = read_secrets();
805+ if let Some(value) = secrets.remove(&secret_key(instance, from.trim())) {
806+ if !to.trim().is_empty() {
807+ secrets.insert(secret_key(instance, to.trim()), value);
808+ }
809+ write_secrets(&secrets);
810+ }
811+ }
812+
813+ fn write_secrets(secrets: &std::collections::BTreeMap<String, String>) {
814+ let Some(path) = secrets_path() else { return };
815+ let written = path.parent().map(std::fs::create_dir_all).unwrap_or(Ok(())).and_then(|_| {
816+ use std::{io::Write as _, os::unix::fs::OpenOptionsExt as _};
817+ let mut file = std::fs::OpenOptions::new().write(true).create(true).truncate(true).mode(0o600).open(&path)?;
818+ file.write_all(serde_json::to_string_pretty(&secrets).unwrap_or_default().as_bytes())
819+ });
820+ if let Err(err) = written {
821+ eprintln!("vectrum-code: couldn't save {}: {err}", path.display());
822+ }
823+ }
824+
585825 /// `~/bin/claude` → `/home/me/bin/claude`.
586826 pub fn expand_home(path: &str) -> PathBuf {
587827 match (path.strip_prefix("~/"), std::env::var_os("HOME")) {
@@ -601,7 +841,7 @@ pub fn data_dir() -> Option<PathBuf> {
601841
602842 #[cfg(test)]
603843 mod tests {
604- use super::{ThemeMode, parse};
844+ use super::{SendShortcut, ThemeMode, parse};
605845
606846 #[test]
607847 fn old_colorways_become_theme_modes() {
@@ -616,4 +856,26 @@ mod tests {
616856 let saved = parse(r#"{"theme_mode": "dark", "dark_theme": "nord"}"#);
617857 assert_eq!((saved.theme_mode, saved.dark_theme.as_str()), (ThemeMode::Dark, "nord"));
618858 }
859+
860+ #[test]
861+ fn older_fields_carry_over() {
862+ let old = parse(r#"{"send_with_ctrl_enter": true, "group_by_project": true}"#);
863+ assert_eq!(old.send_shortcut, SendShortcut::ModEnter);
864+ assert!(old.legacy_sidebar && old.group_by_project);
865+ // The new fields win once they're saved, and the old ones follow them.
866+ let new = parse(r#"{"send_with_ctrl_enter": true, "send_shortcut": "mod_enter_multiline", "legacy_sidebar": false}"#);
867+ assert_eq!(new.send_shortcut, SendShortcut::ModEnterMultiline);
868+ assert!(!new.send_with_ctrl_enter && !new.group_by_project && !new.legacy_sidebar);
869+ let fresh = parse("{}");
870+ assert_eq!((fresh.send_shortcut, fresh.legacy_sidebar), (SendShortcut::Enter, false));
871+ }
872+
873+ #[test]
874+ fn restore_lists_what_changed() {
875+ let mut settings = parse("{}");
876+ assert!(settings.differing_defaults().is_empty());
877+ settings.chat_width = super::ChatWidth::Wide;
878+ settings.dark_theme = "nord".into();
879+ assert_eq!(settings.differing_defaults(), ["Theme", "Chat width"]);
880+ }
619881 }
+7−5src/ui/changes.rsView File
@@ -102,9 +102,11 @@ fn counts(added: Option<u64>, removed: Option<u64>, p: &Palette) -> Div {
102102 .font_family(metal::MONO)
103103 .text_size(px(11.5))
104104 .map(|this| match (added, removed) {
105- (Some(added), Some(removed)) => this
106- .child(div().text_color(p.green_ink).child(format!("+{}", format_count(added))))
107- .child(div().text_color(p.red).child(format!("−{}", format_count(removed)))),
105+ (Some(added), Some(removed)) => {
106+ let ink = metal::diff_ink(p);
107+ this.child(div().text_color(ink.added).child(format!("+{}", format_count(added))))
108+ .child(div().text_color(ink.removed).child(format!("−{}", format_count(removed))))
109+ }
108110 _ => this.child(div().text_color(p.ink3).child("binary")),
109111 })
110112 }
@@ -345,8 +347,8 @@ fn split_rows(lines: &[DiffLine]) -> Vec<SplitRow<'_>> {
345347 /// A line's sign, background and ink.
346348 fn line_style(kind: LineKind, p: &Palette) -> (&'static str, Option<Hsla>, Hsla) {
347349 match kind {
348- LineKind::Added => ("+", Some(p.green_deep.opacity(0.14)), p.ink),
349- LineKind::Removed => ("−", Some(p.red.opacity(0.12)), p.ink),
350+ LineKind::Added => ("+", Some(metal::diff_ink(p).added_bg), p.ink),
351+ LineKind::Removed => ("−", Some(metal::diff_ink(p).removed_bg), p.ink),
350352 LineKind::Hunk => ("", Some(p.ink.opacity(0.04)), p.ink3),
351353 LineKind::Context => (" ", None, p.ink2),
352354 }
+24−8src/ui/chat.rsView File
@@ -36,7 +36,7 @@ use crate::session::{
3636 use crate::worktree::StageStatus;
3737 use crate::settings::{self, FollowUp, WorkspaceMode};
3838 use crate::ui::changes::{self, DiffAction, DiffView};
39- use crate::ui::composer::{self, CONTENT_WIDTH, Density, Tone};
39+ use crate::ui::composer::{self, Density, Tone};
4040 use crate::ui::icons::Lucide;
4141 use crate::ui::markdown_input::{self, MarkdownInput};
4242 use crate::ui::metal::{self, Led, MetalButton, MetalStyled as _, Palette};
@@ -214,7 +214,7 @@ impl ChatView {
214214 pub fn new(session: Entity<Session>, window: &mut Window, cx: &mut Context<Self>) -> Self {
215215 let composer = cx.new(|cx| {
216216 markdown_input::composer_state(EditorState::new(window, cx), settings::get(|settings| settings.rich_composer))
217- .submit_on_enter(!settings::get(|settings| settings.send_with_ctrl_enter))
217+ .submit_on_enter(settings::get(|settings| settings.send_shortcut) != settings::SendShortcut::ModEnter)
218218 .placeholder(DEFAULT_PLACEHOLDER)
219219 });
220220 let item_count = session.read(cx).items.len();
@@ -238,7 +238,7 @@ impl ChatView {
238238 }),
239239 cx.subscribe_in(&composer, window, |this, _, event, window, cx| match event {
240240 InputEvent::PressEnter { shift: false, secondary } => {
241- let ctrl_enter = settings::get(|settings| settings.send_with_ctrl_enter);
241+ let ctrl_enter = this.ctrl_sends(cx);
242242 if *secondary || !ctrl_enter {
243243 // With Enter sending, Ctrl+Enter does the opposite
244244 // of the follow-up setting.
@@ -248,6 +248,7 @@ impl ChatView {
248248 InputEvent::Change => {
249249 this.menu_selected = 0;
250250 this.stash_open = false;
251+ this.update_send_key(cx);
251252 this.sync_custom_answer(cx);
252253 this.expand(cx);
253254 this.load_files_if_mentioning(cx);
@@ -344,14 +345,29 @@ impl ChatView {
344345 /// Picks up changed settings: the send key, and folding, which changes
345346 /// the height of transcript rows.
346347 pub fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
347- let ctrl_enter = settings::get(|settings| settings.send_with_ctrl_enter);
348- self.composer.update(cx, |composer, cx| composer.set_submit_on_enter(!ctrl_enter, cx));
348+ self.update_send_key(cx);
349349 markdown_input::enable(&self.composer, settings::get(|settings| settings.rich_composer), cx);
350350 self.scroller.update(cx, |scroller, cx| scroller.remeasure(cx));
351351 self.sync_with_session(window, cx);
352352 cx.notify();
353353 }
354354
355+ /// Whether Ctrl+Enter sends right now, as Settings → Send shortcut says:
356+ /// always, never, or once the prompt runs over several lines.
357+ pub(super) fn ctrl_sends(&self, cx: &App) -> bool {
358+ match settings::get(|settings| settings.send_shortcut) {
359+ settings::SendShortcut::Enter => false,
360+ settings::SendShortcut::ModEnter => true,
361+ settings::SendShortcut::ModEnterMultiline => self.composer.read(cx).value().contains('\n'),
362+ }
363+ }
364+
365+ /// Lets Enter send, or start a new line, as the send shortcut wants.
366+ fn update_send_key(&mut self, cx: &mut Context<Self>) {
367+ let enter_sends = !self.ctrl_sends(cx);
368+ self.composer.update(cx, |composer, cx| composer.set_submit_on_enter(enter_sends, cx));
369+ }
370+
355371 pub fn focus_composer(&self, window: &mut Window, cx: &mut App) {
356372 self.composer.update(cx, |composer, cx| composer.focus(window, cx));
357373 }
@@ -1441,7 +1457,7 @@ impl ChatView {
14411457 Some(
14421458 h_flex()
14431459 .w_full()
1444- .max_w(px(CONTENT_WIDTH))
1460+ .max_w(composer::content_width())
14451461 .px(px(16.))
14461462 .pb(px(8.))
14471463 .gap(px(6.))
@@ -1532,7 +1548,7 @@ impl ChatView {
15321548 let (cancel, local) = (self.session.clone(), self.session.clone());
15331549 v_flex()
15341550 .w_full()
1535- .max_w(px(CONTENT_WIDTH))
1551+ .max_w(composer::content_width())
15361552 .px(px(16.))
15371553 .pb(px(8.))
15381554 .child(
@@ -1754,7 +1770,7 @@ impl ChatView {
17541770 .child(
17551771 v_flex()
17561772 .w_full()
1757- .max_w(px(CONTENT_WIDTH))
1773+ .max_w(composer::content_width())
17581774 .capture_key_down(cx.listener(|this, event: &KeyDownEvent, window, cx| {
17591775 this.composer_key(event, window, cx)
17601776 }))
+2−1src/ui/chat/footer.rsView File
@@ -377,7 +377,8 @@ impl ChatView {
377377 if working && !has_input && self.editing_queued.is_none() {
378378 return self.stop_button(cx).into_any_element();
379379 }
380- let (follow_up, ctrl_enter) = settings::get(|settings| (settings.follow_up, settings.send_with_ctrl_enter));
380+ let follow_up = settings::get(|settings| settings.follow_up);
381+ let ctrl_enter = self.ctrl_sends(cx);
381382 let queue_first = follow_up == FollowUp::Queue;
382383 let (icon, tooltip): (Icon, SharedString) = if self.editing_queued.is_some() {
383384 (Icon::new(IconName::Check), "Update queued message".into())
+2−2src/ui/chat/timeline.rsView File
@@ -28,7 +28,7 @@ use crate::session::{
2828 };
2929 use crate::settings;
3030 use crate::ui::changes;
31- use crate::ui::composer::CONTENT_WIDTH;
31+ use crate::ui::composer;
3232 use crate::ui::icons::Lucide;
3333 use crate::ui::metal::{self, Led, MetalButton, MetalStyled as _, Palette};
3434
@@ -417,7 +417,7 @@ pub(super) fn render_item(
417417 .child(
418418 v_flex()
419419 .w_full()
420- .max_w(px(CONTENT_WIDTH))
420+ .max_w(composer::content_width())
421421 .map(|this| match item {
422422 ChatItem::TaskEvent { .. } => this.children(content).children(summary.map(|summary| div().pt(px(8.)).child(summary))),
423423 _ => this.children(summary.map(|summary| div().pb(px(6.)).child(summary))).children(content.map(|content| {
+9−2src/ui/composer.rsView File
@@ -15,8 +15,15 @@ pub const INSET: f32 = 22.;
1515 pub const OVERLAP: f32 = 17.;
1616 /// The icon column of a banner row.
1717 pub const ICON_COLUMN: f32 = 24.;
18- /// The widest the conversation and the composer grow.
19- pub const CONTENT_WIDTH: f32 = 736.;
18+ /// The widest the conversation and the composer grow, as Settings →
19+ /// Appearance → Chat width says: 736px, 1152px, or the whole pane.
20+ pub fn content_width() -> Pixels {
21+ match crate::settings::get(|settings| settings.chat_width) {
22+ crate::settings::ChatWidth::Comfortable => px(736.),
23+ crate::settings::ChatWidth::Wide => px(1152.),
24+ crate::settings::ChatWidth::Full => px(100_000.),
25+ }
26+ }
2027
2128 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
2229 pub enum Tone {
+6−0src/ui/icons.rsView File
@@ -11,8 +11,10 @@ gpui_kit::assets::icon_assets!(ExtraIcons, [
1111 AlarmClock,
1212 AlarmClockOff,
1313 Archive,
14+ ArchiveX,
1415 ArchiveRestore,
1516 Bell,
17+ Blocks,
1618 Brain,
1719 ChevronsDownUp,
1820 ChevronsUpDown,
@@ -24,6 +26,7 @@ gpui_kit::assets::icon_assets!(ExtraIcons, [
2426 FolderGit2,
2527 FolderPlus,
2628 Gauge,
29+ HardDrive,
2730 GitBranch,
2831 GitCommitHorizontal,
2932 GitPullRequest,
@@ -31,6 +34,7 @@ gpui_kit::assets::icon_assets!(ExtraIcons, [
3134 Keyboard,
3235 Laptop,
3336 Layers,
37+ Link2,
3438 ListOrdered,
3539 Lock,
3640 MonitorSmartphone,
@@ -50,6 +54,7 @@ gpui_kit::assets::icon_assets!(ExtraIcons, [
5054 Plus,
5155 RotateCcw,
5256 Server,
57+ Settings2,
5358 ShieldCheck,
5459 SquareSlash,
5560 SlidersHorizontal,
@@ -59,6 +64,7 @@ gpui_kit::assets::icon_assets!(ExtraIcons, [
5964 SwatchBook,
6065 Star,
6166 Trash,
67+ Undo2,
6268 Zap,
6369 Bookmark,
6470 Bot,
+28−0src/ui/metal.rsView File
@@ -476,6 +476,34 @@ pub fn badge(initials: impl Into<SharedString>, tint: usize, p: &Palette) -> Div
476476 .child(initials.into())
477477 }
478478
479+ /// The colors diffs and change counts use, from the palette, as the Diff
480+ /// colors setting picks them.
481+ pub struct DiffInk {
482+ /// Text for additions: `+12`.
483+ pub added: Hsla,
484+ pub removed: Hsla,
485+ /// The tint behind an added line.
486+ pub added_bg: Hsla,
487+ pub removed_bg: Hsla,
488+ }
489+
490+ pub fn diff_ink(p: &Palette) -> DiffInk {
491+ match crate::settings::get(|settings| settings.diff_colors) {
492+ crate::settings::DiffColors::RedGreen => DiffInk {
493+ added: p.green_ink,
494+ removed: p.red,
495+ added_bg: p.green_deep.opacity(0.14),
496+ removed_bg: p.red.opacity(0.12),
497+ },
498+ crate::settings::DiffColors::BlueOrange => DiffInk {
499+ added: p.blue_ink,
500+ removed: p.tints[0],
501+ added_bg: p.blue_ink.opacity(0.14),
502+ removed_bg: p.tints[0].opacity(0.14),
503+ },
504+ }
505+ }
506+
479507 /// A vertical hairline, for separating toolbar groups.
480508 pub fn vrule(p: &Palette) -> Div {
481509 div().flex_none().w(px(1.)).h(px(16.)).bg(p.rule)
+3−1src/ui/pickers.rsView File
@@ -339,6 +339,7 @@ impl ModelPicker {
339339 let words: Vec<&str> = query.split_whitespace().collect();
340340 let mut matches: Vec<(bool, ModelEntry)> = catalog
341341 .all_models()
342+ .filter(|model| !catalog.is_hidden(model))
342343 .filter(|model| {
343344 let haystack = format!(
344345 "{} {} {} {} {}",
@@ -359,8 +360,9 @@ impl ModelPicker {
359360 match &self.rail {
360361 Rail::Favorites => (catalog.favorites().into_iter().cloned().collect(), Vec::new()),
361362 Rail::Instance(instance) => {
363+ // Models hidden in Settings → Providers stay out of the picker.
362364 let (mut current, legacy): (Vec<ModelEntry>, Vec<ModelEntry>) =
363- catalog.models(instance).iter().cloned().partition(|model| !model.legacy);
365+ catalog.models(instance).iter().filter(|model| !catalog.is_hidden(model)).cloned().partition(|model| !model.legacy);
364366 // Favorites float to the top, the rest keep the provider's order.
365367 current.sort_by_key(|model| !catalog.is_favorite(model));
366368 (current, legacy)
+0−2448src/ui/settings.rsdeleted

Large diffs are not rendered by default.

+286−0src/ui/settings/appearance.rsaddedView File

Large diffs are not rendered by default.

+148−0src/ui/settings/archive.rsaddedView File

Large diffs are not rendered by default.

+336−0src/ui/settings/connections.rsaddedView File

Large diffs are not rendered by default.

+248−0src/ui/settings/diagnostics.rsaddedView File

Large diffs are not rendered by default.

+615−0src/ui/settings/general.rsaddedView File

Large diffs are not rendered by default.

+81−0src/ui/settings/integrations.rsaddedView File

Large diffs are not rendered by default.

+307−0src/ui/settings/keybindings.rsaddedView File

Large diffs are not rendered by default.

+223−0src/ui/settings/licenses.rsaddedView File

Large diffs are not rendered by default.

+808−0src/ui/settings/mod.rsaddedView File

Large diffs are not rendered by default.

+1449−0src/ui/settings/providers.rsaddedView File

Large diffs are not rendered by default.

+219−0src/ui/settings/search.rsaddedView File

Large diffs are not rendered by default.

+174−0src/ui/settings/source_control.rsaddedView File

Large diffs are not rendered by default.

+85−0src/ui/settings/storage.rsaddedView File

Large diffs are not rendered by default.

+890−0src/ui/settings/widgets.rsaddedView File

Large diffs are not rendered by default.

+49−89src/ui/themes.rsView File

Large diffs are not rendered by default.

+5−4src/ui/usage.rsView File

Large diffs are not rendered by default.

+6−3src/ui/workspace.rsView File

Large diffs are not rendered by default.

+4−4src/ui/workspace/git_actions.rsView File

Large diffs are not rendered by default.