superpowers-codex 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. #!/usr/bin/env node
  2. const fs = require('fs');
  3. const path = require('path');
  4. const os = require('os');
  5. const skillsCore = require('../lib/skills-core');
  6. // Paths
  7. const homeDir = os.homedir();
  8. const superpowersSkillsDir = path.join(homeDir, '.codex', 'superpowers', 'skills');
  9. const personalSkillsDir = path.join(homeDir, '.codex', 'skills');
  10. const bootstrapFile = path.join(homeDir, '.codex', 'superpowers', '.codex', 'superpowers-bootstrap.md');
  11. const superpowersRepoDir = path.join(homeDir, '.codex', 'superpowers');
  12. // Utility functions
  13. function printSkill(skillPath, sourceType) {
  14. const skillFile = path.join(skillPath, 'SKILL.md');
  15. const relPath = sourceType === 'personal'
  16. ? path.relative(personalSkillsDir, skillPath)
  17. : path.relative(superpowersSkillsDir, skillPath);
  18. // Print skill name with namespace
  19. if (sourceType === 'personal') {
  20. console.log(relPath.replace(/\\/g, '/')); // Personal skills are not namespaced
  21. } else {
  22. console.log(`superpowers:${relPath.replace(/\\/g, '/')}`); // Superpowers skills get superpowers namespace
  23. }
  24. // Extract and print metadata
  25. const { name, description } = skillsCore.extractFrontmatter(skillFile);
  26. if (description) console.log(` ${description}`);
  27. console.log('');
  28. }
  29. // Commands
  30. function runFindSkills() {
  31. console.log('Available skills:');
  32. console.log('==================');
  33. console.log('');
  34. const foundSkills = new Set();
  35. // Find personal skills first (these take precedence)
  36. const personalSkills = skillsCore.findSkillsInDir(personalSkillsDir, 'personal', 2);
  37. for (const skill of personalSkills) {
  38. const relPath = path.relative(personalSkillsDir, skill.path);
  39. foundSkills.add(relPath);
  40. printSkill(skill.path, 'personal');
  41. }
  42. // Find superpowers skills (only if not already found in personal)
  43. const superpowersSkills = skillsCore.findSkillsInDir(superpowersSkillsDir, 'superpowers', 1);
  44. for (const skill of superpowersSkills) {
  45. const relPath = path.relative(superpowersSkillsDir, skill.path);
  46. if (!foundSkills.has(relPath)) {
  47. printSkill(skill.path, 'superpowers');
  48. }
  49. }
  50. console.log('Usage:');
  51. console.log(' superpowers-codex use-skill <skill-name> # Load a specific skill');
  52. console.log('');
  53. console.log('Skill naming:');
  54. console.log(' Superpowers skills: superpowers:skill-name (from ~/.codex/superpowers/skills/)');
  55. console.log(' Personal skills: skill-name (from ~/.codex/skills/)');
  56. console.log(' Personal skills override superpowers skills when names match.');
  57. console.log('');
  58. console.log('Note: All skills are disclosed at session start via bootstrap.');
  59. }
  60. function runBootstrap() {
  61. console.log('# Superpowers Bootstrap for Codex');
  62. console.log('# ================================');
  63. console.log('');
  64. // Check for updates (with timeout protection)
  65. if (skillsCore.checkForUpdates(superpowersRepoDir)) {
  66. console.log('## Update Available');
  67. console.log('');
  68. console.log('⚠️ Your superpowers installation is behind the latest version.');
  69. console.log('To update, run: `cd ~/.codex/superpowers && git pull`');
  70. console.log('');
  71. console.log('---');
  72. console.log('');
  73. }
  74. // Show the bootstrap instructions
  75. if (fs.existsSync(bootstrapFile)) {
  76. console.log('## Bootstrap Instructions:');
  77. console.log('');
  78. try {
  79. const content = fs.readFileSync(bootstrapFile, 'utf8');
  80. console.log(content);
  81. } catch (error) {
  82. console.log(`Error reading bootstrap file: ${error.message}`);
  83. }
  84. console.log('');
  85. console.log('---');
  86. console.log('');
  87. }
  88. // Run find-skills to show available skills
  89. console.log('## Available Skills:');
  90. console.log('');
  91. runFindSkills();
  92. console.log('');
  93. console.log('---');
  94. console.log('');
  95. // Load the using-superpowers skill automatically
  96. console.log('## Auto-loading superpowers:using-superpowers skill:');
  97. console.log('');
  98. runUseSkill('superpowers:using-superpowers');
  99. console.log('');
  100. console.log('---');
  101. console.log('');
  102. console.log('# Bootstrap Complete!');
  103. console.log('# You now have access to all superpowers skills.');
  104. console.log('# Use "superpowers-codex use-skill <skill>" to load and apply skills.');
  105. console.log('# Remember: If a skill applies to your task, you MUST use it!');
  106. }
  107. function runUseSkill(skillName) {
  108. if (!skillName) {
  109. console.log('Usage: superpowers-codex use-skill <skill-name>');
  110. console.log('Examples:');
  111. console.log(' superpowers-codex use-skill superpowers:brainstorming # Load superpowers skill');
  112. console.log(' superpowers-codex use-skill brainstorming # Load personal skill (or superpowers if not found)');
  113. console.log(' superpowers-codex use-skill my-custom-skill # Load personal skill');
  114. return;
  115. }
  116. // Handle namespaced skill names
  117. let actualSkillPath;
  118. let forceSuperpowers = false;
  119. if (skillName.startsWith('superpowers:')) {
  120. // Remove the superpowers: namespace prefix
  121. actualSkillPath = skillName.substring('superpowers:'.length);
  122. forceSuperpowers = true;
  123. } else {
  124. actualSkillPath = skillName;
  125. }
  126. // Remove "skills/" prefix if present
  127. if (actualSkillPath.startsWith('skills/')) {
  128. actualSkillPath = actualSkillPath.substring('skills/'.length);
  129. }
  130. // Function to find skill file
  131. function findSkillFile(searchPath) {
  132. // Check for exact match with SKILL.md
  133. const skillMdPath = path.join(searchPath, 'SKILL.md');
  134. if (fs.existsSync(skillMdPath)) {
  135. return skillMdPath;
  136. }
  137. // Check for direct SKILL.md file
  138. if (searchPath.endsWith('SKILL.md') && fs.existsSync(searchPath)) {
  139. return searchPath;
  140. }
  141. return null;
  142. }
  143. let skillFile = null;
  144. // If superpowers: namespace was used, only check superpowers skills
  145. if (forceSuperpowers) {
  146. if (fs.existsSync(superpowersSkillsDir)) {
  147. const superpowersPath = path.join(superpowersSkillsDir, actualSkillPath);
  148. skillFile = findSkillFile(superpowersPath);
  149. }
  150. } else {
  151. // First check personal skills directory (takes precedence)
  152. if (fs.existsSync(personalSkillsDir)) {
  153. const personalPath = path.join(personalSkillsDir, actualSkillPath);
  154. skillFile = findSkillFile(personalPath);
  155. if (skillFile) {
  156. console.log(`# Loading personal skill: ${actualSkillPath}`);
  157. console.log(`# Source: ${skillFile}`);
  158. console.log('');
  159. }
  160. }
  161. // If not found in personal, check superpowers skills
  162. if (!skillFile && fs.existsSync(superpowersSkillsDir)) {
  163. const superpowersPath = path.join(superpowersSkillsDir, actualSkillPath);
  164. skillFile = findSkillFile(superpowersPath);
  165. if (skillFile) {
  166. console.log(`# Loading superpowers skill: superpowers:${actualSkillPath}`);
  167. console.log(`# Source: ${skillFile}`);
  168. console.log('');
  169. }
  170. }
  171. }
  172. // If still not found, error
  173. if (!skillFile) {
  174. console.log(`Error: Skill not found: ${actualSkillPath}`);
  175. console.log('');
  176. console.log('Available skills:');
  177. runFindSkills();
  178. return;
  179. }
  180. // Extract frontmatter and content using shared core functions
  181. let content, frontmatter;
  182. try {
  183. const fullContent = fs.readFileSync(skillFile, 'utf8');
  184. const { name, description } = skillsCore.extractFrontmatter(skillFile);
  185. content = skillsCore.stripFrontmatter(fullContent);
  186. frontmatter = { name, description };
  187. } catch (error) {
  188. console.log(`Error reading skill file: ${error.message}`);
  189. return;
  190. }
  191. // Display skill header with clean info
  192. const displayName = forceSuperpowers ? `superpowers:${actualSkillPath}` :
  193. (skillFile.includes(personalSkillsDir) ? actualSkillPath : `superpowers:${actualSkillPath}`);
  194. const skillDirectory = path.dirname(skillFile);
  195. console.log(`# ${frontmatter.name || displayName}`);
  196. if (frontmatter.description) {
  197. console.log(`# ${frontmatter.description}`);
  198. }
  199. console.log(`# Skill-specific tools and reference files live in ${skillDirectory}`);
  200. console.log('# ============================================');
  201. console.log('');
  202. // Display the skill content (without frontmatter)
  203. console.log(content);
  204. }
  205. // Main CLI
  206. const command = process.argv[2];
  207. const arg = process.argv[3];
  208. switch (command) {
  209. case 'bootstrap':
  210. runBootstrap();
  211. break;
  212. case 'use-skill':
  213. runUseSkill(arg);
  214. break;
  215. case 'find-skills':
  216. runFindSkills();
  217. break;
  218. default:
  219. console.log('Superpowers for Codex');
  220. console.log('Usage:');
  221. console.log(' superpowers-codex bootstrap # Run complete bootstrap with all skills');
  222. console.log(' superpowers-codex use-skill <skill-name> # Load a specific skill');
  223. console.log(' superpowers-codex find-skills # List all available skills');
  224. console.log('');
  225. console.log('Examples:');
  226. console.log(' superpowers-codex bootstrap');
  227. console.log(' superpowers-codex use-skill superpowers:brainstorming');
  228. console.log(' superpowers-codex use-skill my-custom-skill');
  229. break;
  230. }