Skip to content

Commit e9da5a6

Browse files
committed
refactor: enhance system prompts, config system, and i18n infrastructure
(cherry picked from commit 7f9e7a5)
1 parent ba0f394 commit e9da5a6

36 files changed

Lines changed: 1317 additions & 266 deletions

packages/cli/src/assets/help/cli-help-knowledge.md

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,20 @@ prompt = "请重构以下代码为纯函数:{{args}}"
152152

153153
---
154154

155+
### Q10: 如何快速调整主题、模型、Agent风格等常用设置?
156+
**A:** 使用 `/config` 命令打开**交互式设置面板**
157+
1. 直接输入 `/config` 并按回车。
158+
2. 你将看到一个可视化菜单,集成了所有常用设置:
159+
- **🎨 主题 (Theme)**:快速切换界面配色。
160+
- **🤖 AI 模型 (Model)**:在不同的 AI 模型间切换。
161+
- **🧠 Agent 风格 (Style)**:调整助手的行为风格(如默认、Codex、Cursor、Windsurf、Claude Code 等)。
162+
- **🚀 YOLO 模式**:开启/关闭工具调用自动批准。
163+
- **Vim 模式**:切换内置输入的 Vim 体验。
164+
- **🌐 语言偏好**:设置 AI 的回复语言。
165+
3. 使用方向键上下移动,按回车进入子菜单或确认选择,按 `Esc` 返回或退出。
166+
167+
---
168+
155169
## 📖 斜杠命令完整列表 (Slash Commands `/`)
156170
1. 输入斜杠则可以看到所有支持的斜杠命令
157171

@@ -402,6 +416,32 @@ prompt = "请重构以下代码为纯函数:{{args}}"
402416

403417
---
404418

419+
### `/config` - 统一配置菜单
420+
打开交互式设置面板,让您可以直观地配置 DeepV Code 的各种设置。常用的设置如主题、模型、Agent 风格等都在这里了。
421+
422+
**用法:** `/config [子命令]`
423+
424+
**功能:**
425+
- **交互式面板:** 直接输入 `/config` 回车,打开可视化菜单。
426+
- **常用设置:** 面板集成了主题、编辑器、模型切换、Vim 模式、Agent 风格、YOLO 模式、健康使用提醒及语言偏好。
427+
- **快捷操作:** 支持键盘上下移动、回车进入子菜单、`Esc` 返回或关闭。
428+
429+
**子命令:**
430+
- `/config theme` - 打开主题选择
431+
- `/config model` - 打开模型选择
432+
- `/config agent-style` - 切换 Agent 风格
433+
- `/config yolo [on|off]` - 切换 YOLO 自动批准模式
434+
- `/config language [name]` - 设置回复语言偏好
435+
436+
**示例:**
437+
```
438+
/config
439+
/config model claude
440+
/config yolo on
441+
```
442+
443+
---
444+
405445
### `/tools` - 工具列表
406446
显示当前可用的所有工具(内置 + MCP)。
407447

@@ -621,6 +661,20 @@ prompt = "请重构以下代码为纯函数:{{args}}"
621661

622662
---
623663

664+
### Q10: 如何快速调整主题、模型、Agent风格等常用设置?
665+
**A:** 使用 `/config` 命令打开**交互式设置面板**
666+
1. 直接输入 `/config` 并按回车。
667+
2. 你将看到一个可视化菜单,集成了所有常用设置:
668+
- **🎨 主题 (Theme)**:快速切换界面配色。
669+
- **🤖 AI 模型 (Model)**:在不同的 AI 模型间切换。
670+
- **🧠 Agent 风格 (Style)**:调整助手的行为风格(如默认、Codex、Cursor、Windsurf、Claude Code 等)。
671+
- **🚀 YOLO 模式**:开启/关闭工具调用自动批准。
672+
- **Vim 模式**:切换内置输入的 Vim 体验。
673+
- **🌐 语言偏好**:设置 AI 的回复语言。
674+
3. 使用方向键上下移动,按回车进入子菜单或确认选择,按 `Esc` 返回或退出。
675+
676+
---
677+
624678
## 📖 斜杠命令完整列表 (Slash Commands `/`)
625679
1. 输入斜杠则可以看到所有支持的斜杠命令
626680

@@ -871,6 +925,32 @@ prompt = "请重构以下代码为纯函数:{{args}}"
871925

872926
---
873927

