feat(settings): Activity category — conversation fold level (T-453)

The first real settings tab. The Claude extension contributes an Activity
SettingsCategory whose fold-level select binds to app.claude.activityFoldLevel;
the activity panes already rebuild off the settings notifier, so a pick applies
live. Proves the schema-driven engine end to end with a production setting —
opening Settings now shows a populated, working category.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-17 12:41:20 +02:00
co-authored by Claude Opus 4.8
parent 76d8dadc25
commit 291f997d31
3 changed files with 56 additions and 13 deletions
+12 -13
View File
@@ -25,30 +25,29 @@ heading, and (b) bumping `pubspec.yaml` `version:` in the same commit.
✕, Esc, or a barrier tap. (T-445) ✕, Esc, or a barrier tap. (T-445)
- **Schema-driven settings engine.** Subsystems register a `SettingsCategory` - **Schema-driven settings engine.** Subsystems register a `SettingsCategory`
(a `SettingsCategoryContribution` routed into the kernel `SettingsRegistry`); (via `SettingsCategoryContribution` → the kernel `SettingsRegistry`); the
the panel renders it as carded sections of field rows — toggle, select, panel renders it as carded sections of toggle/select/text/number/file rows,
text, number, and an "opens external file" button — each bound to a each bound to a `SettingsStore` key with help and reset-to-default.
`SettingsStore` key with help text and reset-to-default. Inputs recede to Registering a category surfaces a new tab. (T-448)
`panelBackground` inside the elevated `panelHeader` cards (ui-design
surface.md). Categories are data; registering one surfaces a new tab. (T-448)
- **Settings category rail.** The modal's left rail lists the registered - **Settings category rail.** The modal's left rail lists the registered
categories (icon + title, data-driven from the registry) with an accent categories (icon + title, data-driven from the registry) with an accent
left-stripe + surfaceHi selection; picking one swaps the panel. (T-447) left-stripe + surfaceHi selection; picking one swaps the panel. (T-447)
- **Per-field scope tags.** Each settings field shows where its value lives — - **Per-field scope tags.** Each field shows where its value lives — folder =
folder = Project (`.clide`), globe = Always (`~/.clide`), circle-dashed = Project (`.clide`), globe = Always (`~/.clide`), circle-dashed =
Default/unset — colour-coded with a tooltip. Tapping opens a menu to move the Default/unset — with a tooltip and a menu to move the value between scopes or
value between the scopes the key supports or reset it to default. Backed by reset it. Backed by scope-explicit `SettingsStore` access. (T-449)
scope-explicit `SettingsStore` access (`rawAt`/`setAt`/`removeAt`/
`effectiveLayer`/`writableLayers`); `ext.*` keys layer project-over-app,
`app.*`/`project.*` keys live in their prefix's file. (T-449)
- **Cross-category settings search.** A search box atop the rail filters fields - **Cross-category settings search.** A search box atop the rail filters fields
across every category; the panel shows the matches grouped under category across every category; the panel shows the matches grouped under category
subheaders (editable inline), and each rail row shows its match count with subheaders (editable inline), and each rail row shows its match count with
zero-match categories dimmed. (T-450) zero-match categories dimmed. (T-450)
- **Settings → Activity category.** The first real settings tab: the
conversation fold level (none / tools / thinking / everything) as a schema
field; picking a level applies live to the activity stream. (T-453)
### Changed ### Changed
- **Theme picker relabelled "Theme…".** The ⌘K theme picker's command title - **Theme picker relabelled "Theme…".** The ⌘K theme picker's command title
+32
View File
@@ -100,6 +100,38 @@ class ClaudeExtension extends ClideExtension {
title: 'Claude: cycle activity fold level', title: 'Claude: cycle activity fold level',
run: _cycleFoldLevel, run: _cycleFoldLevel,
), ),
// Activity settings category (T-453) — the fold level as a schema field,
// written to kActivityFoldLevelKey; the panes already rebuild off the
// settings notifier, so picking a level applies live.
const SettingsCategoryContribution(
id: 'activity',
category: SettingsCategory(
id: 'activity',
title: 'Activity',
iconName: 'cards-three',
priority: 50,
sections: [
SettingsSection(
label: 'Conversation',
fields: [
SettingsField(
key: kActivityFoldLevelKey,
kind: SettingsFieldKind.select,
label: 'Fold level',
help: 'How aggressively the conversation folds tool calls, thinking, and results.',
defaultValue: 'tools',
options: [
SettingsOption(value: 'none', label: 'Show everything'),
SettingsOption(value: 'tools', label: 'Fold tool calls'),
SettingsOption(value: 'thinking', label: 'Fold tools + thinking'),
SettingsOption(value: 'everything', label: 'Fold all but prose'),
],
),
],
),
],
),
),
// T-171: agent roster controls (D-6 CLI/UI parity). // T-171: agent roster controls (D-6 CLI/UI parity).
// Usage: clide claude.agent.show <sessionId> // Usage: clide claude.agent.show <sessionId>
CommandContribution( CommandContribution(
@@ -145,4 +145,16 @@ void main() {
expect(activeClaudeConfig, isNull); expect(activeClaudeConfig, isNull);
}); });
}); });
group('Activity settings category (T-453)', () {
final category = ext.contributions.whereType<SettingsCategoryContribution>().firstWhere((c) => c.id == 'activity').category;
test('contributes an Activity category with the fold-level field', () {
expect(category.title, 'Activity');
final field = category.sections.expand((s) => s.fields).firstWhere((f) => f.key == kActivityFoldLevelKey);
expect(field.kind, SettingsFieldKind.select);
expect(field.defaultValue, 'tools');
expect(field.options.map((o) => o.value), containsAll(['none', 'tools', 'thinking', 'everything']));
});
});
} }