add Trae support
This commit is contained in:
@@ -2,4 +2,5 @@
|
||||
export * as clineProfile from './cline.js';
|
||||
export * as cursorProfile from './cursor.js';
|
||||
export * as rooProfile from './roo.js';
|
||||
export * as traeProfile from './trae.js';
|
||||
export * as windsurfProfile from './windsurf.js';
|
||||
|
||||
32
scripts/profiles/trae.js
Normal file
32
scripts/profiles/trae.js
Normal file
@@ -0,0 +1,32 @@
|
||||
// Trae conversion profile for rule-transformer
|
||||
import { createProfile, COMMON_TOOL_MAPPINGS } from './base-profile.js';
|
||||
|
||||
// Create trae profile using the base factory
|
||||
const traeProfile = createProfile({
|
||||
name: 'trae',
|
||||
displayName: 'Trae',
|
||||
url: 'trae.ai',
|
||||
docsUrl: 'docs.trae.ai',
|
||||
profileDir: '.trae',
|
||||
rulesDir: '.trae/rules',
|
||||
mcpConfig: false,
|
||||
mcpConfigName: 'trae_mcp_settings.json',
|
||||
fileExtension: '.mdc',
|
||||
targetExtension: '.md',
|
||||
toolMappings: COMMON_TOOL_MAPPINGS.STANDARD // Trae uses standard tool names
|
||||
});
|
||||
|
||||
// Export all the standard profile properties
|
||||
export const {
|
||||
conversionConfig,
|
||||
fileMap,
|
||||
globalReplacements,
|
||||
profileName,
|
||||
displayName,
|
||||
profileDir,
|
||||
rulesDir,
|
||||
mcpConfig,
|
||||
mcpConfigName,
|
||||
mcpConfigPath,
|
||||
getTargetRuleFilename
|
||||
} = traeProfile;
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @typedef {'cline' | 'cursor' | 'roo' | 'windsurf'} RulesProfile
|
||||
* @typedef {'cline' | 'cursor' | 'roo' | 'trae' | 'windsurf'} RulesProfile
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -13,6 +13,7 @@
|
||||
* - cline: Cline IDE rules
|
||||
* - cursor: Cursor IDE rules (default)
|
||||
* - roo: Roo Code IDE rules
|
||||
* - trae: Trae IDE rules
|
||||
* - windsurf: Windsurf IDE rules
|
||||
*
|
||||
* To add a new rule profile:
|
||||
@@ -20,7 +21,7 @@
|
||||
* 2. Create a profile file in scripts/profiles/{profile}.js
|
||||
* 3. Export it as {profile}Profile in scripts/profiles/index.js
|
||||
*/
|
||||
export const RULE_PROFILES = ['cline', 'cursor', 'roo', 'windsurf'];
|
||||
export const RULE_PROFILES = ['cline', 'cursor', 'roo', 'trae', 'windsurf'];
|
||||
|
||||
/**
|
||||
* Check if a given rule profile is valid
|
||||
|
||||
46
tests/integration/trae-init-functionality.test.js
Normal file
46
tests/integration/trae-init-functionality.test.js
Normal file
@@ -0,0 +1,46 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
describe('Trae Profile Initialization Functionality', () => {
|
||||
let traeProfileContent;
|
||||
|
||||
beforeAll(() => {
|
||||
const traeJsPath = path.join(
|
||||
process.cwd(),
|
||||
'scripts',
|
||||
'profiles',
|
||||
'trae.js'
|
||||
);
|
||||
traeProfileContent = fs.readFileSync(traeJsPath, 'utf8');
|
||||
});
|
||||
|
||||
test('trae.js uses factory pattern with correct configuration', () => {
|
||||
expect(traeProfileContent).toContain("name: 'trae'");
|
||||
expect(traeProfileContent).toContain("displayName: 'Trae'");
|
||||
expect(traeProfileContent).toContain("rulesDir: '.trae/rules'");
|
||||
expect(traeProfileContent).toContain("profileDir: '.trae'");
|
||||
});
|
||||
|
||||
test('trae.js configures .mdc to .md extension mapping', () => {
|
||||
expect(traeProfileContent).toContain("fileExtension: '.mdc'");
|
||||
expect(traeProfileContent).toContain("targetExtension: '.md'");
|
||||
});
|
||||
|
||||
test('trae.js uses standard tool mappings', () => {
|
||||
expect(traeProfileContent).toContain('COMMON_TOOL_MAPPINGS.STANDARD');
|
||||
// Should contain comment about standard tool names
|
||||
expect(traeProfileContent).toContain('standard tool names');
|
||||
});
|
||||
|
||||
test('trae.js contains correct URL configuration', () => {
|
||||
expect(traeProfileContent).toContain("url: 'trae.ai'");
|
||||
expect(traeProfileContent).toContain("docsUrl: 'docs.trae.ai'");
|
||||
});
|
||||
|
||||
test('trae.js has MCP configuration disabled', () => {
|
||||
expect(traeProfileContent).toContain('mcpConfig: false');
|
||||
expect(traeProfileContent).toContain(
|
||||
"mcpConfigName: 'trae_mcp_settings.json'"
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -23,6 +23,12 @@ describe('MCP Configuration Validation', () => {
|
||||
expectedConfigName: 'mcp.json',
|
||||
expectedPath: '.roo/mcp.json'
|
||||
},
|
||||
trae: {
|
||||
shouldHaveMcp: false,
|
||||
expectedDir: '.trae',
|
||||
expectedConfigName: 'trae_mcp_settings.json',
|
||||
expectedPath: '.trae/trae_mcp_settings.json'
|
||||
},
|
||||
cline: {
|
||||
shouldHaveMcp: false,
|
||||
expectedDir: '.clinerules',
|
||||
@@ -100,8 +106,11 @@ describe('MCP Configuration Validation', () => {
|
||||
});
|
||||
|
||||
test('should use profile-specific config name for non-MCP profiles', () => {
|
||||
const profile = getRulesProfile('cline');
|
||||
expect(profile.mcpConfigName).toBe('cline_mcp_settings.json');
|
||||
const clineProfile = getRulesProfile('cline');
|
||||
expect(clineProfile.mcpConfigName).toBe('cline_mcp_settings.json');
|
||||
|
||||
const traeProfile = getRulesProfile('trae');
|
||||
expect(traeProfile.mcpConfigName).toBe('trae_mcp_settings.json');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -134,6 +143,7 @@ describe('MCP Configuration Validation', () => {
|
||||
expect(mcpEnabledProfiles).toContain('windsurf');
|
||||
expect(mcpEnabledProfiles).toContain('roo');
|
||||
expect(mcpEnabledProfiles).not.toContain('cline');
|
||||
expect(mcpEnabledProfiles).not.toContain('trae');
|
||||
});
|
||||
|
||||
test('should provide all necessary information for MCP config creation', () => {
|
||||
|
||||
113
tests/unit/rule-transformer-trae.test.js
Normal file
113
tests/unit/rule-transformer-trae.test.js
Normal file
@@ -0,0 +1,113 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname } from 'path';
|
||||
import { convertRuleToProfileRule } from '../../src/utils/rule-transformer.js';
|
||||
import * as traeProfile from '../../scripts/profiles/trae.js';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
describe('Trae Rule Transformer', () => {
|
||||
const testDir = path.join(__dirname, 'temp-test-dir');
|
||||
|
||||
beforeAll(() => {
|
||||
// Create test directory
|
||||
if (!fs.existsSync(testDir)) {
|
||||
fs.mkdirSync(testDir, { recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
// Clean up test directory
|
||||
if (fs.existsSync(testDir)) {
|
||||
fs.rmSync(testDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it('should correctly convert basic terms', () => {
|
||||
// Create a test Cursor rule file with basic terms
|
||||
const testCursorRule = path.join(testDir, 'basic-terms.mdc');
|
||||
const testContent = `---
|
||||
description: Test Cursor rule for basic terms
|
||||
globs: **/*
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
This is a Cursor rule that references cursor.so and uses the word Cursor multiple times.
|
||||
Also has references to .mdc files.`;
|
||||
|
||||
fs.writeFileSync(testCursorRule, testContent);
|
||||
|
||||
// Convert it
|
||||
const testTraeRule = path.join(testDir, 'basic-terms.md');
|
||||
convertRuleToProfileRule(testCursorRule, testTraeRule, traeProfile);
|
||||
|
||||
// Read the converted file
|
||||
const convertedContent = fs.readFileSync(testTraeRule, 'utf8');
|
||||
|
||||
// Verify transformations
|
||||
expect(convertedContent).toContain('Trae');
|
||||
expect(convertedContent).toContain('trae.ai');
|
||||
expect(convertedContent).toContain('.md');
|
||||
expect(convertedContent).not.toContain('cursor.so');
|
||||
expect(convertedContent).not.toContain('Cursor rule');
|
||||
});
|
||||
|
||||
it('should correctly convert tool references', () => {
|
||||
// Create a test Cursor rule file with tool references
|
||||
const testCursorRule = path.join(testDir, 'tool-refs.mdc');
|
||||
const testContent = `---
|
||||
description: Test Cursor rule for tool references
|
||||
globs: **/*
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
- Use the search tool to find code
|
||||
- The edit_file tool lets you modify files
|
||||
- run_command executes terminal commands
|
||||
- use_mcp connects to external services`;
|
||||
|
||||
fs.writeFileSync(testCursorRule, testContent);
|
||||
|
||||
// Convert it
|
||||
const testTraeRule = path.join(testDir, 'tool-refs.md');
|
||||
convertRuleToProfileRule(testCursorRule, testTraeRule, traeProfile);
|
||||
|
||||
// Read the converted file
|
||||
const convertedContent = fs.readFileSync(testTraeRule, 'utf8');
|
||||
|
||||
// Verify transformations (Trae uses standard tool names, so no transformation)
|
||||
expect(convertedContent).toContain('search tool');
|
||||
expect(convertedContent).toContain('edit_file tool');
|
||||
expect(convertedContent).toContain('run_command');
|
||||
expect(convertedContent).toContain('use_mcp');
|
||||
});
|
||||
|
||||
it('should correctly update file references', () => {
|
||||
// Create a test Cursor rule file with file references
|
||||
const testCursorRule = path.join(testDir, 'file-refs.mdc');
|
||||
const testContent = `---
|
||||
description: Test Cursor rule for file references
|
||||
globs: **/*
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
This references [dev_workflow.mdc](mdc:.cursor/rules/dev_workflow.mdc) and
|
||||
[taskmaster.mdc](mdc:.cursor/rules/taskmaster.mdc).`;
|
||||
|
||||
fs.writeFileSync(testCursorRule, testContent);
|
||||
|
||||
// Convert it
|
||||
const testTraeRule = path.join(testDir, 'file-refs.md');
|
||||
convertRuleToProfileRule(testCursorRule, testTraeRule, traeProfile);
|
||||
|
||||
// Read the converted file
|
||||
const convertedContent = fs.readFileSync(testTraeRule, 'utf8');
|
||||
|
||||
// Verify transformations
|
||||
expect(convertedContent).toContain('(.trae/rules/dev_workflow.md)');
|
||||
expect(convertedContent).toContain('(.trae/rules/taskmaster.md)');
|
||||
expect(convertedContent).not.toContain('(mdc:.cursor/rules/');
|
||||
});
|
||||
});
|
||||
@@ -12,7 +12,7 @@ describe('Rule Transformer - General', () => {
|
||||
expect(RULE_PROFILES.length).toBeGreaterThan(0);
|
||||
|
||||
// Verify expected profiles are present
|
||||
const expectedProfiles = ['cline', 'cursor', 'roo', 'windsurf'];
|
||||
const expectedProfiles = ['cline', 'cursor', 'roo', 'trae', 'windsurf'];
|
||||
expectedProfiles.forEach((profile) => {
|
||||
expect(RULE_PROFILES).toContain(profile);
|
||||
});
|
||||
@@ -153,6 +153,11 @@ describe('Rule Transformer - General', () => {
|
||||
mcpConfigName: 'mcp.json',
|
||||
expectedPath: '.roo/mcp.json'
|
||||
},
|
||||
trae: {
|
||||
mcpConfig: false,
|
||||
mcpConfigName: 'trae_mcp_settings.json',
|
||||
expectedPath: '.trae/trae_mcp_settings.json'
|
||||
},
|
||||
cline: {
|
||||
mcpConfig: false,
|
||||
mcpConfigName: 'cline_mcp_settings.json',
|
||||
|
||||
Reference in New Issue
Block a user