mirror of
https://github.com/nexu-io/open-design.git
synced 2026-09-20 06:15:06 +08:00
98f2fd1a46
* fix(chat): render cards inside execution records Render supported od-card payloads inside execution records with the existing card components, instance scopes, and browser-assistance callback. Preserve Markdown code examples and isolate card payloads from later Markdown parsing. * test(web): await writable scope before deleting a conversation * fix(web): buffer streamed card opener prefixes * fix(web): remove undesigned ChatPanel cards (OPEND-2971) Remove task-brief and rule-proposal presentation and their exclusive UI, styles, and translations following the explicit product decision. Preserve quoted card examples, neighboring prose, and the three retained card kinds, including browser-assist callbacks. * fix(chat): stop generating undesigned brief and rule cards * test(web): use supported role query options for removed cards * fix(chat): hide retired brand browser assistance cards * fix(web): hide undesigned assistant message panels * test(web): specify the brand project kind in hidden UI fixture * style(web): remove trailing blank line after panel styles * fix(web): hide verification scorecards in ChatPanel * test(chat): align retired UI expectations with approved hiding * fix(chat): keep card payloads opaque to question form parsing * fix(web): preserve card parsing across replay metadata Keep marker masking aligned with physical run boundaries, and replace repeated Markdown tail scans with a forward indexed walk. Preserve actual forms and raw code examples with replay and paragraph-boundary regression coverage. * fix(web): keep form field syntax inside its payload Recognize complete forms through the existing parser before scanning their fields for card or code markers. Preserve sibling form actions and keep outer card/code ownership with callback-based parsing that avoids an import cycle. * fix(chat): share question form protocol context with host detection --------- Co-authored-by: lefarcen <935902669@qq.com>
94 lines
3.5 KiB
TypeScript
94 lines
3.5 KiB
TypeScript
// @vitest-environment jsdom
|
|
|
|
// The in-chat plugin action panel was retired by explicit product decision.
|
|
// Generated plugin files remain accessible while host install state changes;
|
|
// installation itself continues through the existing non-chat surfaces.
|
|
|
|
import { cleanup, fireEvent, render, screen } from '@testing-library/react';
|
|
import { afterEach, beforeAll, describe, expect, it, vi } from 'vitest';
|
|
|
|
import { AssistantMessage } from '../../src/components/AssistantMessage';
|
|
import type { AgentEvent, ChatMessage, ProjectFile } from '../../src/types';
|
|
|
|
beforeAll(() => {
|
|
if (window.localStorage) return;
|
|
const store = new Map<string, string>();
|
|
Object.defineProperty(window, 'localStorage', {
|
|
configurable: true,
|
|
value: {
|
|
clear: () => store.clear(),
|
|
getItem: (key: string) => store.get(key) ?? null,
|
|
removeItem: (key: string) => store.delete(key),
|
|
setItem: (key: string, value: string) => store.set(key, value),
|
|
},
|
|
});
|
|
});
|
|
|
|
afterEach(() => {
|
|
cleanup();
|
|
});
|
|
|
|
function pluginFolderFiles(folderPath: string): ProjectFile[] {
|
|
return [
|
|
{
|
|
name: `${folderPath}/open-design.json`,
|
|
path: `${folderPath}/open-design.json`,
|
|
size: 100,
|
|
mtime: 1700000005,
|
|
kind: 'code',
|
|
mime: 'application/json',
|
|
} as ProjectFile,
|
|
{
|
|
name: `${folderPath}/SKILL.md`,
|
|
path: `${folderPath}/SKILL.md`,
|
|
size: 100,
|
|
mtime: 1700000005,
|
|
kind: 'text',
|
|
mime: 'text/markdown',
|
|
} as ProjectFile,
|
|
];
|
|
}
|
|
|
|
function pluginMessage(folderPath: string): ChatMessage {
|
|
return {
|
|
id: 'msg-plugin-1',
|
|
role: 'assistant',
|
|
content: 'Plugin is ready to add to My plugins.',
|
|
runStatus: 'succeeded',
|
|
startedAt: 1700000000,
|
|
endedAt: 1700000005,
|
|
events: [{ kind: 'text', text: 'Plugin is ready to add to My plugins.' } as AgentEvent],
|
|
producedFiles: pluginFolderFiles(folderPath),
|
|
} as ChatMessage;
|
|
}
|
|
|
|
describe('AssistantMessage generated plugin files without in-chat install controls', () => {
|
|
it.each([false, true])('preserves files with a host active-install state of %s and never presents retired actions', (active) => {
|
|
const folderPath = 'my-skill';
|
|
const onAction = vi.fn();
|
|
const onOpen = vi.fn();
|
|
const props = {
|
|
message: pluginMessage(folderPath), streaming: false, isLast: true,
|
|
projectId: 'proj-1', projectFiles: pluginFolderFiles(folderPath),
|
|
onRequestOpenFile: onOpen, onRequestPluginFolderAgentAction: onAction,
|
|
};
|
|
const { rerender } = render(<AssistantMessage {...props}
|
|
hiddenPluginActionPaths={active ? new Set([folderPath]) : new Set()}
|
|
activePluginActionPaths={active ? new Set([folderPath]) : new Set()}
|
|
/>);
|
|
for (const file of pluginFolderFiles(folderPath)) {
|
|
expect(screen.getByTestId(`artifact-card-${file.name}`)).toBeTruthy();
|
|
}
|
|
expect(screen.queryByTestId(`assistant-plugin-install-${folderPath}`)).toBeNull();
|
|
expect(screen.queryByTestId(`plugin-folder-notice-${folderPath}`)).toBeNull();
|
|
expect(onAction).not.toHaveBeenCalled();
|
|
|
|
// Changing the host's install bookkeeping cannot recreate the retired UI.
|
|
rerender(<AssistantMessage {...props} hiddenPluginActionPaths={new Set()} activePluginActionPaths={new Set()} />);
|
|
expect(screen.queryByTestId(`assistant-plugin-actions-${folderPath}`)).toBeNull();
|
|
fireEvent.click(screen.getByTestId(`artifact-card-open-${folderPath}/open-design.json`));
|
|
expect(onOpen).toHaveBeenCalledWith(`${folderPath}/open-design.json`);
|
|
expect(onAction).not.toHaveBeenCalled();
|
|
});
|
|
});
|