Restore Agent workspace and add platform pixel avatars

This commit is contained in:
鲨鱼辣椒 committed 2026-10-12 17:05:24 +08:00
1 parent 7a7d1f7fd8
commit c14d996c05
22 files changed
+1387 -462

No files matched your search

+37 -2
View File
@@ -45,6 +45,42 @@ beforeEach(() => { vi.clearAllMocks(); journalRecords.clear(); clearWorksSquareS
afterEach(() => { instances.splice(0).forEach((module) => module.dispose()); clearWorksSquareSession(); vi.useRealTimers(); });
describe('Main cloud Agents boundary', () => {
it.each(Array.from({ length: 16 }, (_, index) => `avatar-${String(index + 1).padStart(2, '0')}`))('uploads the bundled platform portrait %s through scoped Main transport without a dialog', async id => {
const icon = '/api/storage/public/images/creator/preset.png';
const transport = vi.fn().mockResolvedValueOnce(session()).mockResolvedValueOnce(json({ icon, private: 'hidden' }));
expect(await moduleFor(transport).useAvatarPreset({ id })).toEqual({ icon, icon_url: 'https://agents.example.test' + icon });
expect(desktop.pick).not.toHaveBeenCalled();
expect(transport.mock.calls[1][0]).toBe('https://agents.example.test/api/makelore/avatars');
expect(transport.mock.calls[1][1].headers).toEqual({ Authorization: 'Bearer yuxi-secret' });
const file = (transport.mock.calls[1][1].body as FormData).get('file') as File;
expect(file.name).toBe(`${id}.png`);
expect(file.type).toBe('image/png');
const bytes = Buffer.from(await file.arrayBuffer());
expect(bytes.subarray(0, 8)).toEqual(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]));
expect(bytes.length).toBeGreaterThan(100000);
});
it.each(['avatar-00', 'avatar-17', '../../private/avatar.png', 'file:///tmp/avatar.png', 'data:image/png;base64,a', undefined])('rejects a non-allowlisted preset %s before transport', async id => {
const transport = vi.fn();
await expect(moduleFor(transport).useAvatarPreset({ id })).rejects.toMatchObject({ status: 422, code: 'invalid_input' });
expect(desktop.pick).not.toHaveBeenCalled();
expect(transport).not.toHaveBeenCalled();
});
it('requires a logged-in account for platform avatars and drops upload results after an account switch', async () => {
const transport = vi.fn();
const module = moduleFor(transport);
clearWorksSquareSession();
await expect(module.useAvatarPreset({ id: 'avatar-01' })).rejects.toMatchObject({ code: 'session_expired' });
expect(transport).not.toHaveBeenCalled();
login();
transport.mockResolvedValueOnce(session()).mockImplementationOnce(async () => {
login('b'.repeat(64));
return json({ icon: '/api/storage/public/images/other/preset.png' });
});
await expect(module.useAvatarPreset({ id: 'avatar-01' })).rejects.toMatchObject({ code: 'account_changed' });
});
it('uploads avatar bytes through Main and resolves Yuxi public URLs without exposing credentials', async () => {
const directory = await mkdtemp(join(tmpdir(), 'makelore-avatar-'));
try {
@@ -106,8 +142,7 @@ describe('Main cloud Agents boundary', () => {
expect(await module.execute({ operation: 'version', input: { slug: draft.slug, version: '1' } })).toMatchObject(avatar);
});
it.each(['file:///private/avatar.png', 'javascript:alert(1)', 'https://secret@images.example.test/avatar.png'])
('falls back for an unusable legacy avatar URL %s', async icon => {
it.each(['file:///private/avatar.png', 'javascript:alert(1)', 'https://secret@images.example.test/avatar.png'])('falls back for an unusable legacy avatar URL %s', async icon => {
const transport = vi.fn().mockResolvedValueOnce(session()).mockResolvedValueOnce(json({ ...draft, icon }));
expect(await moduleFor(transport).get(draft.slug)).toMatchObject({ icon, icon_url: null });
});