Agent Skills: Status Bar Integration for Skill Counts (#15741)

This commit is contained in:
N. Taylor Mullen
2026-01-02 15:01:31 -08:00
committed by GitHub
parent c0ccb22460
commit e78c3fe4f0
4 changed files with 36 additions and 17 deletions

View File

@@ -144,10 +144,16 @@ const createMockConfig = (overrides = {}) => ({
getDebugMode: vi.fn(() => false),
getAccessibility: vi.fn(() => ({})),
getMcpServers: vi.fn(() => ({})),
getMcpClientManager: vi.fn().mockImplementation(() => ({
getBlockedMcpServers: vi.fn(),
getMcpServers: vi.fn(),
})),
getToolRegistry: () => ({
getTool: vi.fn(),
}),
getSkillManager: () => ({
getSkills: () => [],
}),
getMcpClientManager: () => ({
getMcpServers: () => ({}),
getBlockedMcpServers: () => [],
}),
...overrides,
});

View File

@@ -120,6 +120,7 @@ export const Composer = () => {
blockedMcpServers={
config.getMcpClientManager()?.getBlockedMcpServers() ?? []
}
skillCount={config.getSkillManager().getSkills().length}
/>
)
)}

View File

@@ -34,14 +34,16 @@ describe('<ContextSummaryDisplay />', () => {
openFiles: [{ path: '/a/b/c', timestamp: Date.now() }],
},
},
skillCount: 1,
};
it('should render on a single line on a wide screen', () => {
const { lastFrame, unmount } = renderWithWidth(120, baseProps);
const output = lastFrame()!;
expect(output).toContain(
'Using: 1 open file (ctrl+g to view) | 1 GEMINI.md file | 1 MCP server',
'1 open file (ctrl+g to view) | 1 GEMINI.md file | 1 MCP server | 1 skill',
);
expect(output).not.toContain('Using:');
// Check for absence of newlines
expect(output.includes('\n')).toBe(false);
unmount();
@@ -51,10 +53,10 @@ describe('<ContextSummaryDisplay />', () => {
const { lastFrame, unmount } = renderWithWidth(60, baseProps);
const output = lastFrame()!;
const expectedLines = [
' Using:',
' - 1 open file (ctrl+g to view)',
' - 1 GEMINI.md file',
' - 1 MCP server',
' - 1 open file (ctrl+g to view)',
' - 1 GEMINI.md file',
' - 1 MCP server',
' - 1 skill',
];
const actualLines = output.split('\n');
expect(actualLines).toEqual(expectedLines);
@@ -86,9 +88,10 @@ describe('<ContextSummaryDisplay />', () => {
geminiMdFileCount: 0,
contextFileNames: [],
mcpServers: {},
skillCount: 0,
};
const { lastFrame, unmount } = renderWithWidth(60, props);
const expectedLines = [' Using:', ' - 1 open file (ctrl+g to view)'];
const expectedLines = [' - 1 open file (ctrl+g to view)'];
const actualLines = lastFrame()!.split('\n');
expect(actualLines).toEqual(expectedLines);
unmount();

View File

@@ -17,6 +17,7 @@ interface ContextSummaryDisplayProps {
mcpServers?: Record<string, MCPServerConfig>;
blockedMcpServers?: Array<{ name: string; extensionName: string }>;
ideContext?: IdeContext;
skillCount: number;
}
export const ContextSummaryDisplay: React.FC<ContextSummaryDisplayProps> = ({
@@ -25,6 +26,7 @@ export const ContextSummaryDisplay: React.FC<ContextSummaryDisplayProps> = ({
mcpServers,
blockedMcpServers,
ideContext,
skillCount,
}) => {
const { columns: terminalWidth } = useTerminalSize();
const isNarrow = isNarrowWidth(terminalWidth);
@@ -36,7 +38,8 @@ export const ContextSummaryDisplay: React.FC<ContextSummaryDisplayProps> = ({
geminiMdFileCount === 0 &&
mcpServerCount === 0 &&
blockedMcpServerCount === 0 &&
openFileCount === 0
openFileCount === 0 &&
skillCount === 0
) {
return <Text> </Text>; // Render an empty space to reserve height
}
@@ -83,15 +86,23 @@ export const ContextSummaryDisplay: React.FC<ContextSummaryDisplayProps> = ({
return parts.join(', ');
})();
const summaryParts = [openFilesText, geminiMdText, mcpText].filter(Boolean);
const skillText = (() => {
if (skillCount === 0) {
return '';
}
return `${skillCount} skill${skillCount > 1 ? 's' : ''}`;
})();
const summaryParts = [openFilesText, geminiMdText, mcpText, skillText].filter(
Boolean,
);
if (isNarrow) {
return (
<Box flexDirection="column" paddingX={1}>
<Text color={theme.text.secondary}>Using:</Text>
{summaryParts.map((part, index) => (
<Text key={index} color={theme.text.secondary}>
{' '}- {part}
- {part}
</Text>
))}
</Box>
@@ -100,9 +111,7 @@ export const ContextSummaryDisplay: React.FC<ContextSummaryDisplayProps> = ({
return (
<Box paddingX={1}>
<Text color={theme.text.secondary}>
Using: {summaryParts.join(' | ')}
</Text>
<Text color={theme.text.secondary}>{summaryParts.join(' | ')}</Text>
</Box>
);
};