show the configured skills count in the Claude status line

The status slot showed only live session fields (model/mode/context).
It now also shows the configured skills count from ClaudeConfig — the
environment side alongside the live session — and the pane rebuilds when
the config changes so the count appears once skills load and tracks
.claude edits.

T-154.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-23 16:50:09 +02:00
co-authored by Claude Opus 4.7
parent 2fd911d01d
commit 849024b7ee
4 changed files with 33 additions and 8 deletions
+3 -3
View File
@@ -26,10 +26,10 @@ heading, and (b) bumping `pubspec.yaml` `version:` in the same commit.
settings, and permissions from `~/.claude` and the repo's `.claude`
(layered), and caches the slash-command list per claude version. Backs
the typeahead and command-aware send.
- Per-session status in the bottom status bar (T-145, T-150) — the
- Per-session status in the bottom status bar (T-145, T-150, T-154) — the
active Claude pane shows its model · permission mode (accept-edits /
plan / …) · context-token count in a status-bar slot, swapping to the
focused pane on tab switch and clearing on blur. Long status text
plan / …) · context-token count · configured skills count, swapping to
the focused pane on tab switch and clearing on blur. Long status text
marquee-scrolls within the slot.
- tmux agent teams surface as native teammate tiles (T-139, T-140) —
when a Claude team is running, each teammate shows as a live
+19 -5
View File
@@ -72,13 +72,18 @@ class _ClaudePaneState extends State<ClaudePane> {
bool _spawned = false;
bool _usingTmux = false;
// The status line surfaced to the bottom status bar via ClidePane —
// null until Claude reports a model/mode/context. ClidePane conveys it
// while this pane is the focused one (T-150).
// The status line surfaced to the bottom status bar via ClidePane — the
// live session fields (model/mode/context, T-150) plus the configured
// skills count from ClaudeConfig (T-154). Null when there's nothing yet.
Widget? _statusWidget(SurfaceTokens tokens) {
if (_status.isEmpty) return null;
final skills = formatSkillsLabel(activeClaudeConfig?.skills.length ?? 0);
final parts = [
if (!_status.isEmpty) formatStatusLine(_status),
if (skills != null) skills,
];
if (parts.isEmpty) return null;
return ClideText(
formatStatusLine(_status),
parts.join(' · '),
fontSize: clideFontSmall,
fontFamily: clideMonoFamily,
color: tokens.statusBarForeground,
@@ -86,6 +91,12 @@ class _ClaudePaneState extends State<ClaudePane> {
);
}
// Rebuild when the Claude environment changes (e.g. skills load or a
// watched .claude file changes) so the status line stays current (T-154).
void _onConfigChanged() {
if (mounted) setState(() {});
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
@@ -97,11 +108,14 @@ class _ClaudePaneState extends State<ClaudePane> {
// Warm the slash-command list in the background (lazy, idempotent) so
// custom commands are recognised by the time the user types one (T-153).
unawaited(activeClaudeConfig?.ensureProbe());
// Reflect skills/config changes in the status line (T-154).
activeClaudeConfig?.addListener(_onConfigChanged);
}
}
@override
void dispose() {
activeClaudeConfig?.removeListener(_onConfigChanged);
_conversation?.dispose();
_conversation = null;
unawaited(_feed?.dispose());
@@ -43,6 +43,11 @@ String permissionModeLabel(String mode) {
}
}
/// Configured-skills count for the status line (`12 skills`), from
/// ClaudeConfig — the *environment* side alongside the live session fields
/// (T-154). Null when there are none to show.
String? formatSkillsLabel(int count) => count > 0 ? '$count skill${count == 1 ? '' : 's'}' : null;
/// Compact token count: `765k`, `1.2M`, or the raw number under 1k.
String formatTokenCount(int n) {
if (n >= 1000000) return '${(n / 1000000).toStringAsFixed(1)}M';
@@ -26,6 +26,12 @@ void main() {
expect(formatTokenCount(765000), '765k');
expect(formatTokenCount(1200000), '1.2M');
});
test('formatSkillsLabel pluralises and hides zero', () {
expect(formatSkillsLabel(0), isNull);
expect(formatSkillsLabel(1), '1 skill');
expect(formatSkillsLabel(12), '12 skills');
});
});
group('formatStatusLine', () {