928+
### `/config` - 统一配置菜单
929+
打开交互式设置面板,让您可以直观地配置 DeepV Code 的各种设置。常用的设置如主题、模型、Agent 风格等都在这里了。
930+
931+
**用法:** `/config [子命令]`
932+
933+
**功能:**
934+
- **交互式面板:** 直接输入 `/config` 回车,打开可视化菜单。
935+
- **常用设置:** 面板集成了主题、编辑器、模型切换、Vim 模式、Agent 风格、YOLO 模式、健康使用提醒及语言偏好。
936+
- **快捷操作:** 支持键盘上下移动、回车进入子菜单、`Esc` 返回或关闭。
937+
938+
**子命令:**
939+
- `/config theme` - 打开主题选择
940+
- `/config model` - 打开模型选择
941+
- `/config agent-style` - 切换 Agent 风格
942+
- `/config yolo [on|off]` - 切换 YOLO 自动批准模式
943+
- `/config language [name]` - 设置回复语言偏好
944+
945+
**示例:**
946+
```
947+
/config
948+
/config model claude
949+
/config yolo on
950+
```
951+
952+
---
953+
874954
### `/tools` - 工具列表
875955
显示当前可用的所有工具(内置 + MCP)。
876956

@@ -957,27 +1037,36 @@ prompt = "请重构以下代码为纯函数:{{args}}"
9571037
---
9581038

9591039
### `/agent-style` - AI 风格切换
960-
切换 AI 工作风格:默认风格(强调计划和解释)或 Codex 风格(快速静默执行)
1040+
切换 AI 工作风格:包括默认风格、Codex 极速风格,以及受 Cursor、Augment 等工具启发的一系列专业风格
9611041

9621042
**用法:** `/agent-style [子命令]`
9631043

9641044
**子命令:**
9651045
- 无参数或 `status` - 显示当前风格及使用说明
9661046
- `default` - 切换到默认风格(🧠 强调计划、解释)
9671047
- `codex` - 切换到 Codex 风格(⚡ 快速确认后静默执行)
1048+
- `cursor` - 切换到 Cursor 风格(🎯 语义搜索优先,高并发调用)
1049+
- `augment` - 切换到 Augment 风格(🚀 任务列表驱动,严格验证)
1050+
- `claude-code` - 切换到 Claude Code 风格(⌨️ 极致极简,极高响应效率)
1051+
- `antigravity` - 切换到 Antigravity 风格(💎 知识库优先,高端协作流程)
1052+
- `windsurf` - 切换到 Windsurf 风格(🌊 基于 AI Flow 范式的独立与协作平衡)
9681053

9691054
**工作模式对比:**
9701055

9711056
| 风格 | 特点 | 适合场景 |
9721057
|-----|------|---------|
9731058
| **Default** 🧠 | 详细计划、充分解释、步骤确认 | 学习、复杂任务、需要理解过程 |
9741059
| **Codex**| 快速执行、最少输出、静默完成 | 熟练场景、重复任务、追求效率 |
1060+
| **Cursor** 🎯 | 语义搜索增强、详细代码风格规范 | 大规模代码库探索、对代码质量有极高要求 |
1061+
| **Augment** 🚀 | 任务列表驱动、严格的版本控制和验证 | 复杂多步骤重构、需要严格执行流程的场景 |
1062+
| **Claude Code** ⌨️ | 极简响应、直接行动、杜绝废话 | 高频 CLI 交互、追求极致开发心流 |
1063+
| **Antigravity** 💎 | 知识发现优先、高端协作美学 | 深度研究、追求极致协同体验 |
1064+
| **Windsurf** 🌊 | AI Flow 范式、独立与协作平衡 | 现代 AI 驱动的全流程开发 |
9751065

9761066
**示例:**
9771067
```
9781068
/agent-style # 查看当前状态
979-
/agent-style default # 切换到默认风格
980-
/agent-style codex # 切换到 Codex 风格
1069+
/agent-style cursor # 切换到 Cursor 风格
9811070
/agent-style status # 查看当前状态
9821071
```
9831072

packages/cli/src/config/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,7 @@ export async function loadCliConfig(
584584
silentMode: isNonInteractiveMode,
585585
hooks: settings.hooks,
586586
healthyUse: settings.healthyUse ?? true,
587+
preferredLanguage: settings.preferredLanguage,
587588
});
588589

589590
// Set memory file paths for display in UI

packages/cli/src/config/settings.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ export interface Settings {
151151

152152
// 健康使用提醒开关
153153
healthyUse?: boolean;
154+
155+
// 语言偏好设置
156+
preferredLanguage?: string;
154157
}
155158

