99be1d76fe
- 新增 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 技术文档
76 lines
2.7 KiB
TypeScript
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');
|
|
});
|
|
});
|