wip: first run of implementation

This commit is contained in:
2026-02-25 20:29:01 +01:00
parent 2e203fa3a9
commit 20ea499a6f
40 changed files with 2170 additions and 22 deletions

View File

@@ -55,6 +55,18 @@ describe('Editor dashboard timeline', () => {
]);
(window as any).electronAPI.posts.getTagsWithCounts = vi.fn().mockResolvedValue([]);
(window as any).electronAPI.posts.getCategoriesWithCounts = vi.fn().mockResolvedValue([]);
(window as any).electronAPI.chat = {
getProtocolHealth: vi.fn().mockResolvedValue({
totalTurns: 10,
validEnvelopeTurns: 9,
repairAttempts: 1,
fallbackTurns: 0,
blockedActionCount: 2,
parseValidityRate: 0.9,
repairRate: 0.1,
fallbackRate: 0,
}),
};
(window as any).electronAPI.tags = {
getAll: vi.fn().mockResolvedValue([]),
};
@@ -82,4 +94,17 @@ describe('Editor dashboard timeline', () => {
expect(screen.getByText('2024')).toBeInTheDocument();
});
it('renders protocol telemetry stats in dashboard', async () => {
render(<Editor />);
await act(async () => {
await Promise.resolve();
await Promise.resolve();
await Promise.resolve();
});
expect(screen.getByText('90%')).toBeInTheDocument();
expect(screen.getByText('2 blocked actions')).toBeInTheDocument();
});
});

View File

@@ -0,0 +1,30 @@
import { describe, expect, it } from 'vitest';
import { toClarificationElements } from '../../../src/renderer/navigation/protocolNeedsInput';
describe('protocolNeedsInput', () => {
it('builds a clarification form element when required fields are provided', () => {
const elements = toClarificationElements({
required: true,
fields: [
{ key: 'date', label: 'Date', inputType: 'date', required: true },
{ key: 'category', label: 'Category', inputType: 'select', options: [{ label: 'A', value: 'a' }] },
],
});
expect(elements).toHaveLength(1);
expect(elements[0]).toMatchObject({
type: 'form',
formId: 'agui-needs-input',
action: 'submitNeedsInput',
});
});
it('returns empty elements when input is not required', () => {
const elements = toClarificationElements({
required: false,
fields: [],
});
expect(elements).toEqual([]);
});
});

View File

@@ -25,6 +25,7 @@ describe('pythonApiContractV1', () => {
'app.getSystemLanguage',
'chat.getConversations',
'chat.sendMessage',
'chat.getProtocolHealth',
]));
});
@@ -45,7 +46,7 @@ describe('pythonApiContractV1', () => {
it('contains semantic version metadata for compatibility checks', () => {
expect(BDS_PYTHON_API_CONTRACT_V1).toMatchObject({
version: '1.3.0',
version: '1.4.0',
generatedAt: expect.any(String),
});
});
@@ -55,6 +56,7 @@ describe('pythonApiContractV1', () => {
expect.objectContaining({ name: 'PostData' }),
expect.objectContaining({ name: 'MediaData' }),
expect.objectContaining({ name: 'ProjectData' }),
expect.objectContaining({ name: 'ProtocolTelemetrySnapshot' }),
]));
});
});

View File

@@ -29,12 +29,16 @@ describe('invokePythonApiMethodV1', () => {
const getProjectMetadata = vi.fn().mockResolvedValue({ name: 'My Project' });
const getAllProjects = vi.fn().mockResolvedValue([{ id: 'prj-1', name: 'Main' }]);
const getAllPosts = vi.fn().mockResolvedValue({ items: [], hasMore: false, total: 0 });
const getProtocolHealth = vi.fn().mockResolvedValue({ totalTurns: 1, parseValidityRate: 1 });
vi.stubGlobal('window', {
electronAPI: {
projects: {
getAll: getAllProjects,
},
chat: {
getProtocolHealth,
},
posts: {
search: searchPosts,
getAll: getAllPosts,
@@ -49,10 +53,12 @@ describe('invokePythonApiMethodV1', () => {
await expect(invokePythonApiMethodV1('posts.getAll', { options: { limit: 10, offset: 5 } })).resolves.toEqual({ items: [], hasMore: false, total: 0 });
await expect(invokePythonApiMethodV1('posts.search', { query: 'hit' })).resolves.toEqual([{ id: 'p1', title: 'Hit' }]);
await expect(invokePythonApiMethodV1('meta.getProjectMetadata', {})).resolves.toEqual({ name: 'My Project' });
await expect(invokePythonApiMethodV1('chat.getProtocolHealth', {})).resolves.toEqual({ totalTurns: 1, parseValidityRate: 1 });
expect(getAllProjects).toHaveBeenCalledWith();
expect(getAllPosts).toHaveBeenCalledWith({ limit: 10, offset: 5 });
expect(searchPosts).toHaveBeenCalledWith('hit');
expect(getProjectMetadata).toHaveBeenCalledWith();
expect(getProtocolHealth).toHaveBeenCalledWith();
});
it('rejects unknown methods and malformed args', async () => {
@@ -66,6 +72,9 @@ describe('invokePythonApiMethodV1', () => {
projects: {
getAll: vi.fn(),
},
chat: {
getProtocolHealth: vi.fn(),
},
meta: {
getProjectMetadata: vi.fn(),
},