156159
export interface SettingsError {

packages/cli/src/gemini.tsx

Lines changed: 102 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { getUserStartupWarnings } from './utils/userStartupWarnings.js';
2626
import { runNonInteractive } from './nonInteractiveCli.js';
2727
import { loadExtensions, Extension } from './config/extension.js';
2828
import { cleanupCheckpoints, registerCleanup, runExitCleanup } from './utils/cleanup.js';
29+
import { getIsQuitting } from './utils/quitState.js';
2930
import { getCliVersion } from './utils/version.js';
3031
import { checkForUpdates, executeUpdateCommand } from './ui/utils/updateCheck.js';
3132
import {
@@ -211,6 +212,56 @@ async function askUserForUpdate(): Promise<boolean> {
211212
});
212213
}
213214

215+
// -------------------------------------------------------------------------
216+
// Startup Animation Logic
217+
// -------------------------------------------------------------------------
218+
let startupTimer: NodeJS.Timeout | null = null;
219+
220+
function startStartupAnimation() {
221+
if (!process.stdout.isTTY || process.env.CI || process.env.DEEPV_SILENT_MODE === 'true' || process.env.NO_COLOR) {
222+
return;
223+
}
224+
225+
let count = 0;
226+
const maxChars = 20; // Maximum number of '=' chars
227+
228+
// Hide cursor to prevent flickering
229+
process.stdout.write('\x1b[?25l');
230+
231+
// Print the static message first with a newline
232+
process.stdout.write('DeepV Code is starting...\n');
233+
234+
const renderFrame = () => {
235+
// \x1b[2K: Clear entire line
236+
// \r: Return to start of line
237+
// Only animate the second line
238+
process.stdout.write(`\x1b[2K\r${'='.repeat(count)}`);
239+
};
240+
241+
// Render first frame immediately
242+
renderFrame();
243+
244+
startupTimer = setInterval(() => {
245+
count = (count + 1) % (maxChars + 1);
246+
renderFrame();
247+
}, 100);
248+
}
249+
250+
function stopStartupAnimation() {
251+
if (startupTimer) {
252+
clearInterval(startupTimer);
253+
startupTimer = null;
254+
255+
if (process.stdout.isTTY) {
256+
// Clear the animation line (current line)
257+
// Then move up one line (\x1b[1A) and clear the text line
258+
// Finally restore cursor (\x1b[?25h)
259+
process.stdout.write('\x1b[2K\r\x1b[1A\x1b[2K\r\x1b[?25h');
260+
}
261+
}
262+
}
263+
// -------------------------------------------------------------------------
264+
214265
/**
215266
* Check if checkpoint history size exceeds 2GB and prompt for cleanup
216267
*/
@@ -309,6 +360,9 @@ export async function main() {
309360
// Clear screen at startup for clean interface
310361
console.clear();
311362

363+
// Start simple loading animation
364+
startStartupAnimation();
365+
312366
setupUnhandledRejectionHandler();
313367

314368
// Setup Git error monitoring early to catch initialization errors
@@ -364,6 +418,7 @@ export async function main() {
364418

365419
// Handle --update flag
366420
if (argv.update) {
421+
stopStartupAnimation();
367422
console.log(t('update.force.checking'));
368423
const updateMessage = await checkForUpdates(true, true);
369424

@@ -500,6 +555,7 @@ export async function main() {
500555

501556
// Early check for list-sessions to avoid unnecessary session management
502557
if (argv.listSessions) {
558+
stopStartupAnimation();
503559
const tempConfig = await loadCliConfig(
504560
settings.merged,
505561
extensions,
@@ -512,6 +568,7 @@ export async function main() {
512568

513569
// Handle --export-session flag
514570
if (argv.exportSession) {
571+
stopStartupAnimation();
515572
try {
516573
const sessionId = argv.exportSession;
517574
console.log(tp('export.exporting', { sessionId }));
@@ -526,6 +583,7 @@ export async function main() {
526583

527584
// Handle --test-audio flag
528585
if (argv.testAudio) {
586+
stopStartupAnimation();
529587
console.log('🎵 Testing audio notifications...');
530588
console.log('This will test all three notification sounds with a 1-second delay between each.');
531589
console.log('Make sure your speakers/headphones are on and volume is audible.\n');
@@ -550,23 +608,43 @@ export async function main() {
550608
const sessionManager = new SessionManager(workspaceRoot);
551609

552610
// 添加进程信号处理器,确保在意外退出时也能清理空会话
611+
let isExiting = false;
612+
553613
const handleExit = async () => {
614+
// 1. 如果已经在退出中,不重复执行
615+
if (isExiting) return;
616+
isExiting = true;
617+
618+
// 🎯 macOS 优化:如果正在通过 /quit 优雅退出,快速 Ctrl+C 直接 exit 不执行 JS 清理
619+
// 这避免了多个信号处理器同时执行导致的内存积累和 OOM
620+
if (getIsQuitting()) {
621+
process.exit(0);
622+
return;
623+
}
624+
625+
// 2. 立即移除所有现有的 SIGINT/SIGTERM 监听器(关键:防止第三方库如Ink或用户继续按Ctrl+C导致的重入)
626+
process.removeAllListeners('SIGINT');
627+
process.removeAllListeners('SIGTERM');
628+
629+
// 3. 注册“自杀”监听器:如果用户再次按 Ctrl+C,直接强制退出,不执行任何 JS 逻辑
630+
const forceExit = () => process.exit(1);
631+
process.on('SIGINT', forceExit);
632+
process.on('SIGTERM', forceExit);
633+
634+
// 4. 设置安全网:5秒后如果还没退完,强制退出(防止清理逻辑死锁或 OOM)
635+
setTimeout(forceExit, 5000).unref();
636+
554637
try {
555638
await runExitCleanup();
639+
process.exit(0);
556640
} catch (error) {
557-
// 忽略清理错误,避免影响正常退出
641+
// 忽略清理错误,避免影响退出
642+
process.exit(1);
558643
}
559644
};
560645

561-
process.on('SIGINT', async () => {
562-
await handleExit();
563-
process.exit(0);
564-
});
565-
566-
process.on('SIGTERM', async () => {
567-
await handleExit();
568-
process.exit(0);
569-
});
646+
process.on('SIGINT', handleExit);
647+
process.on('SIGTERM', handleExit);
570648

571649
// Perform session cleanup based on settings (runs in background)
572650
const sessionCleanupConfig = settings.merged.sessionCleanup || {
@@ -649,6 +727,7 @@ export async function main() {
649727
}
650728

651729
if (config.getListExtensions()) {
730+
stopStartupAnimation();
652731
logIfNotSilent('log', 'Installed extensions:');
653732
for (const extension of extensions) {
654733
logIfNotSilent('log', `- ${extension.config.name}`);
@@ -780,6 +859,7 @@ export async function main() {
780859

781860
// Check for cloud mode
782861
if (argv.cloudMode) {
862+
stopStartupAnimation();
783863
const { startCloudMode } = await import('./remote/remoteServer.js');
784864
const { maskServerUrl } = await import('./utils/urlMask.js');
785865
const cloudServerUrl = argv.cloudServer || 'https://api-code.deepvlab.ai';
@@ -806,6 +886,8 @@ export async function main() {
806886

807887
// Render UI, passing necessary config values. Check that there is no command line question.
808888
if (shouldBeInteractive) {
889+
stopStartupAnimation();
890+
809891
// 检查历史记录大小并提示清理
810892
await checkAndPromptHistoryCleanup(settings);
811893

@@ -818,6 +900,9 @@ export async function main() {
818900
// 🚀 启动优化:给事件循环一个喘息机会,确保之前的初始化任务(如 Git, 进程检测)不会挤占首屏渲染
819901
await new Promise(resolve => setImmediate(resolve));
820902

903+
// Clear screen again before rendering Welcome UI to ensure cleanliness
904+
console.clear();
905+
821906
const instance = render(
822907
<React.StrictMode>
823908
<AppWrapper
@@ -832,7 +917,12 @@ export async function main() {
832917
{ exitOnCtrlC: false },
833918
);
834919

835-
registerCleanup(() => instance.unmount());
920+
registerCleanup(async () => {
921+
instance.unmount();
922+
// 等待 Ink/Yoga 清理资源,防止 WASM 内存访问错误
923+
// Wait for Ink/React to finish unmounting and Yoga to release resources
924+
await new Promise((resolve) => setTimeout(resolve, 200));
925+
});
836926

837927
// 注册会话清理函数,在程序退出时清理空会话
838928
registerCleanup(async () => {
@@ -882,6 +972,7 @@ export async function main() {
882972
});
883973

884974
// Non-interactive mode handled by runNonInteractive
975+
stopStartupAnimation(); // Ensure stopped before non-interactive mode
885976
const nonInteractiveConfig = await loadNonInteractiveConfig(
886977
config,
887978
extensions,

0 commit comments

Comments
 (0)