From 0eeffc6875195023a5ccffb90dd08b65179cebed Mon Sep 17 00:00:00 2001 From: yyyanghj Date: Mon, 17 Nov 2025 10:58:33 +0800 Subject: [PATCH] feat: add support for Trae editor (#1037) --- .../cli/src/ui/commands/terminalSetupCommand.ts | 2 +- .../cli/src/ui/editors/editorSettingsManager.ts | 1 + packages/cli/src/ui/utils/terminalSetup.ts | 15 ++++++++++++++- packages/core/src/utils/editor.test.ts | 5 +++++ packages/core/src/utils/editor.ts | 10 ++++++++-- 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/ui/commands/terminalSetupCommand.ts b/packages/cli/src/ui/commands/terminalSetupCommand.ts index 09e5240c..31b473c7 100644 --- a/packages/cli/src/ui/commands/terminalSetupCommand.ts +++ b/packages/cli/src/ui/commands/terminalSetupCommand.ts @@ -17,7 +17,7 @@ import { terminalSetup } from '../utils/terminalSetup.js'; export const terminalSetupCommand: SlashCommand = { name: 'terminal-setup', description: - 'Configure terminal keybindings for multiline input (VS Code, Cursor, Windsurf)', + 'Configure terminal keybindings for multiline input (VS Code, Cursor, Windsurf, Trae)', kind: CommandKind.BUILT_IN, action: async (): Promise => { diff --git a/packages/cli/src/ui/editors/editorSettingsManager.ts b/packages/cli/src/ui/editors/editorSettingsManager.ts index 8f5c3710..612e4ff5 100644 --- a/packages/cli/src/ui/editors/editorSettingsManager.ts +++ b/packages/cli/src/ui/editors/editorSettingsManager.ts @@ -25,6 +25,7 @@ export const EDITOR_DISPLAY_NAMES: Record = { vscodium: 'VSCodium', windsurf: 'Windsurf', zed: 'Zed', + trae: 'Trae', }; class EditorSettingsManager { diff --git a/packages/cli/src/ui/utils/terminalSetup.ts b/packages/cli/src/ui/utils/terminalSetup.ts index a7b00d86..af5367f7 100644 --- a/packages/cli/src/ui/utils/terminalSetup.ts +++ b/packages/cli/src/ui/utils/terminalSetup.ts @@ -48,7 +48,7 @@ export interface TerminalSetupResult { requiresRestart?: boolean; } -type SupportedTerminal = 'vscode' | 'cursor' | 'windsurf'; +type SupportedTerminal = 'vscode' | 'cursor' | 'windsurf' | 'trae'; // Terminal detection async function detectTerminal(): Promise { @@ -68,6 +68,11 @@ async function detectTerminal(): Promise { ) { return 'windsurf'; } + + if (process.env['TERM_PRODUCT']?.toLowerCase().includes('trae')) { + return 'trae'; + } + // Check VS Code last since forks may also set VSCODE env vars if (termProgram === 'vscode' || process.env['VSCODE_GIT_IPC_HANDLE']) { return 'vscode'; @@ -86,6 +91,8 @@ async function detectTerminal(): Promise { return 'cursor'; if (parentName.includes('code') || parentName.includes('Code')) return 'vscode'; + if (parentName.includes('trae') || parentName.includes('Trae')) + return 'trae'; } catch (error) { // Continue detection even if process check fails console.debug('Parent process detection failed:', error); @@ -287,6 +294,10 @@ async function configureWindsurf(): Promise { return configureVSCodeStyle('Windsurf', 'Windsurf'); } +async function configureTrae(): Promise { + return configureVSCodeStyle('Trae', 'Trae'); +} + /** * Main terminal setup function that detects and configures the current terminal. * @@ -333,6 +344,8 @@ export async function terminalSetup(): Promise { return configureCursor(); case 'windsurf': return configureWindsurf(); + case 'trae': + return configureTrae(); default: return { success: false, diff --git a/packages/core/src/utils/editor.test.ts b/packages/core/src/utils/editor.test.ts index acc9e1a1..dd3202b8 100644 --- a/packages/core/src/utils/editor.test.ts +++ b/packages/core/src/utils/editor.test.ts @@ -72,6 +72,7 @@ describe('editor utils', () => { { editor: 'neovim', commands: ['nvim'], win32Commands: ['nvim'] }, { editor: 'zed', commands: ['zed', 'zeditor'], win32Commands: ['zed'] }, { editor: 'emacs', commands: ['emacs'], win32Commands: ['emacs.exe'] }, + { editor: 'trae', commands: ['trae'], win32Commands: ['trae'] }, ]; for (const { editor, commands, win32Commands } of testCases) { @@ -171,6 +172,7 @@ describe('editor utils', () => { }, { editor: 'cursor', commands: ['cursor'], win32Commands: ['cursor'] }, { editor: 'zed', commands: ['zed', 'zeditor'], win32Commands: ['zed'] }, + { editor: 'trae', commands: ['trae'], win32Commands: ['trae'] }, ]; for (const { editor, commands, win32Commands } of guiEditors) { @@ -321,6 +323,7 @@ describe('editor utils', () => { 'windsurf', 'cursor', 'zed', + 'trae', ]; for (const editor of guiEditors) { @@ -430,6 +433,7 @@ describe('editor utils', () => { 'windsurf', 'cursor', 'zed', + 'trae', ]; for (const editor of guiEditors) { it(`should not call onEditorClose for ${editor}`, async () => { @@ -481,6 +485,7 @@ describe('editor utils', () => { 'windsurf', 'cursor', 'zed', + 'trae', ]; for (const editor of guiEditors) { it(`should not allow ${editor} in sandbox mode`, () => { diff --git a/packages/core/src/utils/editor.ts b/packages/core/src/utils/editor.ts index 1023abe4..b6328925 100644 --- a/packages/core/src/utils/editor.ts +++ b/packages/core/src/utils/editor.ts @@ -14,7 +14,8 @@ export type EditorType = | 'vim' | 'neovim' | 'zed' - | 'emacs'; + | 'emacs' + | 'trae'; function isValidEditorType(editor: string): editor is EditorType { return [ @@ -26,6 +27,7 @@ function isValidEditorType(editor: string): editor is EditorType { 'neovim', 'zed', 'emacs', + 'trae', ].includes(editor); } @@ -62,6 +64,7 @@ const editorCommands: Record< neovim: { win32: ['nvim'], default: ['nvim'] }, zed: { win32: ['zed'], default: ['zed', 'zeditor'] }, emacs: { win32: ['emacs.exe'], default: ['emacs'] }, + trae: { win32: ['trae'], default: ['trae'] }, }; export function checkHasEditorType(editor: EditorType): boolean { @@ -73,7 +76,9 @@ export function checkHasEditorType(editor: EditorType): boolean { export function allowEditorTypeInSandbox(editor: EditorType): boolean { const notUsingSandbox = !process.env['SANDBOX']; - if (['vscode', 'vscodium', 'windsurf', 'cursor', 'zed'].includes(editor)) { + if ( + ['vscode', 'vscodium', 'windsurf', 'cursor', 'zed', 'trae'].includes(editor) + ) { return notUsingSandbox; } // For terminal-based editors like vim and emacs, allow in sandbox. @@ -115,6 +120,7 @@ export function getDiffCommand( case 'windsurf': case 'cursor': case 'zed': + case 'trae': return { command, args: ['--wait', '--diff', oldPath, newPath] }; case 'vim': case 'neovim':