add Catppuccin Mocha theme (+ high-contrast sibling)
Ships catppuccin-mocha (faithful to the official Catppuccin Mocha palette) and catppuccin-mocha-hc (high-contrast sibling per D-69 — the faithful palette is never retuned to pass the gate). Both bundled and gated: mocha clears baseline AA, mocha-hc clears the strict extended set. Catppuccin MIT palette recorded in licenses.yaml. Closes T-82 (Mocha + hc meets every acceptance bullet; faithful Latte deferred — it can't clear baseline AA without retuning, a separate call). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -112,3 +112,7 @@ INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by,
|
||||
|
||||
Resolved (2026-06-03): NO new mechanism or decision needed -- the contract already existed. D-74''s CommandSchema.normalize (lib/src/ipc/command_schema.dart) already folds the argv shape {positional,flags} into named args using a declared positional ordering, and the dispatcher already runs normalize+validate. The arg-taking commands simply never registered a schema (adoption is opt-in per D-74). Fix = adopt it: added positional schemas (non-required, so missing-arg errors stay as handlers produce them; only effect is positional->named mapping + numeric coercion of line/cols/rows) to editor.open/activate/read/save/close, files.read/ls, pane.close/focus/resize/write. Handlers unchanged. Tests: CLI-shape ({positional:[...]}) dispatch now binds (editor/pane/files command tests). DEFERRED (still named-arg only; in-process UI works, CLI-arg niche): editor.insert/replace-selection/set-selection/set-content (content/selection encoding + active-buffer fallback make positional ambiguous), pane.spawn (argv is a list, not scalar positional), git.* arg verbs (agents use plain git; D-83 external-agent scope). NOTE: takes effect on app RESTART, not hot reload -- the dispatcher is built once at boot.', NULL, '2026-06-03 13:41:38', '2026-06-03 13:41:38', '2026-06-03 13:41:38', NULL, '0655a8efb4c977b404daedd86d926761', 1) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-232', 'status', 'in_progress', 'done', NULL, '2026-06-03 13:41:42', '2026-06-03 13:41:42', '2026-06-03 13:41:42', NULL, '17995cc58fd4260f4901357531eeafc4', 1) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-234', 'status', 'backlog', 'ready', NULL, '2026-06-03 14:25:47', '2026-06-03 14:25:47', '2026-06-03 14:25:47', NULL, 'e8216367ab4337bdbaa8fc97c596e111', 1) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-234', 'status', 'ready', 'in_progress', NULL, '2026-06-03 14:27:26', '2026-06-03 14:27:26', '2026-06-03 14:27:26', NULL, '3db43a5f8b3855b2a78b4f6294dfeb97', 1) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-82', 'status', 'ready', 'in_progress', NULL, '2026-06-03 14:27:26', '2026-06-03 14:27:26', '2026-06-03 14:27:26', NULL, '7a7042a498a0f09a072d911fad8d33d7', 1) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-230', 'status', 'ready', 'in_progress', NULL, '2026-06-03 14:27:26', '2026-06-03 14:27:26', '2026-06-03 14:27:26', NULL, 'ec0e54053e51dea1fecb48eebc69e387', 1) ON CONFLICT(hash) DO NOTHING;
|
||||
|
||||
@@ -303,3 +303,58 @@ Acceptance:
|
||||
3. Selecting a theme applies it live (ThemeController.select) and closes the popout.
|
||||
4. Esc / outside-click dismisses without changing the theme; the control is keyboard-operable.
|
||||
5. theme.pick (palette/command) still works unchanged.', 'backlog', 'medium', NULL, NULL, NULL, '2026-06-03 13:49:44', '2026-06-03 13:49:44', NULL, '301e958c679661deb77d1e3ca5d45d72', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-230', 'story', 'T-132', 'Cluster meta messages into a collapsible activity card', 'The Claude pane renders every transcript item as its own row, so a heavy agent turn becomes a wall of tool-call/result rows (Bash <cmd> / Bash · result {…} / ''completed with no output'') that buries the messages that matter (user + Claude prose). Wireframe: docs/design/wireframes/claude/meta-activity-card.png.
|
||||
|
||||
Fold runs of consecutive ''meta'' items into one live, collapsible activity card:
|
||||
- The card shows the MOST RECENT meta line as a live ticker and updates in place as new ones stream in — a running ''what''s happening now''. A step count (''14 steps'') sits on the right.
|
||||
- Collapsed by default; click the chevron to expand the full list of folded steps, click to re-collapse.
|
||||
- ''Sticky'' items never fold — they render first-class. A sticky item SEALS the current card and a new cluster begins after it. A cluster = one unbroken run of foldable items between two sticky items.
|
||||
|
||||
Taxonomy over the sealed ConversationItem set (transcript_reader.dart): UserMessage, AssistantTextMessage, AssistantThinkingMessage, AssistantToolUse, ToolResultMessage.
|
||||
- Always sticky: UserMessage, AssistantTextMessage. Permission/AskUserQuestion prompts already live in the interaction zone (D-78) and are inherently sticky / cluster-breaking — no change, but note they break the run too.
|
||||
- Foldable: AssistantToolUse + its paired ToolResultMessage (pairing already exists via toolUseById, T-168).
|
||||
|
||||
Refinement decisions (2026-06-03, user):
|
||||
1. WHAT FOLDS is a 3-level setting (conservative → aggressive); DEFAULT = level 1. Build the foldable predicate so all three are switchable:
|
||||
- L1 (default): fold tool calls + results only; diffs (Edit/Write results) AND AssistantThinkingMessage stay first-class/sticky.
|
||||
- L2: also fold thinking; diffs stay sticky.
|
||||
- L3: fold everything except UserMessage + AssistantTextMessage (incl. diffs + thinking).
|
||||
2. ERRORS: a failed/error ToolResultMessage SURFACES — treated as sticky, stays visible and breaks the cluster (see wireframe state B). Start here; the user noted some non-fatal errors are themselves clutter, so expect to tune which errors surface vs. fold.
|
||||
3. DEFAULT/RUN STATE: always collapsed, showing the last line + step count, with the ticker updating live. NO setting. (Rejected auto-expanding the in-flight cluster: it scrolls the last useful sticky message out of view during long runs and only collapses when done — worst timing. Collapsed-with-live-ticker keeps the last sticky message anchored while preserving the motion/dynamism.)
|
||||
|
||||
Implementation home: a ''collapse adjacent foldable items'' grouping pass over ConversationController.items, consumed by ConversationView; the card is a new conversation_card variant. Keep it accessible (keyboard expand/collapse + semantics: announce step count and collapsed/expanded state).
|
||||
|
||||
Acceptance:
|
||||
1. Consecutive foldable items collapse into one card; the collapsed card shows the latest line + a live-updating step count.
|
||||
2. A sticky message (user / Claude prose / surfaced error / interaction-zone prompt) seals the card and starts a new cluster after it.
|
||||
3. Expanding shows every folded step (tool call + result pairs) in order; collapsing returns to the one-line view.
|
||||
4. The foldable level is a setting (default L1: diffs + thinking stay first-class); switching levels re-groups the transcript.
|
||||
5. Failed tool results surface as their own (sticky) row and break the cluster.
|
||||
6. Keyboard + screen-reader accessible (expand/collapse, step count announced).', 'in_progress', 'medium', NULL, NULL, NULL, '2026-06-03 11:15:39', '2026-06-03 14:27:26', NULL, '3eb3d504dad69cc0c06e57bce8f10456', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-82', 'task', NULL, 'add Catppuccin theme to bundled themes', 'User request: ship a Catppuccin theme alongside the four bundled themes (clide, midnight, paper, terminal — D-44).
|
||||
|
||||
**Acceptance:**
|
||||
- New theme YAML at `lib/kernel/src/theme/themes/catppuccin.yaml` (or split for the four Catppuccin flavours: latte / frappe / macchiato / mocha — pick one or all four; recommend Mocha as the dark default and Latte for the light variant).
|
||||
- Tokens populated for every key in `SurfaceTokens` (lib/kernel/src/theme/tokens.dart) — chrome, panels, tabs, list items, status colours, syntax tokens (D-45).
|
||||
- WCAG-AA contrast gate (D-22) passes against the theme.
|
||||
- Listed in `assets/licenses.yaml` with the upstream license (MIT) and attribution.
|
||||
- Theme picker (`builtin.theme-picker`) shows it in the live-switch menu.
|
||||
|
||||
**Source palettes:** https://github.com/catppuccin/catppuccin#-palette — official hex values, don`t paraphrase.
|
||||
|
||||
**Why now:** test user request; also a good exercise for any future user-contributed theme since Catppuccin is the most common one to ask for.', 'in_progress', 'low', NULL, NULL, NULL, '2026-05-06 08:30:15', '2026-06-03 14:27:26', NULL, '4cb876eb35abc00ee93eb0bced3315da', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-234', 'story', NULL, 'Theme-switcher popout in the status bar', 'Add a theme switcher to the far-right corner of the bottom status bar (the empty area to the right of the ''application ok'' / ipc-status item — see the user''s screenshot). Today switching themes is only reachable via the theme.pick command / palette (ThemePickerExtension opens a modal picker_view); there''s no always-visible affordance.
|
||||
|
||||
Add a compact status-bar control that opens a POPOUT (popover anchored to the control, not the full-screen modal) for quick theme switching:
|
||||
- A small right-aligned status item — a palette/swatch icon (or the current theme name). Contribute via StatusItemContribution at Slots.statusbar with priority > 100 so it sits in the right group, to the right of the ipc/toolchain ''application ok'' item (priority 100).
|
||||
- Click (or focus + Enter/Space) opens a popover listing ThemeController.available, the current (ThemeController.currentName) marked.
|
||||
- Selecting an entry applies it immediately via ThemeController.select(name) and closes the popout.
|
||||
- Esc / click-away dismisses with no change. Keyboard navigable (arrow + Enter), matching the palette/quick-open overlay pattern.
|
||||
- Natural home: ThemePickerExtension (lib/builtin/theme_picker). Reuse the theme list + select logic from picker_view rather than duplicating; the modal theme.pick command stays as-is for parity (D-6).
|
||||
|
||||
Acceptance:
|
||||
1. A theme control sits in the far-right of the status bar.
|
||||
2. Clicking/activating it opens a popover of all available themes with the current one marked.
|
||||
3. Selecting a theme applies it live (ThemeController.select) and closes the popout.
|
||||
4. Esc / outside-click dismisses without changing the theme; the control is keyboard-operable.
|
||||
5. theme.pick (palette/command) still works unchanged.', 'in_progress', 'medium', NULL, NULL, NULL, '2026-06-03 13:49:44', '2026-06-03 14:27:26', NULL, '9a5ac18d9e54e009f912b9c54584d796', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
|
||||
@@ -18,6 +18,9 @@ heading, and (b) bumping `pubspec.yaml` `version:` in the same commit.
|
||||
|
||||
### Added
|
||||
|
||||
- Catppuccin Mocha theme, plus a high-contrast `catppuccin-mocha-hc` sibling,
|
||||
added to the bundled themes — switchable from the theme picker. Faithful to
|
||||
the official palette (D-69). (T-82)
|
||||
- `clide ui open <reader> <id|path>` opens a doc in a GUI reader from the CLI —
|
||||
`tickets`/`decisions` by id, `markdown` by path — so an agent can surface what
|
||||
it's looking at on your screen. The drive-half complement to `clide status`. (T-231)
|
||||
|
||||
@@ -81,6 +81,17 @@ dependencies:
|
||||
Fill weights bundled.
|
||||
weights_bundled: [Regular, Bold, Fill]
|
||||
|
||||
- name: Catppuccin (palette)
|
||||
kind: theme-palette
|
||||
version: "mocha"
|
||||
homepage: https://github.com/catppuccin/catppuccin
|
||||
license: MIT
|
||||
purpose: >-
|
||||
Source palette for the bundled catppuccin-mocha theme and its
|
||||
high-contrast sibling catppuccin-mocha-hc. Official hex values,
|
||||
mapped to clide's SurfaceTokens (Mauve accent, Blue primary); the
|
||||
faithful palette is not retuned (D-69).
|
||||
|
||||
- name: yaml
|
||||
kind: dart-package
|
||||
version: "3.1.3"
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# catppuccin-mocha-hc — high-contrast sibling of `catppuccin-mocha`
|
||||
#
|
||||
# Same Catppuccin Mocha silhouette; muted text, status chips, syntax
|
||||
# tokens, and the focus border bumped to clear the strict contrast gate
|
||||
# (D-22 + D-69, `extendedPairs`). The faithful palette lives in
|
||||
# catppuccin-mocha.yaml and is never retuned. License: MIT.
|
||||
|
||||
name: catppuccin-mocha-hc
|
||||
display_name: Catppuccin Mocha (high contrast)
|
||||
dark: true
|
||||
|
||||
palette:
|
||||
background: "#1e1e2e" # Base
|
||||
panel: "#181825" # Mantle
|
||||
surface: "#313244" # Surface0
|
||||
muted: "#bac2de" # Subtext1 (brightened for AA)
|
||||
foreground: "#eff1f5" # near-white
|
||||
secondary: "#cdd6f4" # Text
|
||||
primary: "#a6c8ff" # brightened Blue
|
||||
accent: "#d4bbfb" # brightened Mauve
|
||||
success: "#b9ecb4" # brightened Green
|
||||
warning: "#f9e2af" # Yellow
|
||||
error: "#ffa3bd" # brightened Red
|
||||
info: "#9fe1ee" # brightened Sky
|
||||
onAccent: "#11111b" # Crust
|
||||
surfaceHi: "#45475a" # Surface1
|
||||
border: "#313244" # Surface0
|
||||
borderHi: "#9399b2" # Overlay2 (visible focus border)
|
||||
textDim: "#bac2de" # Subtext1
|
||||
textMute: "#9399b2" # Overlay2
|
||||
accentSoft: "#21cba6f7" # Mauve, low alpha
|
||||
|
||||
syntax:
|
||||
keyword: "#cba6f7" # Mauve
|
||||
type: "#f9e2af" # Yellow
|
||||
string: "#a6e3a1" # Green
|
||||
number: "#fab387" # Peach
|
||||
comment: "#a6adc8" # Subtext0 (brightened for AA on the panel)
|
||||
method: "#89b4fa" # Blue
|
||||
punct: "#9399b2" # Overlay2
|
||||
@@ -0,0 +1,39 @@
|
||||
# catppuccin-mocha — the Catppuccin Mocha (dark) flavour
|
||||
# Source palette: https://github.com/catppuccin/catppuccin (official hex).
|
||||
# Mapping: Base/Mantle/Surface0/1/2 → chrome; Text/Subtext → foreground;
|
||||
# Blue=primary, Mauve=accent (the Catppuccin signature). License: MIT,
|
||||
# see assets/licenses.yaml.
|
||||
|
||||
name: catppuccin-mocha
|
||||
display_name: Catppuccin Mocha
|
||||
dark: true
|
||||
|
||||
palette:
|
||||
background: "#1e1e2e" # Base
|
||||
panel: "#181825" # Mantle
|
||||
surface: "#313244" # Surface0
|
||||
muted: "#9399b2" # Overlay2
|
||||
foreground: "#cdd6f4" # Text
|
||||
secondary: "#bac2de" # Subtext1
|
||||
primary: "#89b4fa" # Blue
|
||||
accent: "#cba6f7" # Mauve
|
||||
success: "#a6e3a1" # Green
|
||||
warning: "#f9e2af" # Yellow
|
||||
error: "#f38ba8" # Red
|
||||
info: "#89dceb" # Sky
|
||||
onAccent: "#11111b" # Crust (dark text on the light accent)
|
||||
surfaceHi: "#45475a" # Surface1
|
||||
border: "#313244" # Surface0
|
||||
borderHi: "#45475a" # Surface1
|
||||
textDim: "#a6adc8" # Subtext0
|
||||
textMute: "#7f849c" # Overlay1
|
||||
accentSoft: "#21cba6f7" # Mauve, low alpha
|
||||
|
||||
syntax:
|
||||
keyword: "#cba6f7" # Mauve
|
||||
type: "#f9e2af" # Yellow
|
||||
string: "#a6e3a1" # Green
|
||||
number: "#fab387" # Peach
|
||||
comment: "#7f849c" # Overlay1
|
||||
method: "#89b4fa" # Blue
|
||||
punct: "#9399b2" # Overlay2
|
||||
@@ -425,6 +425,8 @@ Future<List<ThemeDefinition>> _loadBundledThemes() async {
|
||||
'lib/kernel/src/theme/themes/midnight-hc.yaml',
|
||||
'lib/kernel/src/theme/themes/paper-hc.yaml',
|
||||
'lib/kernel/src/theme/themes/terminal-hc.yaml',
|
||||
'lib/kernel/src/theme/themes/catppuccin-mocha.yaml',
|
||||
'lib/kernel/src/theme/themes/catppuccin-mocha-hc.yaml',
|
||||
];
|
||||
final out = <ThemeDefinition>[];
|
||||
for (final p in paths) {
|
||||
|
||||
@@ -23,6 +23,8 @@ void main() {
|
||||
'lib/kernel/src/theme/themes/midnight-hc.yaml',
|
||||
'lib/kernel/src/theme/themes/paper-hc.yaml',
|
||||
'lib/kernel/src/theme/themes/terminal-hc.yaml',
|
||||
'lib/kernel/src/theme/themes/catppuccin-mocha.yaml',
|
||||
'lib/kernel/src/theme/themes/catppuccin-mocha-hc.yaml',
|
||||
];
|
||||
|
||||
for (final path in bundledPaths) {
|
||||
|
||||
Reference in New Issue
Block a user