Merge branch 'main' into mk-windows-sandboxing

This commit is contained in:
matt korwel
2026-03-13 12:13:09 -07:00
committed by GitHub
17 changed files with 792 additions and 74 deletions

View File

@@ -116,38 +116,9 @@ const Kbd = ({ name, shortcut }: { name: string; shortcut: string }) => (
</>
);
/**
* Loading state component displayed while sessions are being loaded.
*/
const SessionBrowserLoading = (): React.JSX.Element => (
<Box flexDirection="column" paddingX={1}>
<Text color={Colors.Gray}>Loading sessions</Text>
</Box>
);
/**
* Error state component displayed when session loading fails.
*/
const SessionBrowserError = ({
state,
}: {
state: SessionBrowserState;
}): React.JSX.Element => (
<Box flexDirection="column" paddingX={1}>
<Text color={Colors.AccentRed}>Error: {state.error}</Text>
<Text color={Colors.Gray}>Press q to exit</Text>
</Box>
);
/**
* Empty state component displayed when no sessions are found.
*/
const SessionBrowserEmpty = (): React.JSX.Element => (
<Box flexDirection="column" paddingX={1}>
<Text color={Colors.Gray}>No auto-saved conversations found.</Text>
<Text color={Colors.Gray}>Press q to exit</Text>
</Box>
);
import { SessionBrowserLoading } from './SessionBrowser/SessionBrowserLoading.js';
import { SessionBrowserError } from './SessionBrowser/SessionBrowserError.js';
import { SessionBrowserEmpty } from './SessionBrowser/SessionBrowserEmpty.js';
import { sortSessions, filterSessions } from './SessionBrowser/utils.js';

View File

@@ -0,0 +1,19 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import type React from 'react';
import { Box, Text } from 'ink';
import { Colors } from '../../colors.js';
/**
* Empty state component displayed when no sessions are found.
*/
export const SessionBrowserEmpty = (): React.JSX.Element => (
<Box flexDirection="column" paddingX={1}>
<Text color={Colors.Gray}>No auto-saved conversations found.</Text>
<Text color={Colors.Gray}>Press q to exit</Text>
</Box>
);

View File

@@ -0,0 +1,24 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import type React from 'react';
import { Box, Text } from 'ink';
import { Colors } from '../../colors.js';
import type { SessionBrowserState } from '../SessionBrowser.js';
/**
* Error state component displayed when session loading fails.
*/
export const SessionBrowserError = ({
state,
}: {
state: SessionBrowserState;
}): React.JSX.Element => (
<Box flexDirection="column" paddingX={1}>
<Text color={Colors.AccentRed}>Error: {state.error}</Text>
<Text color={Colors.Gray}>Press q to exit</Text>
</Box>
);

View File

@@ -0,0 +1,18 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import type React from 'react';
import { Box, Text } from 'ink';
import { Colors } from '../../colors.js';
/**
* Loading state component displayed while sessions are being loaded.
*/
export const SessionBrowserLoading = (): React.JSX.Element => (
<Box flexDirection="column" paddingX={1}>
<Text color={Colors.Gray}>Loading sessions</Text>
</Box>
);

View File

@@ -0,0 +1,35 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { render } from '../../../test-utils/render.js';
import { describe, it, expect } from 'vitest';
import { SessionBrowserLoading } from './SessionBrowserLoading.js';
import { SessionBrowserError } from './SessionBrowserError.js';
import { SessionBrowserEmpty } from './SessionBrowserEmpty.js';
import type { SessionBrowserState } from '../SessionBrowser.js';
describe('SessionBrowser UI States', () => {
it('SessionBrowserLoading renders correctly', async () => {
const { lastFrame, waitUntilReady } = render(<SessionBrowserLoading />);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
it('SessionBrowserError renders correctly', async () => {
const mockState = { error: 'Test error message' } as SessionBrowserState;
const { lastFrame, waitUntilReady } = render(
<SessionBrowserError state={mockState} />,
);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
it('SessionBrowserEmpty renders correctly', async () => {
const { lastFrame, waitUntilReady } = render(<SessionBrowserEmpty />);
await waitUntilReady();
expect(lastFrame()).toMatchSnapshot();
});
});

View File

@@ -0,0 +1,18 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`SessionBrowser UI States > SessionBrowserEmpty renders correctly 1`] = `
" No auto-saved conversations found.
Press q to exit
"
`;
exports[`SessionBrowser UI States > SessionBrowserError renders correctly 1`] = `
" Error: Test error message
Press q to exit
"
`;
exports[`SessionBrowser UI States > SessionBrowserLoading renders correctly 1`] = `
" Loading sessions…
"
`;

View File

@@ -18,7 +18,7 @@ export const TodoTray: React.FC = () => {
const uiState = useUIState();
const todos: TodoList | null = useMemo(() => {
// Find the most recent todo list written by the WriteTodosTool
// Find the most recent todo list written by tools that output a TodoList (e.g., WriteTodosTool or Tracker tools)
for (let i = uiState.history.length - 1; i >= 0; i--) {
const entry = uiState.history[i];
if (entry.type !== 'tool_group') {