-
-
Notifications
You must be signed in to change notification settings - Fork 3k
supports trae.ai #372
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
supports trae.ai #372
Changes from all commits
7491da4
d565c71
6befba6
6453b15
b29ff86
e93f71d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| # Installing Superpowers for Trae | ||
|
|
||
| Quick setup to enable superpowers skills in Trae. | ||
|
|
||
| ## Installation | ||
|
|
||
| 1. **Clone superpowers repository**: | ||
| ```bash | ||
| mkdir -p ~/.trae/superpowers | ||
| cd ~/.trae/superpowers | ||
| git clone https://github.com/ice-zjchen/superpowers.git . | ||
| ``` | ||
|
|
||
| 2. **Create personal skills directory**: | ||
| ```bash | ||
| mkdir -p ~/.trae/skills | ||
| ``` | ||
|
|
||
| 3. **Create `.trae/rules/superpowers.md` and Update it** to include this superpowers section: | ||
| ```markdown | ||
| ## Superpowers System | ||
|
|
||
| <EXTREMELY_IMPORTANT> | ||
| You have superpowers. Superpowers teach you new skills and capabilities. RIGHT NOW run: `~/.trae/superpowers/.trae/superpowers-trae bootstrap` and follow the instructions it returns. | ||
| </EXTREMELY_IMPORTANT> | ||
| ``` | ||
|
|
||
| ## Verification | ||
|
|
||
| Test the installation: | ||
| ```bash | ||
| ~/.trae/superpowers/.trae/superpowers-trae bootstrap | ||
| ``` | ||
|
|
||
| You should see skill listings and bootstrap instructions. The system is now ready for use. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| # Superpowers Bootstrap for Trae | ||
|
|
||
| <EXTREMELY_IMPORTANT> | ||
| You have superpowers. | ||
|
|
||
| **Tool for running skills:** | ||
| - `~/.trae/superpowers/.trae/superpowers-trae use-skill <skill-name>` | ||
|
|
||
| **Tool Mapping for Trae:** | ||
| When skills reference tools you don't have, substitute your equivalent tools: | ||
| - `TodoWrite` → `update_plan` (your planning/task tracking tool) | ||
| - `Task` tool with subagents → Tell the user that subagents aren't available in Trae yet and you'll do the work the subagent would do | ||
| - `Skill` tool → `~/.trae/superpowers/.trae/superpowers-trae use-skill` command (already available) | ||
| - `Read`, `Write`, `Edit`, `Bash` → Use your native tools with similar functions | ||
|
|
||
| **Skills naming:** | ||
| - Superpowers skills: `superpowers:skill-name` (from ~/.trae/superpowers/skills/) | ||
| - Personal skills: `skill-name` (from ~/.trae/skills/) | ||
| - Personal skills override superpowers skills when names match | ||
|
|
||
| **Critical Rules:** | ||
| - Before ANY task, review the skills list (shown below) | ||
| - If a relevant skill exists, you MUST use `~/.trae/superpowers/.trae/superpowers-trae use-skill` to load it | ||
| - Announce: "I've read the [Skill Name] skill and I'm using it to [purpose]" | ||
| - Skills with checklists require `update_plan` todos for each item | ||
| - NEVER skip mandatory workflows (brainstorming before coding, TDD, systematic debugging) | ||
|
|
||
| **Skills location:** | ||
| - Superpowers skills: ~/.trae/superpowers/skills/ | ||
| - Personal skills: ~/.trae/skills/ (override superpowers when names match) | ||
|
|
||
| IF A SKILL APPLIES TO YOUR TASK, YOU DO NOT HAVE A CHOICE. YOU MUST USE IT. | ||
| </EXTREMELY_IMPORTANT> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,267 @@ | ||
| #!/usr/bin/env node | ||
|
|
||
| const fs = require('fs'); | ||
| const path = require('path'); | ||
| const os = require('os'); | ||
| const skillsCore = require('../lib/skills-core'); | ||
|
|
||
| // Paths | ||
| const homeDir = os.homedir(); | ||
| const superpowersSkillsDir = path.join(homeDir, '.trae', 'superpowers', 'skills'); | ||
| const personalSkillsDir = path.join(homeDir, '.trae', 'skills'); | ||
| const bootstrapFile = path.join(homeDir, '.trae', 'superpowers', '.trae', 'superpowers-bootstrap.md'); | ||
| const superpowersRepoDir = path.join(homeDir, '.trae', 'superpowers'); | ||
|
|
||
| // Utility functions | ||
| function printSkill(skillPath, sourceType) { | ||
| const skillFile = path.join(skillPath, 'SKILL.md'); | ||
| const relPath = sourceType === 'personal' | ||
| ? path.relative(personalSkillsDir, skillPath) | ||
| : path.relative(superpowersSkillsDir, skillPath); | ||
|
|
||
| // Print skill name with namespace | ||
| if (sourceType === 'personal') { | ||
| console.log(relPath.replace(/\\/g, '/')); // Personal skills are not namespaced | ||
| } else { | ||
| console.log(`superpowers:${relPath.replace(/\\/g, '/')}`); // Superpowers skills get superpowers namespace | ||
| } | ||
|
|
||
| // Extract and print metadata | ||
| const { name, description } = skillsCore.extractFrontmatter(skillFile); | ||
|
|
||
| if (description) console.log(` ${description}`); | ||
| console.log(''); | ||
| } | ||
|
|
||
| // Commands | ||
| function runFindSkills() { | ||
| console.log('Available skills:'); | ||
| console.log('=================='); | ||
| console.log(''); | ||
|
|
||
| const foundSkills = new Set(); | ||
|
|
||
| // Find personal skills first (these take precedence) | ||
| const personalSkills = skillsCore.findSkillsInDir(personalSkillsDir, 'personal', 2); | ||
| for (const skill of personalSkills) { | ||
| const relPath = path.relative(personalSkillsDir, skill.path); | ||
| foundSkills.add(relPath); | ||
| printSkill(skill.path, 'personal'); | ||
| } | ||
|
|
||
| // Find superpowers skills (only if not already found in personal) | ||
| const superpowersSkills = skillsCore.findSkillsInDir(superpowersSkillsDir, 'superpowers', 1); | ||
| for (const skill of superpowersSkills) { | ||
| const relPath = path.relative(superpowersSkillsDir, skill.path); | ||
| if (!foundSkills.has(relPath)) { | ||
| printSkill(skill.path, 'superpowers'); | ||
| } | ||
| } | ||
|
|
||
| console.log('Usage:'); | ||
| console.log(' superpowers-trae use-skill <skill-name> # Load a specific skill'); | ||
| console.log(''); | ||
| console.log('Skill naming:'); | ||
| console.log(' Superpowers skills: superpowers:skill-name (from ~/.trae/superpowers/skills/)'); | ||
| console.log(' Personal skills: skill-name (from ~/.trae/skills/)'); | ||
| console.log(' Personal skills override superpowers skills when names match.'); | ||
| console.log(''); | ||
| console.log('Note: All skills are disclosed at session start via bootstrap.'); | ||
| } | ||
|
|
||
| function runBootstrap() { | ||
| console.log('# Superpowers Bootstrap for Trae'); | ||
| console.log('# ==============================='); | ||
| console.log(''); | ||
|
|
||
| // Check for updates (with timeout protection) | ||
| if (skillsCore.checkForUpdates(superpowersRepoDir)) { | ||
| console.log('## Update Available'); | ||
| console.log(''); | ||
| console.log('⚠️ Your superpowers installation is behind the latest version.'); | ||
| console.log('To update, run: `cd ~/.trae/superpowers && git pull`'); | ||
| console.log(''); | ||
| console.log('---'); | ||
| console.log(''); | ||
| } | ||
|
|
||
| // Show the bootstrap instructions | ||
| if (fs.existsSync(bootstrapFile)) { | ||
| console.log('## Bootstrap Instructions:'); | ||
| console.log(''); | ||
| try { | ||
| const content = fs.readFileSync(bootstrapFile, 'utf8'); | ||
| console.log(content); | ||
| } catch (error) { | ||
| console.log(`Error reading bootstrap file: ${error.message}`); | ||
| } | ||
| console.log(''); | ||
| console.log('---'); | ||
| console.log(''); | ||
| } | ||
|
|
||
| // Run find-skills to show available skills | ||
| console.log('## Available Skills:'); | ||
| console.log(''); | ||
| runFindSkills(); | ||
|
|
||
| console.log(''); | ||
| console.log('---'); | ||
| console.log(''); | ||
|
|
||
| // Load the using-superpowers skill automatically | ||
| console.log('## Auto-loading superpowers:using-superpowers skill:'); | ||
| console.log(''); | ||
| runUseSkill('superpowers:using-superpowers'); | ||
|
|
||
| console.log(''); | ||
| console.log('---'); | ||
| console.log(''); | ||
| console.log('# Bootstrap Complete!'); | ||
| console.log('# You now have access to all superpowers skills.'); | ||
| console.log('# Use "superpowers-trae use-skill <skill>" to load and apply skills.'); | ||
| console.log('# Remember: If a skill applies to your task, you MUST use it!'); | ||
| } | ||
|
|
||
| function runUseSkill(skillName) { | ||
| if (!skillName) { | ||
| console.log('Usage: superpowers-trae use-skill <skill-name>'); | ||
| console.log('Examples:'); | ||
| console.log(' superpowers-trae use-skill superpowers:brainstorming # Load superpowers skill'); | ||
| console.log(' superpowers-trae use-skill brainstorming # Load personal skill (or superpowers if not found)'); | ||
| console.log(' superpowers-trae use-skill my-custom-skill # Load personal skill'); | ||
| return; | ||
| } | ||
|
|
||
| // Handle namespaced skill names | ||
| let actualSkillPath; | ||
| let forceSuperpowers = false; | ||
|
|
||
| if (skillName.startsWith('superpowers:')) { | ||
| // Remove the superpowers: namespace prefix | ||
| actualSkillPath = skillName.substring('superpowers:'.length); | ||
| forceSuperpowers = true; | ||
| } else { | ||
| actualSkillPath = skillName; | ||
| } | ||
|
|
||
| // Remove "skills/" prefix if present | ||
| if (actualSkillPath.startsWith('skills/')) { | ||
| actualSkillPath = actualSkillPath.substring('skills/'.length); | ||
| } | ||
|
Comment on lines
+140
to
+151
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Potential path traversal vulnerability. The 🔒 Suggested fix: Validate the resolved path stays within allowed directories+ // Sanitize skill path to prevent directory traversal
+ function isPathWithinDir(filePath, dirPath) {
+ const resolvedFile = path.resolve(filePath);
+ const resolvedDir = path.resolve(dirPath);
+ return resolvedFile.startsWith(resolvedDir + path.sep);
+ }
+
// If superpowers: namespace was used, only check superpowers skills
if (forceSuperpowers) {
if (fs.existsSync(superpowersSkillsDir)) {
const superpowersPath = path.join(superpowersSkillsDir, actualSkillPath);
+ if (!isPathWithinDir(superpowersPath, superpowersSkillsDir)) {
+ console.log(`Error: Invalid skill path: ${actualSkillPath}`);
+ return;
+ }
skillFile = findSkillFile(superpowersPath);
}Apply similar validation for the personal skills path (line 180) and the fallback superpowers path (line 191). 🤖 Prompt for AI Agents |
||
|
|
||
| // Function to find skill file | ||
| function findSkillFile(searchPath) { | ||
| // Check for exact match with SKILL.md | ||
| const skillMdPath = path.join(searchPath, 'SKILL.md'); | ||
| if (fs.existsSync(skillMdPath)) { | ||
| return skillMdPath; | ||
| } | ||
|
|
||
| // Check for direct SKILL.md file | ||
| if (searchPath.endsWith('SKILL.md') && fs.existsSync(searchPath)) { | ||
| return searchPath; | ||
| } | ||
|
|
||
| return null; | ||
| } | ||
|
|
||
| let skillFile = null; | ||
|
|
||
| // If superpowers: namespace was used, only check superpowers skills | ||
| if (forceSuperpowers) { | ||
| if (fs.existsSync(superpowersSkillsDir)) { | ||
| const superpowersPath = path.join(superpowersSkillsDir, actualSkillPath); | ||
| skillFile = findSkillFile(superpowersPath); | ||
| } | ||
| } else { | ||
| // First check personal skills directory (takes precedence) | ||
| if (fs.existsSync(personalSkillsDir)) { | ||
| const personalPath = path.join(personalSkillsDir, actualSkillPath); | ||
| skillFile = findSkillFile(personalPath); | ||
| if (skillFile) { | ||
| console.log(`# Loading personal skill: ${actualSkillPath}`); | ||
| console.log(`# Source: ${skillFile}`); | ||
| console.log(''); | ||
| } | ||
| } | ||
|
|
||
| // If not found in personal, check superpowers skills | ||
| if (!skillFile && fs.existsSync(superpowersSkillsDir)) { | ||
| const superpowersPath = path.join(superpowersSkillsDir, actualSkillPath); | ||
| skillFile = findSkillFile(superpowersPath); | ||
| if (skillFile) { | ||
| console.log(`# Loading superpowers skill: superpowers:${actualSkillPath}`); | ||
| console.log(`# Source: ${skillFile}`); | ||
| console.log(''); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // If still not found, error | ||
| if (!skillFile) { | ||
| console.log(`Error: Skill not found: ${actualSkillPath}`); | ||
| console.log(''); | ||
| console.log('Available skills:'); | ||
| runFindSkills(); | ||
| return; | ||
| } | ||
|
|
||
| // Extract frontmatter and content using shared core functions | ||
| let content, frontmatter; | ||
| try { | ||
| const fullContent = fs.readFileSync(skillFile, 'utf8'); | ||
| const { name, description } = skillsCore.extractFrontmatter(skillFile); | ||
| content = skillsCore.stripFrontmatter(fullContent); | ||
| frontmatter = { name, description }; | ||
| } catch (error) { | ||
| console.log(`Error reading skill file: ${error.message}`); | ||
| return; | ||
| } | ||
|
|
||
| // Display skill header with clean info | ||
| const displayName = forceSuperpowers ? `superpowers:${actualSkillPath}` : | ||
| (skillFile.includes(personalSkillsDir) ? actualSkillPath : `superpowers:${actualSkillPath}`); | ||
|
|
||
| const skillDirectory = path.dirname(skillFile); | ||
|
|
||
| console.log(`# ${frontmatter.name || displayName}`); | ||
| if (frontmatter.description) { | ||
| console.log(`# ${frontmatter.description}`); | ||
| } | ||
| console.log(`# Skill-specific tools and reference files live in ${skillDirectory}`); | ||
| console.log('# ============================================'); | ||
| console.log(''); | ||
|
|
||
| // Display the skill content (without frontmatter) | ||
| console.log(content); | ||
|
|
||
| } | ||
|
|
||
| // Main CLI | ||
| const command = process.argv[2]; | ||
| const arg = process.argv[3]; | ||
|
|
||
| switch (command) { | ||
| case 'bootstrap': | ||
| runBootstrap(); | ||
| break; | ||
| case 'use-skill': | ||
| runUseSkill(arg); | ||
| break; | ||
| case 'find-skills': | ||
| runFindSkills(); | ||
| break; | ||
| default: | ||
| console.log('Superpowers for Trae'); | ||
| console.log('Usage:'); | ||
| console.log(' superpowers-trae bootstrap # Run complete bootstrap with all skills'); | ||
| console.log(' superpowers-trae use-skill <skill-name> # Load a specific skill'); | ||
| console.log(' superpowers-trae find-skills # List all available skills'); | ||
| console.log(''); | ||
| console.log('Examples:'); | ||
| console.log(' superpowers-trae bootstrap'); | ||
| console.log(' superpowers-trae use-skill superpowers:brainstorming'); | ||
| console.log(' superpowers-trae use-skill my-custom-skill'); | ||
| break; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -77,6 +77,16 @@ Fetch and follow instructions from https://raw.githubusercontent.com/obra/superp | |
|
|
||
| **Detailed docs:** [docs/README.opencode.md](docs/README.opencode.md) | ||
|
|
||
| ### Trae | ||
|
|
||
| Tell Trae: | ||
|
|
||
| ``` | ||
| Fetch and follow instructions from https://raw.githubusercontent.com/obra/superpowers/refs/heads/main/.trae/INSTALL.md | ||
| ``` | ||
|
|
||
| **Detailed docs:** [docs/README.trae.md](docs/README.trae.md) | ||
|
Comment on lines
+80
to
+88
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Repository URL points to fork instead of upstream. The Trae installation URL references the PR author's fork. Update to the upstream repository URL for consistency with other documentation. 🔧 Suggested fix ### Trae
Tell Trae:
-Fetch and follow instructions from https://raw.githubusercontent.com/ice-zjchen/superpowers/refs/heads/main/.trae/INSTALL.md The section structure and placement are consistent with the existing Codex and OpenCode sections. 👍 🤖 Prompt for AI Agents |
||
|
|
||
| ## The Basic Workflow | ||
|
|
||
| 1. **brainstorming** - Activates before writing code. Refines rough ideas through questions, explores alternatives, presents design in sections for validation. Saves design document. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Repository URL points to fork instead of upstream.
The clone URL
https://github.com/ice-zjchen/superpowers.gitreferences the PR author's fork. Before merging, this should be updated to the upstream repository URLhttps://github.com/obra/superpowers.gitto ensure users clone from the canonical source.🔧 Suggested fix
1. **Clone superpowers repository**: ```bash mkdir -p ~/.trae/superpowers cd ~/.trae/superpowers - git clone https://github.com/ice-zjchen/superpowers.git . + git clone https://github.com/obra/superpowers.git . ```📝 Committable suggestion
🤖 Prompt for AI Agents