import { describe, expect, it } from 'vitest'; import { isAbsoluteProjectPath, needsInitializedChatProject, parseRememberInput, pendingCommandDetail, resolveChatProjectPath, resolvePendingCommandProjectPath, } from '../src/App'; describe('AI 游戏创作聊天记忆命令', () => { it('recognizes local project absolute paths across desktop platforms', () => { expect(isAbsoluteProjectPath('/tmp/game')).toBe(true); expect(isAbsoluteProjectPath('C:\\Games\\demo')).toBe(true); expect(isAbsoluteProjectPath('D:/Games/demo')).toBe(true); expect(isAbsoluteProjectPath('relative-game')).toBe(false); }); it('defaults /remember to long memory and supports short memory scope', () => { expect(parseRememberInput('主角喜欢反弹弹幕')).toEqual({ scope: 'long', content: '主角喜欢反弹弹幕', }); expect(parseRememberInput('short 本轮先修输入手感')).toEqual({ scope: 'short', content: '本轮先修输入手感', }); expect(parseRememberInput('长期 保留厨房主题')).toEqual({ scope: 'long', content: '保留厨房主题', }); expect(parseRememberInput('project 覆盖后的长期设定')).toEqual({ scope: 'long', content: '覆盖后的长期设定', }); }); it('describes append and replace memory writes before confirmation', () => { expect( pendingCommandDetail( { id: 'memory.write', scope: 'long', content: '保留厨房主题', mode: 'append', }, '/tmp/game', ), ).toBe('追加到 /tmp/game/memory/project.md'); expect( pendingCommandDetail( { id: 'memory.write', scope: 'short', content: '覆盖本轮上下文', mode: 'replace', }, '/tmp/game', ), ).toBe('覆盖保存到 /tmp/game/memory/session.md'); }); it('requires an initialized local project before chat memory writes', () => { expect(resolveChatProjectPath(null)).toBeNull(); expect(resolveChatProjectPath({ projectPath: '/tmp/game' })).toBe( '/tmp/game', ); expect(parseRememberInput('long')).toEqual({ scope: 'long', content: '', }); expect(parseRememberInput('short 覆盖本轮上下文')).toEqual({ scope: 'short', content: '覆盖本轮上下文', }); expect( pendingCommandDetail( { id: 'memory.delete', scope: 'short', }, '/tmp/game', ), ).toBe('删除 /tmp/game/memory/session.md'); }); it('describes local generation side effects before confirmation', () => { expect( pendingCommandDetail( { id: 'game.generate_draft', prompt: '做一个厨房弹幕游戏', }, '/tmp/game', ), ).toBe( '调用 LLM Planner / Generator,编排 6 组角色 brief,写入 /tmp/game/game、assets、memory、exports,通过 Evaluator 和自检后启动本地 HTTP 预览并交给外部浏览器', ); }); it('requires a project before chat commands write or run local artifacts', () => { expect(needsInitializedChatProject('game.generate_draft')).toBe(true); expect(needsInitializedChatProject('asset.upload')).toBe(true); expect(needsInitializedChatProject('command.run_limited')).toBe(true); expect(needsInitializedChatProject('preview.open')).toBe(true); expect(needsInitializedChatProject('preview.start')).toBe(true); expect(needsInitializedChatProject('canvas.project_sync')).toBe(true); expect(needsInitializedChatProject('canvas.export_import')).toBe(true); expect(needsInitializedChatProject('memory.write')).toBe(true); expect(needsInitializedChatProject('memory.delete')).toBe(true); expect(needsInitializedChatProject('project.create')).toBe(false); expect(needsInitializedChatProject('canvas.project_open')).toBe(false); }); it('shows the authorized project path in pending write command details', () => { expect( resolvePendingCommandProjectPath( { id: 'game.generate_draft', prompt: '做一个厨房弹幕游戏' }, { projectPath: '/authorized/game' }, '/draft/dev-input', ), ).toBe('/authorized/game'); expect( resolvePendingCommandProjectPath( { id: 'project.create', projectPath: '/new/game' }, { projectPath: '/authorized/game' }, '/draft/dev-input', ), ).toBe('/new/game'); }); });