Files
Genarrative/apps/ai-game-creator-shell/tests/windowsCommandPresentation.test.ts
k88936 99be1d76fe 抽离 DirectProject 独立聊天容器并删除工作台壳 Direct 状态
- 新增 view/project-development/chat 模块:DirectProjectChatView 自己持有项目清单订阅、首屏锚点、历史分页、发送队列、附件、终止、草稿与本地消息
- DirectProjectChatView 入参收窄为项目路径、入口首轮需求(canonical content[])和两条权限门,Direct 状态不再穿过 App.tsx
- 线程订阅与聊天 reducer 提成 useDirectThreadChatSubscription:subscribe/consume/notify 单飞循环、订阅欠账、SUBSCRIPTION_EXPIRED 重订与 DirectThreadChatState
- chat/components 按「一个组件一个目录、逻辑与表现同目录」重组(ChatHeader、Composer、Conversation、SettingsDialog、ToolCallGroup)
- DirectProjectChatView 拆成聊天头、会话区、回合、输入盒四个组件
- App.tsx 删除 Direct 专属 state/ref/effect/handler 与 directCodex 分支,首轮需求按 canonical content 交给聊天
- 工作台级动作(运行本地预览等)经 DirectProjectChatHandle.announce 交给聊天自己的本地消息流
- Direct 首轮认领记录提成 app/initialSupervisorMessageClaims,供各入口共用
- Rust 侧 Direct 契约 ts-rs 导出目录改到 chat/generated
- 补齐 direct_codex_user_item/wire.rs 既有的 rustfmt 空格漂移
- 同步 ADR、实施计划、decision-log、pitfalls 与 Direct 技术文档
2026-09-19 15:08:31 +08:00

76 lines
2.7 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import type { GameCreatorDirectToolCall } from '../src/app/types';
import {
toolCallInputText,
toolCallRowText,
} from '../src/view/project-development/chat/components/ToolCallGroup/toolCallGroupPresentation';
function commandCall(command: string): GameCreatorDirectToolCall {
return {
schemaVersion: 'agc-tool-call.v1',
id: 'command',
turnId: 'turn',
kind: 'command',
title: '执行命令',
summary: command.slice(0, 120),
status: 'completed',
startedAt: 1,
updatedAt: 2,
detail: { command, output: 'pwsh -Command output must stay unchanged' },
};
}
describe('Windows 命令卡片展示', () => {
it('从 WindowsApps 路径后的完整输入提取脚本,并解开 shlex 引号拼接', () => {
const script = `foreach ($f in @('game/package.json','game/vite.config.js','game/index.html','game/game.js')) { Write-Output "===== $f ====="; Get-Content -Raw $f }`;
const argument = "'" + script.replaceAll("'", "'\"'\"'") + "'";
const command = String.raw`"<absolute-path> Files\WindowsApps\Microsoft.PowerShell_7.6.6.0_x64__8wekyb3d8bbwe\pwsh.exe" -Command ${argument}`;
const call = commandCall(command);
expect(toolCallInputText(call)).toBe(script);
expect(toolCallRowText(call)).toBe(`${script.slice(0, 120)}…`);
expect(call.detail.command).toBe(command);
expect(call.detail.output).toBe('pwsh -Command output must stay unchanged');
});
it.each([
['pwsh -Command Get-Date', 'Get-Date'],
[
'pwsh.exe -NoLogo -NoProfile -NonInteractive -Command "Get-Date"',
'Get-Date',
],
[
String.raw`"C:\Program Files\PowerShell\7\pwsh.exe" -c 'Get-Date'`,
'Get-Date',
],
["POWERSHELL.EXE -ExecutionPolicy Bypass -Command 'Get-Date'", 'Get-Date'],
[
String.raw`pwsh -Command "Write-Output \"hello\"; Get-Content C:\game\a.txt"`,
String.raw`Write-Output "hello"; Get-Content C:\game\a.txt`,
],
["pwsh -Command 'Get-Date\nGet-Location'", 'Get-Date\nGet-Location'],
["pwsh -Command 'Get-Date…", "'Get-Date…"],
])('隐藏启动器:%s', (command, script) => {
expect(toolCallInputText(commandCall(command))).toBe(script);
});
it.each([
'npm run build',
'pwsh -File game/build.ps1',
'pwsh -EncodedCommand ZgBvAG8A',
'not-pwsh.exe -Command Get-Date',
'echo pwsh -Command Get-Date',
"bash -c 'echo hello'",
])('保留非目标调用:%s', (command) => {
expect(toolCallInputText(commandCall(command))).toBe(command);
});
it('不改写 MCP 工具参数', () => {
const call = {
...commandCall('pwsh -Command Get-Date'),
kind: 'mcp_tool' as const,
};
expect(toolCallInputText(call)).toBe('pwsh -Command Get-Date');
});
});