afd699a060
新增 agent run 状态、停止、重试和恢复命令 把 run 生命周期写入 trace、activity、output 和 context bundle 补齐聊天入口、测试覆盖和实施计划文档
151 lines
5.2 KiB
TypeScript
151 lines
5.2 KiB
TypeScript
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('agent.kill')).toBe(true);
|
|
expect(needsInitializedChatProject('agent.retry')).toBe(true);
|
|
expect(needsInitializedChatProject('agent.resume')).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('describes agent run lifecycle controls before confirmation', () => {
|
|
expect(pendingCommandDetail({ id: 'agent.kill' }, '/tmp/game')).toBe(
|
|
'标记 /tmp/game/.agent/run.latest.json 为 killed,并写入 activity/output',
|
|
);
|
|
expect(pendingCommandDetail({ id: 'agent.retry' }, '/tmp/game')).toBe(
|
|
'标记 /tmp/game/.agent/run.latest.json 为 pending,等待 runner claim',
|
|
);
|
|
expect(
|
|
pendingCommandDetail(
|
|
{ id: 'agent.resume', detail: '继续修复输入监听' },
|
|
'/tmp/game',
|
|
),
|
|
).toBe('附加用户说明并标记 /tmp/game/.agent/run.latest.json 为 pending');
|
|
});
|
|
|
|
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');
|
|
});
|
|
});
|