TabContribution gains an optional iconColor honoured by the icon rail:
full-strength when active/hovered, dimmed (70%) when idle, so the tint
reads as identity without outshouting the active-state border. The
Claude Activity tab sets claudeAccent (#D97757) — nominative use per the
licenses.yaml trademark note (it marks Claude's own panel).
Filed and closed as a try-it-out (user request); trivially revertible if
the accent doesn't land visually.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Raise the declared minimums in pubspec.yaml to what our deps already
require: Flutter >=3.35.0 / Dart >=3.9.0 (was 3.19.0 / 3.5.0). alchemist
0.12 needs Flutter 3.32; Dart 3.9 first ships in Flutter 3.35, so 3.35 is
the binding floor. Pin the exact build toolchain in .fvmrc (Flutter
3.44.1).
Moving to the Dart 3.9 language level switches `dart format` to the new
"tall" style and enables two new lints. This commit is the resulting
mechanical churn, isolated from any behaviour change:
- whole-tree `dart format` reformat (tall style)
- `dart fix` for unnecessary_underscores + use_null_aware_elements
No runtime behaviour change; `make test` green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
panel.focusMode.exit is bound to Escape in the contributions layer, which
outranks the active preset. In Vim insert/visual mode that shadowed the
vim preset's `escape → vim.mode.normal` binding, so Esc closed the editor
instead of returning to normal mode.
Add an optional when-clause to a CommandContribution's defaultBinding
(plumbed through to KeymapService.registerCommandBinding, which already
accepts one) and guard focusMode.exit's escape with
`!vim.insert && !vim.visual` — symmetric with vim.yaml's vim.mode.normal.
Esc still exits focus / closes the editor in normal and non-Vim modes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T-207, first foundation piece of the Vim layer (T-65 epic). A
VimModeService (ChangeNotifier) owns the normal/insert/visual mode and
mirrors it into the keymap as mutually-exclusive vim.normal/vim.insert/
vim.visual scope flags. Those flags are the public mode interface: the
editor (T-206) will read them to decide insert-vs-command, and vim.yaml
(T-65) guards bindings with `when: vim.*`. Nothing reaches across the
builtin boundary into the service object.
The layer is gated on the active preset — the builtin.vim extension
ties VimModeService.enabled to app.keymap.preset and re-checks on every
keymap reload, so i/v/Esc never hijack input under non-Vim presets. Mode
commands (vim.mode.{normal,insert,visual}) carry no default binding for
the same reason; only vim.yaml binds keys to them. A status-bar item
shows `-- NORMAL --` etc. while enabled.
Exposes KeymapService on the extension context so the layer can publish
scope flags.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two reveal-on-open bugs:
Decisions opened only on the second click (T-196): the detail view
subscribed in didChangeDependencies, which runs after the tab is
revealed, so the broadcast 'selection' that triggered the reveal was
already gone. Hoist the back/forward history out of per-view State into
a retained per-reader ReaderNav (kernel ChangeNotifier in a
ReaderNavRegistry, D-81). The nav records selections, emits 'load' (the
single channel readers display from), and survives mount/unmount — the
reader grabs nav.current on mount, so the first selection lands. Both
the markdown and decisions readers move to this model; the per-view
ReaderHistoryMixin and the markdown post-frame forward hack are gone.
The editor pane never opened (T-197): EditorExtension contributed a
workspace tab but nothing activated it on editor.open. Add an activate()
that reveals the tab on editor.opened / editor.active-changed; the
view's hydrate() pulls the active buffer on mount.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
StatusbarHost laid every item at intrinsic width, so once the focused-pane
context line grew long (a model/mode/context/skills summary) the row's
content exceeded the bar width and overflowed instead of letting the slot
shrink. Add an opt-in flex factor to StatusItemContribution; the host wraps
flex>0 items in Flexible(loose) so they yield width when the bar is tight,
and the marquee then receives a bounded viewport and scrolls. Drops the
fixed maxWidth cap on the pane-context item.
T-160.
Co-Authored-By: Claude <noreply@anthropic.com>
DaemonBus (was EventBus): typed events for system/IPC layer.
MessageBus: channel-based pub/sub for UI/extension coordination.
Messages carry publisher (auto-stamped from extension ID),
channel (required), timestamp, and payload. Subscribe by
publisher, channel, or both — zero collision across extensions.
Extension context gains publish() and subscribe() convenience
methods that auto-stamp the extension's ID as publisher.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Single Flutter package at the repo root. All code, tests, assets,
and platform directories moved from app/ to root. Package renamed
from clide_app to clide — all imports rewritten. Merged pubspec
combines core (ffi) and app (flutter, yaml, xterm) dependencies.
Makefile simplified: no APP_PRESENT conditionals, no cd, no daemon
lifecycle. 317 tests pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>