@claude-collective/cli 0.8.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/CHANGELOG.md +127 -0
  2. package/README.md +26 -9
  3. package/dist/{chunk-TOPAIL5W.js → chunk-3U3R4NCG.js} +2 -2
  4. package/dist/chunk-3U3R4NCG.js.map +1 -0
  5. package/dist/{chunk-YKXBGCFD.js → chunk-57Y5RALO.js} +10 -10
  6. package/dist/chunk-57Y5RALO.js.map +1 -0
  7. package/dist/{chunk-ED73HCW2.js → chunk-6DCSSORF.js} +37 -88
  8. package/dist/chunk-6DCSSORF.js.map +1 -0
  9. package/dist/{chunk-6LS7XO3H.js → chunk-6Q3Y7KVB.js} +2 -2
  10. package/dist/chunk-6Q3Y7KVB.js.map +1 -0
  11. package/dist/{chunk-A3J6IAXK.js → chunk-76DWXGQE.js} +4 -2
  12. package/dist/chunk-76DWXGQE.js.map +1 -0
  13. package/dist/{chunk-Q6DR5QUH.js → chunk-7Q44DMSP.js} +62 -27
  14. package/dist/chunk-7Q44DMSP.js.map +1 -0
  15. package/dist/chunk-ACNBKXXJ.js +321 -0
  16. package/dist/chunk-ACNBKXXJ.js.map +1 -0
  17. package/dist/{chunk-QGGSLMO3.js → chunk-B7CCVP6Q.js} +41 -9
  18. package/dist/chunk-B7CCVP6Q.js.map +1 -0
  19. package/dist/{chunk-LVKRVFYR.js → chunk-BDLUZVKU.js} +2 -2
  20. package/dist/chunk-BDLUZVKU.js.map +1 -0
  21. package/dist/{chunk-HNDT5QRB.js → chunk-CDX4W4DM.js} +3 -3
  22. package/dist/chunk-CDX4W4DM.js.map +1 -0
  23. package/dist/{chunk-MYAVQ23U.js → chunk-CJEHB4TB.js} +23 -9
  24. package/dist/chunk-CJEHB4TB.js.map +1 -0
  25. package/dist/{chunk-DKGL77IY.js → chunk-CPZOTVCI.js} +15 -14
  26. package/dist/chunk-CPZOTVCI.js.map +1 -0
  27. package/dist/{chunk-K7PTOVX4.js → chunk-D237EVNB.js} +32 -3
  28. package/dist/chunk-D237EVNB.js.map +1 -0
  29. package/dist/{chunk-Q2LH2DAB.js → chunk-DRXPNNPB.js} +19 -18
  30. package/dist/chunk-DRXPNNPB.js.map +1 -0
  31. package/dist/{chunk-Y3V43XCU.js → chunk-E3FJH4TF.js} +12 -8
  32. package/dist/chunk-E3FJH4TF.js.map +1 -0
  33. package/dist/{chunk-3HBTELJN.js → chunk-ED4E6Q2T.js} +10 -10
  34. package/dist/chunk-ED4E6Q2T.js.map +1 -0
  35. package/dist/{chunk-SYQ7R2JO.js → chunk-EHS3TWWP.js} +3 -3
  36. package/dist/chunk-EHS3TWWP.js.map +1 -0
  37. package/dist/{chunk-LQTST4WY.js → chunk-GDH553MV.js} +6 -6
  38. package/dist/chunk-GDH553MV.js.map +1 -0
  39. package/dist/{chunk-A65SBAAJ.js → chunk-HLJX2FTL.js} +31 -5
  40. package/dist/chunk-HLJX2FTL.js.map +1 -0
  41. package/dist/chunk-I2DSLOXZ.js +75 -0
  42. package/dist/chunk-I2DSLOXZ.js.map +1 -0
  43. package/dist/{chunk-SEBPPFUW.js → chunk-I4TPKIYX.js} +33 -18
  44. package/dist/chunk-I4TPKIYX.js.map +1 -0
  45. package/dist/{chunk-NGBFJJ7Q.js → chunk-IMDW5ZUP.js} +19 -11
  46. package/dist/chunk-IMDW5ZUP.js.map +1 -0
  47. package/dist/{chunk-U4VYHKPM.js → chunk-JIPWV2FX.js} +6 -6
  48. package/dist/chunk-JIPWV2FX.js.map +1 -0
  49. package/dist/{chunk-G2FBJOZG.js → chunk-K7EVM5LY.js} +4 -4
  50. package/dist/chunk-K7EVM5LY.js.map +1 -0
  51. package/dist/{chunk-MJSFR562.js → chunk-KAAEN2PO.js} +3 -3
  52. package/dist/chunk-KAAEN2PO.js.map +1 -0
  53. package/dist/{chunk-FNOYEXUE.js → chunk-LE6IY6IT.js} +22 -17
  54. package/dist/chunk-LE6IY6IT.js.map +1 -0
  55. package/dist/{chunk-CIY5UBRB.js → chunk-NDY25DTL.js} +6 -6
  56. package/dist/chunk-NDY25DTL.js.map +1 -0
  57. package/dist/{chunk-OLBOTK3O.js → chunk-P26A2K5N.js} +7 -7
  58. package/dist/chunk-P26A2K5N.js.map +1 -0
  59. package/dist/{chunk-DHFFRMF6.js → chunk-RTE64SJA.js} +2 -2
  60. package/dist/chunk-RTE64SJA.js.map +1 -0
  61. package/dist/{chunk-3ZCB5K33.js → chunk-SGJ23HIP.js} +14 -11
  62. package/dist/chunk-SGJ23HIP.js.map +1 -0
  63. package/dist/{chunk-C4ZTIYFR.js → chunk-SVYPSDWY.js} +10 -10
  64. package/dist/chunk-SVYPSDWY.js.map +1 -0
  65. package/dist/{chunk-MMDXNZPF.js → chunk-TKFPKEV3.js} +2 -2
  66. package/dist/chunk-TKFPKEV3.js.map +1 -0
  67. package/dist/{chunk-M7YCPFIX.js → chunk-UQTEPWU7.js} +2 -2
  68. package/dist/chunk-UQTEPWU7.js.map +1 -0
  69. package/dist/{chunk-QESUUPOE.js → chunk-V46GGCCI.js} +80 -27
  70. package/dist/chunk-V46GGCCI.js.map +1 -0
  71. package/dist/{chunk-UOWHJ6BE.js → chunk-X6QONICW.js} +6 -3
  72. package/dist/chunk-X6QONICW.js.map +1 -0
  73. package/dist/chunk-Y2LW7R3Y.js +23 -0
  74. package/dist/chunk-Y2LW7R3Y.js.map +1 -0
  75. package/dist/chunk-Z2CWURZ6.js +78 -0
  76. package/dist/chunk-Z2CWURZ6.js.map +1 -0
  77. package/dist/chunk-Z7G4B5HJ.js +377 -0
  78. package/dist/chunk-Z7G4B5HJ.js.map +1 -0
  79. package/dist/{chunk-XKEG3SCV.js → chunk-ZENYS6KW.js} +13 -9
  80. package/dist/chunk-ZENYS6KW.js.map +1 -0
  81. package/dist/{cli-v2 → cli}/defaults/agent-mappings.yaml +5 -5
  82. package/dist/commands/build/marketplace.js +9 -9
  83. package/dist/commands/build/marketplace.js.map +1 -1
  84. package/dist/commands/build/plugins.js +12 -12
  85. package/dist/commands/build/plugins.js.map +1 -1
  86. package/dist/commands/build/stack.js +15 -15
  87. package/dist/commands/build/stack.js.map +1 -1
  88. package/dist/commands/compile.js +21 -21
  89. package/dist/commands/compile.js.map +1 -1
  90. package/dist/commands/config/get.js +9 -8
  91. package/dist/commands/config/get.js.map +1 -1
  92. package/dist/commands/config/index.js +7 -6
  93. package/dist/commands/config/index.js.map +1 -1
  94. package/dist/commands/config/path.js +8 -7
  95. package/dist/commands/config/path.js.map +1 -1
  96. package/dist/commands/config/set-project.js +9 -8
  97. package/dist/commands/config/set-project.js.map +1 -1
  98. package/dist/commands/config/set.js +9 -8
  99. package/dist/commands/config/set.js.map +1 -1
  100. package/dist/commands/config/show.js +6 -5
  101. package/dist/commands/config/unset-project.js +9 -8
  102. package/dist/commands/config/unset-project.js.map +1 -1
  103. package/dist/commands/config/unset.js +9 -8
  104. package/dist/commands/config/unset.js.map +1 -1
  105. package/dist/commands/diff.js +12 -12
  106. package/dist/commands/diff.js.map +1 -1
  107. package/dist/commands/doctor.js +10 -10
  108. package/dist/commands/doctor.js.map +1 -1
  109. package/dist/commands/edit.js +52 -49
  110. package/dist/commands/edit.js.map +1 -1
  111. package/dist/commands/eject.js +180 -97
  112. package/dist/commands/eject.js.map +1 -1
  113. package/dist/commands/import/skill.js +339 -0
  114. package/dist/commands/import/skill.js.map +1 -0
  115. package/dist/commands/info.js +9 -9
  116. package/dist/commands/info.js.map +1 -1
  117. package/dist/commands/init.js +205 -78
  118. package/dist/commands/init.js.map +1 -1
  119. package/dist/commands/list.js +9 -9
  120. package/dist/commands/list.js.map +1 -1
  121. package/dist/commands/new/agent.js +19 -21
  122. package/dist/commands/new/agent.js.map +1 -1
  123. package/dist/commands/new/skill.js +11 -12
  124. package/dist/commands/new/skill.js.map +1 -1
  125. package/dist/commands/outdated.js +12 -12
  126. package/dist/commands/outdated.js.map +1 -1
  127. package/dist/commands/search.js +205 -17
  128. package/dist/commands/search.js.map +1 -1
  129. package/dist/commands/test-imports.js +18 -18
  130. package/dist/commands/test-imports.js.map +1 -1
  131. package/dist/commands/uninstall.js +58 -78
  132. package/dist/commands/uninstall.js.map +1 -1
  133. package/dist/commands/update.js +21 -21
  134. package/dist/commands/update.js.map +1 -1
  135. package/dist/commands/validate.js +9 -9
  136. package/dist/commands/validate.js.map +1 -1
  137. package/dist/commands/version/bump.js +8 -8
  138. package/dist/commands/version/bump.js.map +1 -1
  139. package/dist/commands/version/index.js +8 -8
  140. package/dist/commands/version/index.js.map +1 -1
  141. package/dist/commands/version/set.js +7 -7
  142. package/dist/commands/version/set.js.map +1 -1
  143. package/dist/commands/version/show.js +8 -8
  144. package/dist/commands/version/show.js.map +1 -1
  145. package/dist/components/common/confirm.js +1 -1
  146. package/dist/components/common/message.js +1 -1
  147. package/dist/components/common/message.js.map +1 -1
  148. package/dist/components/common/spinner.js +1 -1
  149. package/dist/components/common/spinner.js.map +1 -1
  150. package/dist/components/skill-search/skill-search.js +10 -0
  151. package/dist/components/skill-search/skill-search.js.map +1 -0
  152. package/dist/components/wizard/category-grid.js +1 -1
  153. package/dist/components/wizard/category-grid.test.js +213 -80
  154. package/dist/components/wizard/category-grid.test.js.map +1 -1
  155. package/dist/components/wizard/section-progress.js +1 -1
  156. package/dist/components/wizard/section-progress.test.js +2 -2
  157. package/dist/components/wizard/section-progress.test.js.map +1 -1
  158. package/dist/components/wizard/step-approach.js +4 -3
  159. package/dist/components/wizard/step-build.js +4 -3
  160. package/dist/components/wizard/step-build.test.js +29 -17
  161. package/dist/components/wizard/step-build.test.js.map +1 -1
  162. package/dist/components/wizard/step-confirm.js +2 -1
  163. package/dist/components/wizard/step-refine.js +2 -1
  164. package/dist/components/wizard/step-refine.test.js +4 -3
  165. package/dist/components/wizard/step-refine.test.js.map +1 -1
  166. package/dist/components/wizard/step-stack-options.js +3 -3
  167. package/dist/components/wizard/step-stack.js +3 -3
  168. package/dist/components/wizard/wizard-footer.js +9 -0
  169. package/dist/components/wizard/wizard-footer.js.map +1 -0
  170. package/dist/components/wizard/wizard-tabs.js +1 -1
  171. package/dist/components/wizard/wizard.js +14 -12
  172. package/dist/hooks/init.js +5 -4
  173. package/dist/hooks/init.js.map +1 -1
  174. package/dist/index.js +1 -1
  175. package/dist/index.js.map +1 -1
  176. package/dist/stores/wizard-store.js +2 -2
  177. package/dist/stores/wizard-store.test.js +3 -3
  178. package/dist/stores/wizard-store.test.js.map +1 -1
  179. package/package.json +3 -2
  180. package/dist/chunk-3HBTELJN.js.map +0 -1
  181. package/dist/chunk-3ZCB5K33.js.map +0 -1
  182. package/dist/chunk-6LS7XO3H.js.map +0 -1
  183. package/dist/chunk-A3J6IAXK.js.map +0 -1
  184. package/dist/chunk-A65SBAAJ.js.map +0 -1
  185. package/dist/chunk-ALEPJ6YN.js +0 -80
  186. package/dist/chunk-ALEPJ6YN.js.map +0 -1
  187. package/dist/chunk-C4ZTIYFR.js.map +0 -1
  188. package/dist/chunk-CIY5UBRB.js.map +0 -1
  189. package/dist/chunk-DHFFRMF6.js.map +0 -1
  190. package/dist/chunk-DKGL77IY.js.map +0 -1
  191. package/dist/chunk-ED73HCW2.js.map +0 -1
  192. package/dist/chunk-FNOYEXUE.js.map +0 -1
  193. package/dist/chunk-G2FBJOZG.js.map +0 -1
  194. package/dist/chunk-HNDT5QRB.js.map +0 -1
  195. package/dist/chunk-K7PTOVX4.js.map +0 -1
  196. package/dist/chunk-LQTST4WY.js.map +0 -1
  197. package/dist/chunk-LVKRVFYR.js.map +0 -1
  198. package/dist/chunk-M7YCPFIX.js.map +0 -1
  199. package/dist/chunk-MJSFR562.js.map +0 -1
  200. package/dist/chunk-MMDXNZPF.js.map +0 -1
  201. package/dist/chunk-MYAVQ23U.js.map +0 -1
  202. package/dist/chunk-NGBFJJ7Q.js.map +0 -1
  203. package/dist/chunk-OLBOTK3O.js.map +0 -1
  204. package/dist/chunk-PPNTD5LO.js +0 -330
  205. package/dist/chunk-PPNTD5LO.js.map +0 -1
  206. package/dist/chunk-Q2LH2DAB.js.map +0 -1
  207. package/dist/chunk-Q6DR5QUH.js.map +0 -1
  208. package/dist/chunk-QESUUPOE.js.map +0 -1
  209. package/dist/chunk-QGGSLMO3.js.map +0 -1
  210. package/dist/chunk-SEBPPFUW.js.map +0 -1
  211. package/dist/chunk-SYQ7R2JO.js.map +0 -1
  212. package/dist/chunk-TOPAIL5W.js.map +0 -1
  213. package/dist/chunk-U4VYHKPM.js.map +0 -1
  214. package/dist/chunk-UOWHJ6BE.js.map +0 -1
  215. package/dist/chunk-XKEG3SCV.js.map +0 -1
  216. package/dist/chunk-Y3V43XCU.js.map +0 -1
  217. package/dist/chunk-YKXBGCFD.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/cli-v2/commands/new/skill.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport path from \"path\";\nimport { BaseCommand } from \"../../base-command.js\";\nimport { loadGlobalConfig } from \"../../lib/config.js\";\nimport { writeFile, directoryExists } from \"../../utils/fs.js\";\nimport { LOCAL_SKILLS_PATH } from \"../../consts.js\";\nimport { EXIT_CODES } from \"../../lib/exit-codes.js\";\n\nconst DEFAULT_AUTHOR = \"@local\";\nconst DEFAULT_CATEGORY = \"local\";\nconst KEBAB_CASE_PATTERN = /^[a-z][a-z0-9-]*$/;\n\n/**\n * Validates that a skill name follows kebab-case convention.\n * Must start with lowercase letter, followed by lowercase letters, numbers, or hyphens.\n */\nexport function validateSkillName(name: string): string | null {\n if (!name || name.trim() === \"\") {\n return \"Skill name is required\";\n }\n\n if (!KEBAB_CASE_PATTERN.test(name)) {\n return \"Skill name must be kebab-case (lowercase letters, numbers, and hyphens, starting with a letter)\";\n }\n\n return null;\n}\n\n/**\n * Converts kebab-case to Title Case.\n * e.g., \"my-patterns\" -> \"My Patterns\"\n */\nexport function toTitleCase(kebabCase: string): string {\n return kebabCase\n .split(\"-\")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n}\n\n/**\n * Generates the SKILL.md content with frontmatter.\n */\nexport function generateSkillMd(name: string, author: string): string {\n const titleName = toTitleCase(name);\n const skillId = `${name} (${author})`;\n\n return `---\nname: ${skillId}\ndescription: Brief description of this skill\n---\n\n# ${titleName}\n\n> **Quick Guide:** Add a brief summary of what this skill teaches.\n\n---\n\n<critical_requirements>\n\n## CRITICAL: Before Using This Skill\n\n**(Add critical requirements here)**\n\n</critical_requirements>\n\n---\n\n**When to use:**\n\n- Add use cases here\n\n**Key patterns covered:**\n\n- Add patterns here\n\n---\n\n<patterns>\n\n## Core Patterns\n\n### Pattern 1: Example Pattern\n\nAdd your patterns here.\n\n</patterns>\n\n---\n\n<critical_reminders>\n\n## CRITICAL REMINDERS\n\n**(Repeat critical requirements here)**\n\n</critical_reminders>\n`;\n}\n\n/**\n * Generates the metadata.yaml content.\n */\nexport function generateMetadataYaml(\n name: string,\n author: string,\n category: string,\n): string {\n const titleName = toTitleCase(name);\n\n return `# yaml-language-server: $schema=https://raw.githubusercontent.com/claude-collective/skills/main/schemas/metadata.schema.json\ncategory: ${category}\ncategory_exclusive: false\nauthor: \"${author}\"\nversion: 1\ncli_name: ${titleName}\ncli_description: Brief description\nusage_guidance: Use when <guidance>.\ntags:\n - local\n - custom\n`;\n}\n\nexport default class NewSkill extends BaseCommand {\n static summary = \"Create a new local skill with proper structure\";\n static description =\n \"Create a new local skill scaffold with SKILL.md and metadata.yaml files\";\n\n static args = {\n name: Args.string({\n description: \"Name of the skill to create (kebab-case)\",\n required: true,\n }),\n };\n\n static flags = {\n ...BaseCommand.baseFlags,\n author: Flags.string({\n char: \"a\",\n description: \"Author identifier (e.g., @myhandle)\",\n required: false,\n }),\n category: Flags.string({\n char: \"c\",\n description: \"Skill category\",\n default: DEFAULT_CATEGORY,\n }),\n force: Flags.boolean({\n char: \"f\",\n description: \"Overwrite existing skill directory\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(NewSkill);\n const projectDir = process.cwd();\n\n this.log(\"\");\n this.log(\"Create New Skill\");\n this.log(\"\");\n\n // Validate skill name\n const validationError = validateSkillName(args.name);\n if (validationError) {\n this.error(validationError, { exit: EXIT_CODES.INVALID_ARGS });\n }\n\n // Determine author: flag > global config > default\n let author = flags.author;\n if (!author) {\n const globalConfig = await loadGlobalConfig();\n author = globalConfig?.author || DEFAULT_AUTHOR;\n }\n\n const category = flags.category;\n\n // Determine skill directory path\n const skillDir = path.join(projectDir, LOCAL_SKILLS_PATH, args.name);\n\n // Check if directory already exists\n if (await directoryExists(skillDir)) {\n if (!flags.force) {\n this.error(\n `Skill directory already exists: ${skillDir}\\nUse --force to overwrite.`,\n { exit: EXIT_CODES.ERROR },\n );\n }\n this.warn(`Overwriting existing skill at ${skillDir}`);\n }\n\n this.log(`Skill name: ${args.name}`);\n this.log(`Author: ${author}`);\n this.log(`Category: ${category}`);\n this.log(`Directory: ${skillDir}`);\n this.log(\"\");\n\n if (flags[\"dry-run\"]) {\n this.log(\"[DRY RUN] Would create skill files\");\n return;\n }\n\n this.log(\"Creating skill files...\");\n\n try {\n // Generate file contents\n const skillMdContent = generateSkillMd(args.name, author);\n const metadataContent = generateMetadataYaml(args.name, author, category);\n\n // Write files (writeFile automatically creates parent directories)\n const skillMdPath = path.join(skillDir, \"SKILL.md\");\n const metadataPath = path.join(skillDir, \"metadata.yaml\");\n\n await writeFile(skillMdPath, skillMdContent);\n await writeFile(metadataPath, metadataContent);\n\n this.log(\"\");\n this.logSuccess(`Created SKILL.md at ${skillMdPath}`);\n this.logSuccess(`Created metadata.yaml at ${metadataPath}`);\n this.log(\"\");\n this.log(\n \"Skill created successfully! Run 'cc compile' to include it in your agents.\",\n );\n this.log(\"\");\n } catch (error) {\n this.error(\n error instanceof Error ? error.message : \"Unknown error occurred\",\n { exit: EXIT_CODES.ERROR },\n );\n }\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/cli/commands/new/skill.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport path from \"path\";\nimport { BaseCommand } from \"../../base-command.js\";\nimport { resolveAuthor } from \"../../lib/config.js\";\nimport { writeFile, directoryExists } from \"../../utils/fs.js\";\nimport { LOCAL_SKILLS_PATH } from \"../../consts.js\";\nimport { EXIT_CODES } from \"../../lib/exit-codes.js\";\n\nconst DEFAULT_AUTHOR = \"@local\";\nconst DEFAULT_CATEGORY = \"local\";\nconst KEBAB_CASE_PATTERN = /^[a-z][a-z0-9-]*$/;\n\n/**\n * Validates that a skill name follows kebab-case convention.\n * Must start with lowercase letter, followed by lowercase letters, numbers, or hyphens.\n */\nexport function validateSkillName(name: string): string | null {\n if (!name || name.trim() === \"\") {\n return \"Skill name is required\";\n }\n\n if (!KEBAB_CASE_PATTERN.test(name)) {\n return \"Skill name must be kebab-case (lowercase letters, numbers, and hyphens, starting with a letter)\";\n }\n\n return null;\n}\n\n/**\n * Converts kebab-case to Title Case.\n * e.g., \"my-patterns\" -> \"My Patterns\"\n */\nexport function toTitleCase(kebabCase: string): string {\n return kebabCase\n .split(\"-\")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n}\n\n/**\n * Generates the SKILL.md content with frontmatter.\n */\nexport function generateSkillMd(name: string, author: string): string {\n const titleName = toTitleCase(name);\n const skillId = `${name} (${author})`;\n\n return `---\nname: ${skillId}\ndescription: Brief description of this skill\n---\n\n# ${titleName}\n\n> **Quick Guide:** Add a brief summary of what this skill teaches.\n\n---\n\n<critical_requirements>\n\n## CRITICAL: Before Using This Skill\n\n**(Add critical requirements here)**\n\n</critical_requirements>\n\n---\n\n**When to use:**\n\n- Add use cases here\n\n**Key patterns covered:**\n\n- Add patterns here\n\n---\n\n<patterns>\n\n## Core Patterns\n\n### Pattern 1: Example Pattern\n\nAdd your patterns here.\n\n</patterns>\n\n---\n\n<critical_reminders>\n\n## CRITICAL REMINDERS\n\n**(Repeat critical requirements here)**\n\n</critical_reminders>\n`;\n}\n\n/**\n * Generates the metadata.yaml content.\n */\nexport function generateMetadataYaml(\n name: string,\n author: string,\n category: string,\n): string {\n const titleName = toTitleCase(name);\n\n return `# yaml-language-server: $schema=https://raw.githubusercontent.com/claude-collective/skills/main/schemas/metadata.schema.json\ncategory: ${category}\ncategory_exclusive: false\nauthor: \"${author}\"\nversion: 1\ncli_name: ${titleName}\ncli_description: Brief description\nusage_guidance: Use when <guidance>.\ntags:\n - local\n - custom\n`;\n}\n\nexport default class NewSkill extends BaseCommand {\n static summary = \"Create a new local skill with proper structure\";\n static description =\n \"Create a new local skill scaffold with SKILL.md and metadata.yaml files\";\n\n static args = {\n name: Args.string({\n description: \"Name of the skill to create (kebab-case)\",\n required: true,\n }),\n };\n\n static flags = {\n ...BaseCommand.baseFlags,\n author: Flags.string({\n char: \"a\",\n description: \"Author identifier (e.g., @myhandle)\",\n required: false,\n }),\n category: Flags.string({\n char: \"c\",\n description: \"Skill category\",\n default: DEFAULT_CATEGORY,\n }),\n force: Flags.boolean({\n char: \"f\",\n description: \"Overwrite existing skill directory\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(NewSkill);\n const projectDir = process.cwd();\n\n this.log(\"\");\n this.log(\"Create New Skill\");\n this.log(\"\");\n\n // Validate skill name\n const validationError = validateSkillName(args.name);\n if (validationError) {\n this.error(validationError, { exit: EXIT_CODES.INVALID_ARGS });\n }\n\n // Determine author: flag > project config > default\n let author = flags.author;\n if (!author) {\n author = (await resolveAuthor(projectDir)) || DEFAULT_AUTHOR;\n }\n\n const category = flags.category;\n\n // Determine skill directory path\n const skillDir = path.join(projectDir, LOCAL_SKILLS_PATH, args.name);\n\n // Check if directory already exists\n if (await directoryExists(skillDir)) {\n if (!flags.force) {\n this.error(\n `Skill directory already exists: ${skillDir}\\nUse --force to overwrite.`,\n { exit: EXIT_CODES.ERROR },\n );\n }\n this.warn(`Overwriting existing skill at ${skillDir}`);\n }\n\n this.log(`Skill name: ${args.name}`);\n this.log(`Author: ${author}`);\n this.log(`Category: ${category}`);\n this.log(`Directory: ${skillDir}`);\n this.log(\"\");\n\n if (flags[\"dry-run\"]) {\n this.log(\"[DRY RUN] Would create skill files\");\n return;\n }\n\n this.log(\"Creating skill files...\");\n\n try {\n // Generate file contents\n const skillMdContent = generateSkillMd(args.name, author);\n const metadataContent = generateMetadataYaml(args.name, author, category);\n\n // Write files (writeFile automatically creates parent directories)\n const skillMdPath = path.join(skillDir, \"SKILL.md\");\n const metadataPath = path.join(skillDir, \"metadata.yaml\");\n\n await writeFile(skillMdPath, skillMdContent);\n await writeFile(metadataPath, metadataContent);\n\n this.log(\"\");\n this.logSuccess(`Created SKILL.md at ${skillMdPath}`);\n this.logSuccess(`Created metadata.yaml at ${metadataPath}`);\n this.log(\"\");\n this.log(\n \"Skill created successfully! Run 'cc compile' to include it in your agents.\",\n );\n this.log(\"\");\n } catch (error) {\n this.error(\n error instanceof Error ? error.message : \"Unknown error occurred\",\n { exit: EXIT_CODES.ERROR },\n );\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,31 +1,31 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  hashFile
4
- } from "../chunk-MJSFR562.js";
4
+ } from "../chunk-KAAEN2PO.js";
5
5
  import {
6
6
  loadSkillsMatrixFromSource
7
- } from "../chunk-DKGL77IY.js";
8
- import "../chunk-QGGSLMO3.js";
9
- import "../chunk-NGBFJJ7Q.js";
10
- import "../chunk-QESUUPOE.js";
11
- import {
12
- LOCAL_SKILLS_PATH
13
- } from "../chunk-A3J6IAXK.js";
7
+ } from "../chunk-CPZOTVCI.js";
8
+ import "../chunk-B7CCVP6Q.js";
9
+ import "../chunk-IMDW5ZUP.js";
14
10
  import {
15
11
  BaseCommand,
16
12
  EXIT_CODES
17
- } from "../chunk-SYQ7R2JO.js";
18
- import "../chunk-TOPAIL5W.js";
13
+ } from "../chunk-EHS3TWWP.js";
14
+ import "../chunk-V46GGCCI.js";
15
+ import "../chunk-3U3R4NCG.js";
19
16
  import {
20
17
  fileExists,
21
18
  listDirectories,
22
19
  readFile
23
- } from "../chunk-MMDXNZPF.js";
20
+ } from "../chunk-TKFPKEV3.js";
21
+ import {
22
+ LOCAL_SKILLS_PATH
23
+ } from "../chunk-76DWXGQE.js";
24
24
  import {
25
25
  init_esm_shims
26
26
  } from "../chunk-DHET7RCE.js";
27
27
 
28
- // src/cli-v2/commands/outdated.ts
28
+ // src/cli/commands/outdated.ts
29
29
  init_esm_shims();
30
30
  import { Flags } from "@oclif/core";
31
31
  import { printTable } from "@oclif/table";
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli-v2/commands/outdated.ts"],"sourcesContent":["import { Flags } from \"@oclif/core\";\nimport { printTable } from \"@oclif/table\";\nimport path from \"path\";\nimport { parse as parseYaml } from \"yaml\";\nimport { BaseCommand } from \"../base-command.js\";\nimport { loadSkillsMatrixFromSource } from \"../lib/source-loader.js\";\nimport { hashFile } from \"../lib/versioning.js\";\nimport { fileExists, readFile, listDirectories } from \"../utils/fs.js\";\nimport { LOCAL_SKILLS_PATH } from \"../consts.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\n\n/**\n * Status values for skill comparison\n */\ntype SkillStatus = \"current\" | \"outdated\" | \"local-only\";\n\n/**\n * Result of comparing a local skill to its source\n */\ninterface SkillComparisonResult {\n id: string;\n localHash: string | null;\n sourceHash: string | null;\n status: SkillStatus;\n}\n\n/**\n * Summary counts for the comparison results\n */\ninterface ComparisonSummary {\n outdated: number;\n current: number;\n localOnly: number;\n}\n\n/**\n * ForkedFrom metadata stored in local skill's metadata.yaml\n */\ninterface ForkedFromMetadata {\n skill_id: string;\n content_hash: string;\n date: string;\n}\n\n/**\n * Local skill metadata structure\n */\ninterface LocalSkillMetadata {\n forked_from?: ForkedFromMetadata;\n [key: string]: unknown;\n}\n\n/**\n * Read forked_from metadata from a local skill's metadata.yaml\n */\nasync function readForkedFromMetadata(\n skillDir: string,\n): Promise<ForkedFromMetadata | null> {\n const metadataPath = path.join(skillDir, \"metadata.yaml\");\n\n if (!(await fileExists(metadataPath))) {\n return null;\n }\n\n const content = await readFile(metadataPath);\n const metadata = parseYaml(content) as LocalSkillMetadata;\n\n return metadata.forked_from ?? null;\n}\n\n/**\n * Get local skills with their forked_from metadata\n */\nasync function getLocalSkillsWithMetadata(\n projectDir: string,\n): Promise<\n Map<string, { dirName: string; forkedFrom: ForkedFromMetadata | null }>\n> {\n const localSkillsPath = path.join(projectDir, LOCAL_SKILLS_PATH);\n const result = new Map<\n string,\n { dirName: string; forkedFrom: ForkedFromMetadata | null }\n >();\n\n if (!(await fileExists(localSkillsPath))) {\n return result;\n }\n\n const skillDirs = await listDirectories(localSkillsPath);\n\n for (const dirName of skillDirs) {\n const skillDir = path.join(localSkillsPath, dirName);\n const forkedFrom = await readForkedFromMetadata(skillDir);\n\n // Use the skill_id from forked_from if available, otherwise use directory name\n const skillId = forkedFrom?.skill_id ?? dirName;\n\n result.set(skillId, { dirName, forkedFrom });\n }\n\n return result;\n}\n\n/**\n * Compute source hash for a skill's SKILL.md file\n */\nasync function computeSourceHash(\n sourcePath: string,\n skillPath: string,\n): Promise<string | null> {\n const skillMdPath = path.join(sourcePath, \"src\", skillPath, \"SKILL.md\");\n\n if (!(await fileExists(skillMdPath))) {\n return null;\n }\n\n return hashFile(skillMdPath);\n}\n\n/**\n * Compare local skills against source and determine status\n */\nasync function compareSkills(\n projectDir: string,\n sourcePath: string,\n sourceSkills: Record<string, { path: string }>,\n): Promise<SkillComparisonResult[]> {\n const results: SkillComparisonResult[] = [];\n const localSkills = await getLocalSkillsWithMetadata(projectDir);\n\n // Process local skills\n for (const [skillId, { forkedFrom }] of localSkills) {\n if (!forkedFrom) {\n // Local-only skill (no forked_from metadata)\n results.push({\n id: skillId,\n localHash: null,\n sourceHash: null,\n status: \"local-only\",\n });\n continue;\n }\n\n const localHash = forkedFrom.content_hash;\n const sourceSkill = sourceSkills[forkedFrom.skill_id];\n\n if (!sourceSkill) {\n // Skill was forked from a source that no longer exists\n results.push({\n id: forkedFrom.skill_id,\n localHash,\n sourceHash: null,\n status: \"local-only\",\n });\n continue;\n }\n\n const sourceHash = await computeSourceHash(sourcePath, sourceSkill.path);\n\n if (sourceHash === null) {\n // Source skill's SKILL.md not found\n results.push({\n id: forkedFrom.skill_id,\n localHash,\n sourceHash: null,\n status: \"local-only\",\n });\n continue;\n }\n\n const status: SkillStatus =\n localHash === sourceHash ? \"current\" : \"outdated\";\n\n results.push({\n id: forkedFrom.skill_id,\n localHash,\n sourceHash,\n status,\n });\n }\n\n // Sort results by skill ID\n results.sort((a, b) => a.id.localeCompare(b.id));\n\n return results;\n}\n\n/**\n * Calculate summary counts from comparison results\n */\nfunction calculateSummary(results: SkillComparisonResult[]): ComparisonSummary {\n return {\n outdated: results.filter((r) => r.status === \"outdated\").length,\n current: results.filter((r) => r.status === \"current\").length,\n localOnly: results.filter((r) => r.status === \"local-only\").length,\n };\n}\n\n/**\n * Format hash for display\n */\nfunction formatHash(hash: string | null, isLocal: boolean): string {\n if (hash === null) {\n return isLocal ? \"(local)\" : \"-\";\n }\n return hash;\n}\n\nexport default class Outdated extends BaseCommand {\n static summary =\n \"Check which local skills are out of date compared to source\";\n static description =\n \"Compare local skills against their source repository to identify outdated skills that need updating\";\n\n static flags = {\n ...BaseCommand.baseFlags,\n json: Flags.boolean({\n description: \"Output results as JSON\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(Outdated);\n const projectDir = process.cwd();\n\n try {\n // Check if local skills directory exists\n const localSkillsPath = path.join(projectDir, LOCAL_SKILLS_PATH);\n if (!(await fileExists(localSkillsPath))) {\n if (flags.json) {\n this.log(\n JSON.stringify({\n skills: [],\n summary: { outdated: 0, current: 0, localOnly: 0 },\n }),\n );\n } else {\n this.warn(\"No local skills found. Run `cc init` or `cc edit` first.\");\n }\n return;\n }\n\n if (!flags.json) {\n this.log(\"Loading skills...\");\n }\n\n const { matrix, sourcePath, isLocal } = await loadSkillsMatrixFromSource({\n sourceFlag: flags.source,\n projectDir,\n });\n\n if (!flags.json) {\n this.log(`Loaded from ${isLocal ? \"local\" : \"remote\"}: ${sourcePath}`);\n }\n\n // Build source skills map for lookup\n const sourceSkills: Record<string, { path: string }> = {};\n for (const [skillId, skill] of Object.entries(matrix.skills)) {\n if (!skill.local) {\n sourceSkills[skillId] = { path: skill.path };\n }\n }\n\n // Compare local skills against source\n const results = await compareSkills(projectDir, sourcePath, sourceSkills);\n const summary = calculateSummary(results);\n\n // Output results\n if (flags.json) {\n this.log(\n JSON.stringify(\n {\n skills: results.map((r) => ({\n id: r.id,\n localHash: r.localHash,\n sourceHash: r.sourceHash,\n status: r.status,\n })),\n summary: {\n outdated: summary.outdated,\n current: summary.current,\n localOnly: summary.localOnly,\n },\n },\n null,\n 2,\n ),\n );\n } else {\n this.log(\"\");\n if (results.length === 0) {\n this.logInfo(\"No local skills found to compare.\");\n } else {\n // Use @oclif/table for table output\n printTable({\n data: results.map((result) => ({\n skill: result.id,\n localHash: formatHash(result.localHash, true),\n sourceHash: formatHash(result.sourceHash, false),\n status: result.status,\n })),\n columns: [\n { key: \"skill\", name: \"Skill\" },\n { key: \"localHash\", name: \"Local Hash\" },\n { key: \"sourceHash\", name: \"Source Hash\" },\n { key: \"status\", name: \"Status\" },\n ],\n headerOptions: { bold: true },\n });\n\n this.log(\"\");\n\n // Display summary\n const parts: string[] = [];\n if (summary.outdated > 0) {\n parts.push(`${summary.outdated} outdated`);\n }\n if (summary.current > 0) {\n parts.push(`${summary.current} current`);\n }\n if (summary.localOnly > 0) {\n parts.push(`${summary.localOnly} local-only`);\n }\n this.log(`Summary: ${parts.join(\", \")}`);\n }\n this.log(\"\");\n }\n\n // Exit with appropriate code if there are outdated skills\n if (summary.outdated > 0) {\n this.error(\"Some skills are outdated\", { exit: EXIT_CODES.ERROR });\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n\n if (flags.json) {\n this.error(JSON.stringify({ error: message }), {\n exit: EXIT_CODES.ERROR,\n });\n } else {\n this.error(`Error: ${message}`, { exit: EXIT_CODES.ERROR });\n }\n }\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/cli/commands/outdated.ts"],"sourcesContent":["import { Flags } from \"@oclif/core\";\nimport { printTable } from \"@oclif/table\";\nimport path from \"path\";\nimport { parse as parseYaml } from \"yaml\";\nimport { BaseCommand } from \"../base-command.js\";\nimport { loadSkillsMatrixFromSource } from \"../lib/source-loader.js\";\nimport { hashFile } from \"../lib/versioning.js\";\nimport { fileExists, readFile, listDirectories } from \"../utils/fs.js\";\nimport { LOCAL_SKILLS_PATH } from \"../consts.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\n\n/**\n * Status values for skill comparison\n */\ntype SkillStatus = \"current\" | \"outdated\" | \"local-only\";\n\n/**\n * Result of comparing a local skill to its source\n */\ninterface SkillComparisonResult {\n id: string;\n localHash: string | null;\n sourceHash: string | null;\n status: SkillStatus;\n}\n\n/**\n * Summary counts for the comparison results\n */\ninterface ComparisonSummary {\n outdated: number;\n current: number;\n localOnly: number;\n}\n\n/**\n * ForkedFrom metadata stored in local skill's metadata.yaml\n */\ninterface ForkedFromMetadata {\n skill_id: string;\n content_hash: string;\n date: string;\n}\n\n/**\n * Local skill metadata structure\n */\ninterface LocalSkillMetadata {\n forked_from?: ForkedFromMetadata;\n [key: string]: unknown;\n}\n\n/**\n * Read forked_from metadata from a local skill's metadata.yaml\n */\nasync function readForkedFromMetadata(\n skillDir: string,\n): Promise<ForkedFromMetadata | null> {\n const metadataPath = path.join(skillDir, \"metadata.yaml\");\n\n if (!(await fileExists(metadataPath))) {\n return null;\n }\n\n const content = await readFile(metadataPath);\n const metadata = parseYaml(content) as LocalSkillMetadata;\n\n return metadata.forked_from ?? null;\n}\n\n/**\n * Get local skills with their forked_from metadata\n */\nasync function getLocalSkillsWithMetadata(\n projectDir: string,\n): Promise<\n Map<string, { dirName: string; forkedFrom: ForkedFromMetadata | null }>\n> {\n const localSkillsPath = path.join(projectDir, LOCAL_SKILLS_PATH);\n const result = new Map<\n string,\n { dirName: string; forkedFrom: ForkedFromMetadata | null }\n >();\n\n if (!(await fileExists(localSkillsPath))) {\n return result;\n }\n\n const skillDirs = await listDirectories(localSkillsPath);\n\n for (const dirName of skillDirs) {\n const skillDir = path.join(localSkillsPath, dirName);\n const forkedFrom = await readForkedFromMetadata(skillDir);\n\n // Use the skill_id from forked_from if available, otherwise use directory name\n const skillId = forkedFrom?.skill_id ?? dirName;\n\n result.set(skillId, { dirName, forkedFrom });\n }\n\n return result;\n}\n\n/**\n * Compute source hash for a skill's SKILL.md file\n */\nasync function computeSourceHash(\n sourcePath: string,\n skillPath: string,\n): Promise<string | null> {\n const skillMdPath = path.join(sourcePath, \"src\", skillPath, \"SKILL.md\");\n\n if (!(await fileExists(skillMdPath))) {\n return null;\n }\n\n return hashFile(skillMdPath);\n}\n\n/**\n * Compare local skills against source and determine status\n */\nasync function compareSkills(\n projectDir: string,\n sourcePath: string,\n sourceSkills: Record<string, { path: string }>,\n): Promise<SkillComparisonResult[]> {\n const results: SkillComparisonResult[] = [];\n const localSkills = await getLocalSkillsWithMetadata(projectDir);\n\n // Process local skills\n for (const [skillId, { forkedFrom }] of localSkills) {\n if (!forkedFrom) {\n // Local-only skill (no forked_from metadata)\n results.push({\n id: skillId,\n localHash: null,\n sourceHash: null,\n status: \"local-only\",\n });\n continue;\n }\n\n const localHash = forkedFrom.content_hash;\n const sourceSkill = sourceSkills[forkedFrom.skill_id];\n\n if (!sourceSkill) {\n // Skill was forked from a source that no longer exists\n results.push({\n id: forkedFrom.skill_id,\n localHash,\n sourceHash: null,\n status: \"local-only\",\n });\n continue;\n }\n\n const sourceHash = await computeSourceHash(sourcePath, sourceSkill.path);\n\n if (sourceHash === null) {\n // Source skill's SKILL.md not found\n results.push({\n id: forkedFrom.skill_id,\n localHash,\n sourceHash: null,\n status: \"local-only\",\n });\n continue;\n }\n\n const status: SkillStatus =\n localHash === sourceHash ? \"current\" : \"outdated\";\n\n results.push({\n id: forkedFrom.skill_id,\n localHash,\n sourceHash,\n status,\n });\n }\n\n // Sort results by skill ID\n results.sort((a, b) => a.id.localeCompare(b.id));\n\n return results;\n}\n\n/**\n * Calculate summary counts from comparison results\n */\nfunction calculateSummary(results: SkillComparisonResult[]): ComparisonSummary {\n return {\n outdated: results.filter((r) => r.status === \"outdated\").length,\n current: results.filter((r) => r.status === \"current\").length,\n localOnly: results.filter((r) => r.status === \"local-only\").length,\n };\n}\n\n/**\n * Format hash for display\n */\nfunction formatHash(hash: string | null, isLocal: boolean): string {\n if (hash === null) {\n return isLocal ? \"(local)\" : \"-\";\n }\n return hash;\n}\n\nexport default class Outdated extends BaseCommand {\n static summary =\n \"Check which local skills are out of date compared to source\";\n static description =\n \"Compare local skills against their source repository to identify outdated skills that need updating\";\n\n static flags = {\n ...BaseCommand.baseFlags,\n json: Flags.boolean({\n description: \"Output results as JSON\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(Outdated);\n const projectDir = process.cwd();\n\n try {\n // Check if local skills directory exists\n const localSkillsPath = path.join(projectDir, LOCAL_SKILLS_PATH);\n if (!(await fileExists(localSkillsPath))) {\n if (flags.json) {\n this.log(\n JSON.stringify({\n skills: [],\n summary: { outdated: 0, current: 0, localOnly: 0 },\n }),\n );\n } else {\n this.warn(\"No local skills found. Run `cc init` or `cc edit` first.\");\n }\n return;\n }\n\n if (!flags.json) {\n this.log(\"Loading skills...\");\n }\n\n const { matrix, sourcePath, isLocal } = await loadSkillsMatrixFromSource({\n sourceFlag: flags.source,\n projectDir,\n });\n\n if (!flags.json) {\n this.log(`Loaded from ${isLocal ? \"local\" : \"remote\"}: ${sourcePath}`);\n }\n\n // Build source skills map for lookup\n const sourceSkills: Record<string, { path: string }> = {};\n for (const [skillId, skill] of Object.entries(matrix.skills)) {\n if (!skill.local) {\n sourceSkills[skillId] = { path: skill.path };\n }\n }\n\n // Compare local skills against source\n const results = await compareSkills(projectDir, sourcePath, sourceSkills);\n const summary = calculateSummary(results);\n\n // Output results\n if (flags.json) {\n this.log(\n JSON.stringify(\n {\n skills: results.map((r) => ({\n id: r.id,\n localHash: r.localHash,\n sourceHash: r.sourceHash,\n status: r.status,\n })),\n summary: {\n outdated: summary.outdated,\n current: summary.current,\n localOnly: summary.localOnly,\n },\n },\n null,\n 2,\n ),\n );\n } else {\n this.log(\"\");\n if (results.length === 0) {\n this.logInfo(\"No local skills found to compare.\");\n } else {\n // Use @oclif/table for table output\n printTable({\n data: results.map((result) => ({\n skill: result.id,\n localHash: formatHash(result.localHash, true),\n sourceHash: formatHash(result.sourceHash, false),\n status: result.status,\n })),\n columns: [\n { key: \"skill\", name: \"Skill\" },\n { key: \"localHash\", name: \"Local Hash\" },\n { key: \"sourceHash\", name: \"Source Hash\" },\n { key: \"status\", name: \"Status\" },\n ],\n headerOptions: { bold: true },\n });\n\n this.log(\"\");\n\n // Display summary\n const parts: string[] = [];\n if (summary.outdated > 0) {\n parts.push(`${summary.outdated} outdated`);\n }\n if (summary.current > 0) {\n parts.push(`${summary.current} current`);\n }\n if (summary.localOnly > 0) {\n parts.push(`${summary.localOnly} local-only`);\n }\n this.log(`Summary: ${parts.join(\", \")}`);\n }\n this.log(\"\");\n }\n\n // Exit with appropriate code if there are outdated skills\n if (summary.outdated > 0) {\n this.error(\"Some skills are outdated\", { exit: EXIT_CODES.ERROR });\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n\n if (flags.json) {\n this.error(JSON.stringify({ error: message }), {\n exit: EXIT_CODES.ERROR,\n });\n } else {\n this.error(`Error: ${message}`, { exit: EXIT_CODES.ERROR });\n }\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,25 +1,50 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ SkillSearch
4
+ } from "../chunk-ACNBKXXJ.js";
5
+ import "../chunk-Z2CWURZ6.js";
2
6
  import {
3
7
  loadSkillsMatrixFromSource
4
- } from "../chunk-DKGL77IY.js";
5
- import "../chunk-QGGSLMO3.js";
6
- import "../chunk-NGBFJJ7Q.js";
7
- import "../chunk-QESUUPOE.js";
8
- import "../chunk-A3J6IAXK.js";
8
+ } from "../chunk-CPZOTVCI.js";
9
+ import "../chunk-B7CCVP6Q.js";
10
+ import {
11
+ fetchFromSource
12
+ } from "../chunk-IMDW5ZUP.js";
13
+ import {
14
+ BaseCommand,
15
+ EXIT_CODES
16
+ } from "../chunk-EHS3TWWP.js";
17
+ import {
18
+ resolveAllSources
19
+ } from "../chunk-V46GGCCI.js";
20
+ import "../chunk-3U3R4NCG.js";
21
+ import {
22
+ copy,
23
+ ensureDir,
24
+ fileExists,
25
+ listDirectories
26
+ } from "../chunk-TKFPKEV3.js";
9
27
  import {
10
- BaseCommand
11
- } from "../chunk-SYQ7R2JO.js";
12
- import "../chunk-TOPAIL5W.js";
13
- import "../chunk-MMDXNZPF.js";
28
+ LOCAL_SKILLS_PATH
29
+ } from "../chunk-76DWXGQE.js";
14
30
  import {
15
31
  init_esm_shims
16
32
  } from "../chunk-DHET7RCE.js";
17
33
 
18
- // src/cli-v2/commands/search.ts
34
+ // src/cli/commands/search.tsx
19
35
  init_esm_shims();
20
36
  import { Args, Flags } from "@oclif/core";
37
+ import { render } from "ink";
21
38
  import { printTable } from "@oclif/table";
39
+ import path from "path";
40
+
41
+ // src/cli/components/skill-search/index.ts
42
+ init_esm_shims();
43
+
44
+ // src/cli/commands/search.tsx
45
+ import { jsx } from "react/jsx-runtime";
22
46
  var MAX_DESCRIPTION_WIDTH = 50;
47
+ var DEFAULT_SKILLS_SUBDIR = "skills";
23
48
  function truncate(str, maxLength) {
24
49
  if (str.length <= maxLength) return str;
25
50
  return str.slice(0, maxLength - 3) + "...";
@@ -40,25 +65,190 @@ function matchesCategory(skill, category) {
40
65
  const lowerCategory = category.toLowerCase();
41
66
  return skill.category.toLowerCase().includes(lowerCategory);
42
67
  }
68
+ function toSourcedSkill(skill, sourceName, sourceUrl) {
69
+ return {
70
+ ...skill,
71
+ sourceName,
72
+ sourceUrl
73
+ };
74
+ }
75
+ async function fetchSkillsFromSource(source, forceRefresh) {
76
+ try {
77
+ const result = await fetchFromSource(source.url, { forceRefresh });
78
+ const skillsDir = path.join(result.path, DEFAULT_SKILLS_SUBDIR);
79
+ if (!await fileExists(skillsDir)) {
80
+ return [];
81
+ }
82
+ const skillDirs = await listDirectories(skillsDir);
83
+ const skills = [];
84
+ for (const skillDir of skillDirs) {
85
+ const skillMdPath = path.join(skillsDir, skillDir, "SKILL.md");
86
+ if (await fileExists(skillMdPath)) {
87
+ skills.push({
88
+ id: skillDir,
89
+ name: skillDir.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" "),
90
+ description: `Skill from ${source.name}`,
91
+ category: "imported",
92
+ categoryExclusive: false,
93
+ tags: [],
94
+ author: "@" + source.name,
95
+ conflictsWith: [],
96
+ recommends: [],
97
+ recommendedBy: [],
98
+ requires: [],
99
+ requiredBy: [],
100
+ alternatives: [],
101
+ discourages: [],
102
+ compatibleWith: [],
103
+ requiresSetup: [],
104
+ providesSetupFor: [],
105
+ sourceName: source.name,
106
+ sourceUrl: source.url,
107
+ path: path.join(skillsDir, skillDir)
108
+ });
109
+ }
110
+ }
111
+ return skills;
112
+ } catch {
113
+ return [];
114
+ }
115
+ }
43
116
  var Search = class _Search extends BaseCommand {
44
117
  static summary = "Search available skills";
45
- static description = "Search skills by name, description, category, or tags and display results in a table";
118
+ static description = "Search skills by name, description, category, or tags. Run without arguments or with -i for interactive mode with multi-select.";
119
+ static examples = [
120
+ {
121
+ description: "Search for React skills",
122
+ command: "<%= config.bin %> search react"
123
+ },
124
+ {
125
+ description: "Interactive search mode",
126
+ command: "<%= config.bin %> search"
127
+ },
128
+ {
129
+ description: "Interactive with pre-filled query",
130
+ command: "<%= config.bin %> search -i react"
131
+ },
132
+ {
133
+ description: "Search with category filter",
134
+ command: "<%= config.bin %> search state -c frontend"
135
+ }
136
+ ];
46
137
  static args = {
47
138
  query: Args.string({
48
139
  description: "Search query (matches name, description, category, tags)",
49
- required: true
140
+ required: false
50
141
  })
51
142
  };
52
143
  static flags = {
53
144
  ...BaseCommand.baseFlags,
145
+ interactive: Flags.boolean({
146
+ char: "i",
147
+ description: "Launch interactive search with multi-select",
148
+ default: false
149
+ }),
54
150
  category: Flags.string({
55
151
  char: "c",
56
152
  description: "Filter by category",
57
153
  required: false
154
+ }),
155
+ refresh: Flags.boolean({
156
+ description: "Force refresh from remote sources",
157
+ default: false
58
158
  })
59
159
  };
60
160
  async run() {
61
161
  const { args, flags } = await this.parse(_Search);
162
+ const projectDir = process.cwd();
163
+ const isInteractive = flags.interactive || !args.query;
164
+ if (isInteractive) {
165
+ await this.runInteractive(args.query, flags.refresh, projectDir);
166
+ } else {
167
+ await this.runStatic(args.query, flags);
168
+ }
169
+ }
170
+ /**
171
+ * Run interactive search mode with full-screen UI
172
+ */
173
+ async runInteractive(initialQuery, forceRefresh, projectDir) {
174
+ this.log("Loading skills from all sources...");
175
+ try {
176
+ const { matrix, sourcePath } = await loadSkillsMatrixFromSource({
177
+ sourceFlag: void 0,
178
+ projectDir,
179
+ forceRefresh
180
+ });
181
+ const primarySkills = Object.values(matrix.skills).map(
182
+ (skill) => toSourcedSkill(skill, "marketplace", sourcePath)
183
+ );
184
+ const { extras } = await resolveAllSources(projectDir);
185
+ const extraSkillArrays = await Promise.all(
186
+ extras.map((source) => fetchSkillsFromSource(source, forceRefresh))
187
+ );
188
+ const allSkills = [
189
+ ...primarySkills,
190
+ ...extraSkillArrays.flat()
191
+ ];
192
+ const sourceCount = 1 + extras.length;
193
+ this.log(
194
+ `Loaded ${allSkills.length} skills from ${sourceCount} source(s)`
195
+ );
196
+ this.log("");
197
+ const searchResultPromise = new Promise((resolve) => {
198
+ const { waitUntilExit } = render(
199
+ /* @__PURE__ */ jsx(
200
+ SkillSearch,
201
+ {
202
+ skills: allSkills,
203
+ sourceCount,
204
+ initialQuery,
205
+ onComplete: (result) => {
206
+ resolve(result);
207
+ },
208
+ onCancel: () => {
209
+ resolve({ selectedSkills: [], cancelled: true });
210
+ }
211
+ }
212
+ )
213
+ );
214
+ waitUntilExit().then(() => {
215
+ resolve({ selectedSkills: [], cancelled: true });
216
+ });
217
+ });
218
+ const searchResult = await searchResultPromise;
219
+ if (searchResult.cancelled) {
220
+ this.log("Search cancelled");
221
+ this.exit(EXIT_CODES.CANCELLED);
222
+ }
223
+ if (searchResult.selectedSkills.length === 0) {
224
+ this.log("No skills selected");
225
+ return;
226
+ }
227
+ this.log("");
228
+ this.log(`Importing ${searchResult.selectedSkills.length} skill(s)...`);
229
+ const destDir = path.join(projectDir, LOCAL_SKILLS_PATH);
230
+ for (const skill of searchResult.selectedSkills) {
231
+ if (skill.path) {
232
+ const destPath = path.join(destDir, skill.id);
233
+ await ensureDir(path.dirname(destPath));
234
+ await copy(skill.path, destPath);
235
+ this.logSuccess(`Imported: ${skill.id}`);
236
+ } else {
237
+ this.warn(`Skipping ${skill.id}: No source path available`);
238
+ }
239
+ }
240
+ this.log("");
241
+ this.logSuccess("Import complete!");
242
+ this.log(`Skills location: ${destDir}`);
243
+ this.log("Run 'cc compile' to include imported skills in your agents.");
244
+ } catch (error) {
245
+ this.handleError(error);
246
+ }
247
+ }
248
+ /**
249
+ * Run static search mode with table output
250
+ */
251
+ async runStatic(query, flags) {
62
252
  try {
63
253
  this.log("Loading skills...");
64
254
  const { matrix, sourcePath, isLocal } = await loadSkillsMatrixFromSource({
@@ -66,9 +256,7 @@ var Search = class _Search extends BaseCommand {
66
256
  });
67
257
  this.log(`Loaded from ${isLocal ? "local" : "remote"}: ${sourcePath}`);
68
258
  const allSkills = Object.values(matrix.skills);
69
- let results = allSkills.filter(
70
- (skill) => matchesQuery(skill, args.query)
71
- );
259
+ let results = allSkills.filter((skill) => matchesQuery(skill, query));
72
260
  if (flags.category) {
73
261
  results = results.filter(
74
262
  (skill) => matchesCategory(skill, flags.category)
@@ -77,13 +265,13 @@ var Search = class _Search extends BaseCommand {
77
265
  results.sort((a, b) => a.name.localeCompare(b.name));
78
266
  this.log("");
79
267
  if (results.length === 0) {
80
- this.warn(`No skills found matching "${args.query}"`);
268
+ this.warn(`No skills found matching "${query}"`);
81
269
  if (flags.category) {
82
270
  this.logInfo(`Category filter: ${flags.category}`);
83
271
  }
84
272
  } else {
85
273
  this.logInfo(
86
- `Found ${results.length} skill${results.length === 1 ? "" : "s"} matching "${args.query}"`
274
+ `Found ${results.length} skill${results.length === 1 ? "" : "s"} matching "${query}"`
87
275
  );
88
276
  if (flags.category) {
89
277
  this.logInfo(`Category filter: ${flags.category}`);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli-v2/commands/search.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport { printTable } from \"@oclif/table\";\nimport { BaseCommand } from \"../base-command.js\";\nimport { loadSkillsMatrixFromSource } from \"../lib/source-loader.js\";\nimport type { ResolvedSkill } from \"../types-matrix.js\";\n\n/**\n * Maximum description width for table output\n */\nconst MAX_DESCRIPTION_WIDTH = 50;\n\n/**\n * Truncate a string to a maximum length with ellipsis\n */\nfunction truncate(str: string, maxLength: number): string {\n if (str.length <= maxLength) return str;\n return str.slice(0, maxLength - 3) + \"...\";\n}\n\n/**\n * Check if a skill matches the search query (case-insensitive)\n */\nfunction matchesQuery(skill: ResolvedSkill, query: string): boolean {\n const lowerQuery = query.toLowerCase();\n\n // Match against name\n if (skill.name.toLowerCase().includes(lowerQuery)) return true;\n\n // Match against ID\n if (skill.id.toLowerCase().includes(lowerQuery)) return true;\n\n // Match against alias\n if (skill.alias?.toLowerCase().includes(lowerQuery)) return true;\n\n // Match against description\n if (skill.description.toLowerCase().includes(lowerQuery)) return true;\n\n // Match against category\n if (skill.category.toLowerCase().includes(lowerQuery)) return true;\n\n // Match against tags\n if (skill.tags.some((tag) => tag.toLowerCase().includes(lowerQuery))) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Check if a skill matches the category filter (case-insensitive)\n */\nfunction matchesCategory(skill: ResolvedSkill, category: string): boolean {\n const lowerCategory = category.toLowerCase();\n return skill.category.toLowerCase().includes(lowerCategory);\n}\n\nexport default class Search extends BaseCommand {\n static summary = \"Search available skills\";\n static description =\n \"Search skills by name, description, category, or tags and display results in a table\";\n\n static args = {\n query: Args.string({\n description: \"Search query (matches name, description, category, tags)\",\n required: true,\n }),\n };\n\n static flags = {\n ...BaseCommand.baseFlags,\n category: Flags.string({\n char: \"c\",\n description: \"Filter by category\",\n required: false,\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(Search);\n\n try {\n this.log(\"Loading skills...\");\n\n const { matrix, sourcePath, isLocal } = await loadSkillsMatrixFromSource({\n sourceFlag: flags.source,\n });\n\n this.log(`Loaded from ${isLocal ? \"local\" : \"remote\"}: ${sourcePath}`);\n\n // Get all skills as array\n const allSkills = Object.values(matrix.skills);\n\n // Filter by query\n let results = allSkills.filter((skill) =>\n matchesQuery(skill, args.query),\n );\n\n // Apply category filter if provided\n if (flags.category) {\n results = results.filter((skill) =>\n matchesCategory(skill, flags.category as string),\n );\n }\n\n // Sort results by name\n results.sort((a, b) => a.name.localeCompare(b.name));\n\n // Display results\n this.log(\"\");\n if (results.length === 0) {\n this.warn(`No skills found matching \"${args.query}\"`);\n if (flags.category) {\n this.logInfo(`Category filter: ${flags.category}`);\n }\n } else {\n this.logInfo(\n `Found ${results.length} skill${results.length === 1 ? \"\" : \"s\"} matching \"${args.query}\"`,\n );\n if (flags.category) {\n this.logInfo(`Category filter: ${flags.category}`);\n }\n this.log(\"\");\n\n // Use @oclif/table for table output\n printTable({\n data: results.map((skill) => ({\n id: skill.alias || skill.id,\n category: skill.category,\n description: truncate(skill.description, MAX_DESCRIPTION_WIDTH),\n })),\n columns: [\n { key: \"id\", name: \"ID\" },\n { key: \"category\", name: \"Category\" },\n { key: \"description\", name: \"Description\" },\n ],\n headerOptions: { bold: true },\n });\n }\n this.log(\"\");\n } catch (error) {\n this.handleError(error);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA,SAAS,MAAM,aAAa;AAC5B,SAAS,kBAAkB;AAQ3B,IAAM,wBAAwB;AAK9B,SAAS,SAAS,KAAa,WAA2B;AACxD,MAAI,IAAI,UAAU,UAAW,QAAO;AACpC,SAAO,IAAI,MAAM,GAAG,YAAY,CAAC,IAAI;AACvC;AAKA,SAAS,aAAa,OAAsB,OAAwB;AAClE,QAAM,aAAa,MAAM,YAAY;AAGrC,MAAI,MAAM,KAAK,YAAY,EAAE,SAAS,UAAU,EAAG,QAAO;AAG1D,MAAI,MAAM,GAAG,YAAY,EAAE,SAAS,UAAU,EAAG,QAAO;AAGxD,MAAI,MAAM,OAAO,YAAY,EAAE,SAAS,UAAU,EAAG,QAAO;AAG5D,MAAI,MAAM,YAAY,YAAY,EAAE,SAAS,UAAU,EAAG,QAAO;AAGjE,MAAI,MAAM,SAAS,YAAY,EAAE,SAAS,UAAU,EAAG,QAAO;AAG9D,MAAI,MAAM,KAAK,KAAK,CAAC,QAAQ,IAAI,YAAY,EAAE,SAAS,UAAU,CAAC,GAAG;AACpE,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAKA,SAAS,gBAAgB,OAAsB,UAA2B;AACxE,QAAM,gBAAgB,SAAS,YAAY;AAC3C,SAAO,MAAM,SAAS,YAAY,EAAE,SAAS,aAAa;AAC5D;AAEA,IAAqB,SAArB,MAAqB,gBAAe,YAAY;AAAA,EAC9C,OAAO,UAAU;AAAA,EACjB,OAAO,cACL;AAAA,EAEF,OAAO,OAAO;AAAA,IACZ,OAAO,KAAK,OAAO;AAAA,MACjB,aAAa;AAAA,MACb,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAAA,EAEA,OAAO,QAAQ;AAAA,IACb,GAAG,YAAY;AAAA,IACf,UAAU,MAAM,OAAO;AAAA,MACrB,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,MAAqB;AACzB,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,KAAK,MAAM,OAAM;AAE/C,QAAI;AACF,WAAK,IAAI,mBAAmB;AAE5B,YAAM,EAAE,QAAQ,YAAY,QAAQ,IAAI,MAAM,2BAA2B;AAAA,QACvE,YAAY,MAAM;AAAA,MACpB,CAAC;AAED,WAAK,IAAI,eAAe,UAAU,UAAU,QAAQ,KAAK,UAAU,EAAE;AAGrE,YAAM,YAAY,OAAO,OAAO,OAAO,MAAM;AAG7C,UAAI,UAAU,UAAU;AAAA,QAAO,CAAC,UAC9B,aAAa,OAAO,KAAK,KAAK;AAAA,MAChC;AAGA,UAAI,MAAM,UAAU;AAClB,kBAAU,QAAQ;AAAA,UAAO,CAAC,UACxB,gBAAgB,OAAO,MAAM,QAAkB;AAAA,QACjD;AAAA,MACF;AAGA,cAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AAGnD,WAAK,IAAI,EAAE;AACX,UAAI,QAAQ,WAAW,GAAG;AACxB,aAAK,KAAK,6BAA6B,KAAK,KAAK,GAAG;AACpD,YAAI,MAAM,UAAU;AAClB,eAAK,QAAQ,oBAAoB,MAAM,QAAQ,EAAE;AAAA,QACnD;AAAA,MACF,OAAO;AACL,aAAK;AAAA,UACH,SAAS,QAAQ,MAAM,SAAS,QAAQ,WAAW,IAAI,KAAK,GAAG,cAAc,KAAK,KAAK;AAAA,QACzF;AACA,YAAI,MAAM,UAAU;AAClB,eAAK,QAAQ,oBAAoB,MAAM,QAAQ,EAAE;AAAA,QACnD;AACA,aAAK,IAAI,EAAE;AAGX,mBAAW;AAAA,UACT,MAAM,QAAQ,IAAI,CAAC,WAAW;AAAA,YAC5B,IAAI,MAAM,SAAS,MAAM;AAAA,YACzB,UAAU,MAAM;AAAA,YAChB,aAAa,SAAS,MAAM,aAAa,qBAAqB;AAAA,UAChE,EAAE;AAAA,UACF,SAAS;AAAA,YACP,EAAE,KAAK,MAAM,MAAM,KAAK;AAAA,YACxB,EAAE,KAAK,YAAY,MAAM,WAAW;AAAA,YACpC,EAAE,KAAK,eAAe,MAAM,cAAc;AAAA,UAC5C;AAAA,UACA,eAAe,EAAE,MAAM,KAAK;AAAA,QAC9B,CAAC;AAAA,MACH;AACA,WAAK,IAAI,EAAE;AAAA,IACb,SAAS,OAAO;AACd,WAAK,YAAY,KAAK;AAAA,IACxB;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/cli/commands/search.tsx","../../src/cli/components/skill-search/index.ts"],"sourcesContent":["/**\n * Search available skills command.\n *\n * Supports two modes:\n * - Static mode (with query arg): Traditional table output for scripting\n * - Interactive mode (no args or -i flag): Full-screen search with multi-select\n *\n * Interactive mode features:\n * - Live filtering as you type\n * - Multi-select for batch import\n * - Keyboard navigation (arrows, vim keys)\n * - Copy skill link to clipboard\n */\nimport React from \"react\";\nimport { Args, Flags } from \"@oclif/core\";\nimport { render } from \"ink\";\nimport { printTable } from \"@oclif/table\";\nimport path from \"path\";\nimport { BaseCommand } from \"../base-command.js\";\nimport { loadSkillsMatrixFromSource } from \"../lib/source-loader.js\";\nimport { resolveAllSources, type SourceEntry } from \"../lib/config.js\";\nimport { fetchFromSource } from \"../lib/source-fetcher.js\";\nimport { listDirectories, fileExists, copy, ensureDir } from \"../utils/fs.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport {\n SkillSearch,\n type SkillSearchResult,\n} from \"../components/skill-search/index.js\";\nimport type { SourcedSkill } from \"../components/skill-search/skill-search.js\";\nimport type { ResolvedSkill } from \"../types-matrix.js\";\nimport { LOCAL_SKILLS_PATH } from \"../consts.js\";\n\n/**\n * Maximum description width for table output\n */\nconst MAX_DESCRIPTION_WIDTH = 50;\n\n/** Default skills subdirectory in third-party repos */\nconst DEFAULT_SKILLS_SUBDIR = \"skills\";\n\n/**\n * Truncate a string to a maximum length with ellipsis\n */\nfunction truncate(str: string, maxLength: number): string {\n if (str.length <= maxLength) return str;\n return str.slice(0, maxLength - 3) + \"...\";\n}\n\n/**\n * Check if a skill matches the search query (case-insensitive)\n */\nfunction matchesQuery(skill: ResolvedSkill, query: string): boolean {\n const lowerQuery = query.toLowerCase();\n\n // Match against name\n if (skill.name.toLowerCase().includes(lowerQuery)) return true;\n\n // Match against ID\n if (skill.id.toLowerCase().includes(lowerQuery)) return true;\n\n // Match against alias\n if (skill.alias?.toLowerCase().includes(lowerQuery)) return true;\n\n // Match against description\n if (skill.description.toLowerCase().includes(lowerQuery)) return true;\n\n // Match against category\n if (skill.category.toLowerCase().includes(lowerQuery)) return true;\n\n // Match against tags\n if (skill.tags.some((tag) => tag.toLowerCase().includes(lowerQuery))) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Check if a skill matches the category filter (case-insensitive)\n */\nfunction matchesCategory(skill: ResolvedSkill, category: string): boolean {\n const lowerCategory = category.toLowerCase();\n return skill.category.toLowerCase().includes(lowerCategory);\n}\n\n/**\n * Convert ResolvedSkill to SourcedSkill with source attribution\n */\nfunction toSourcedSkill(\n skill: ResolvedSkill,\n sourceName: string,\n sourceUrl?: string,\n): SourcedSkill {\n return {\n ...skill,\n sourceName,\n sourceUrl,\n };\n}\n\n/**\n * Fetch skills from a third-party source.\n * Returns array of SourcedSkills with source attribution.\n */\nasync function fetchSkillsFromSource(\n source: SourceEntry,\n forceRefresh: boolean,\n): Promise<SourcedSkill[]> {\n try {\n const result = await fetchFromSource(source.url, { forceRefresh });\n const skillsDir = path.join(result.path, DEFAULT_SKILLS_SUBDIR);\n\n // Check if skills directory exists\n if (!(await fileExists(skillsDir))) {\n return [];\n }\n\n // List skill directories\n const skillDirs = await listDirectories(skillsDir);\n const skills: SourcedSkill[] = [];\n\n for (const skillDir of skillDirs) {\n const skillMdPath = path.join(skillsDir, skillDir, \"SKILL.md\");\n if (await fileExists(skillMdPath)) {\n // Create a minimal skill entry\n skills.push({\n id: skillDir,\n name: skillDir\n .split(\"-\")\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(\" \"),\n description: `Skill from ${source.name}`,\n category: \"imported\",\n categoryExclusive: false,\n tags: [],\n author: \"@\" + source.name,\n conflictsWith: [],\n recommends: [],\n recommendedBy: [],\n requires: [],\n requiredBy: [],\n alternatives: [],\n discourages: [],\n compatibleWith: [],\n requiresSetup: [],\n providesSetupFor: [],\n sourceName: source.name,\n sourceUrl: source.url,\n path: path.join(skillsDir, skillDir),\n });\n }\n }\n\n return skills;\n } catch {\n // Source unavailable, return empty\n return [];\n }\n}\n\nexport default class Search extends BaseCommand {\n static summary = \"Search available skills\";\n static description =\n \"Search skills by name, description, category, or tags. \" +\n \"Run without arguments or with -i for interactive mode with multi-select.\";\n\n static examples = [\n {\n description: \"Search for React skills\",\n command: \"<%= config.bin %> search react\",\n },\n {\n description: \"Interactive search mode\",\n command: \"<%= config.bin %> search\",\n },\n {\n description: \"Interactive with pre-filled query\",\n command: \"<%= config.bin %> search -i react\",\n },\n {\n description: \"Search with category filter\",\n command: \"<%= config.bin %> search state -c frontend\",\n },\n ];\n\n static args = {\n query: Args.string({\n description: \"Search query (matches name, description, category, tags)\",\n required: false,\n }),\n };\n\n static flags = {\n ...BaseCommand.baseFlags,\n interactive: Flags.boolean({\n char: \"i\",\n description: \"Launch interactive search with multi-select\",\n default: false,\n }),\n category: Flags.string({\n char: \"c\",\n description: \"Filter by category\",\n required: false,\n }),\n refresh: Flags.boolean({\n description: \"Force refresh from remote sources\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(Search);\n const projectDir = process.cwd();\n\n // Determine mode: interactive if no query or -i flag\n const isInteractive = flags.interactive || !args.query;\n\n if (isInteractive) {\n await this.runInteractive(args.query, flags.refresh, projectDir);\n } else {\n await this.runStatic(args.query!, flags);\n }\n }\n\n /**\n * Run interactive search mode with full-screen UI\n */\n private async runInteractive(\n initialQuery: string | undefined,\n forceRefresh: boolean,\n projectDir: string,\n ): Promise<void> {\n this.log(\"Loading skills from all sources...\");\n\n try {\n // Load primary source skills\n const { matrix, sourcePath } = await loadSkillsMatrixFromSource({\n sourceFlag: undefined,\n projectDir,\n forceRefresh,\n });\n\n // Convert to SourcedSkills\n const primarySkills = Object.values(matrix.skills).map((skill) =>\n toSourcedSkill(skill, \"marketplace\", sourcePath),\n );\n\n // Get configured extra sources\n const { extras } = await resolveAllSources(projectDir);\n\n // Fetch skills from extra sources\n const extraSkillArrays = await Promise.all(\n extras.map((source) => fetchSkillsFromSource(source, forceRefresh)),\n );\n\n // Merge all skills (primary first, then extras)\n const allSkills: SourcedSkill[] = [\n ...primarySkills,\n ...extraSkillArrays.flat(),\n ];\n\n // Total source count\n const sourceCount = 1 + extras.length;\n\n this.log(\n `Loaded ${allSkills.length} skills from ${sourceCount} source(s)`,\n );\n this.log(\"\");\n\n // Render interactive search\n const searchResultPromise = new Promise<SkillSearchResult>((resolve) => {\n const { waitUntilExit } = render(\n <SkillSearch\n skills={allSkills}\n sourceCount={sourceCount}\n initialQuery={initialQuery}\n onComplete={(result) => {\n resolve(result);\n }}\n onCancel={() => {\n resolve({ selectedSkills: [], cancelled: true });\n }}\n />,\n );\n\n // Also resolve on app exit\n waitUntilExit().then(() => {\n resolve({ selectedSkills: [], cancelled: true });\n });\n });\n\n const searchResult = await searchResultPromise;\n\n // Handle result\n if (searchResult.cancelled) {\n this.log(\"Search cancelled\");\n this.exit(EXIT_CODES.CANCELLED);\n }\n\n if (searchResult.selectedSkills.length === 0) {\n this.log(\"No skills selected\");\n return;\n }\n\n // Import selected skills\n this.log(\"\");\n this.log(`Importing ${searchResult.selectedSkills.length} skill(s)...`);\n\n const destDir = path.join(projectDir, LOCAL_SKILLS_PATH);\n\n for (const skill of searchResult.selectedSkills) {\n if (skill.path) {\n const destPath = path.join(destDir, skill.id);\n await ensureDir(path.dirname(destPath));\n await copy(skill.path, destPath);\n this.logSuccess(`Imported: ${skill.id}`);\n } else {\n this.warn(`Skipping ${skill.id}: No source path available`);\n }\n }\n\n this.log(\"\");\n this.logSuccess(\"Import complete!\");\n this.log(`Skills location: ${destDir}`);\n this.log(\"Run 'cc compile' to include imported skills in your agents.\");\n } catch (error) {\n this.handleError(error);\n }\n }\n\n /**\n * Run static search mode with table output\n */\n private async runStatic(\n query: string,\n flags: { source?: string; category?: string },\n ): Promise<void> {\n try {\n this.log(\"Loading skills...\");\n\n const { matrix, sourcePath, isLocal } = await loadSkillsMatrixFromSource({\n sourceFlag: flags.source,\n });\n\n this.log(`Loaded from ${isLocal ? \"local\" : \"remote\"}: ${sourcePath}`);\n\n // Get all skills as array\n const allSkills = Object.values(matrix.skills);\n\n // Filter by query\n let results = allSkills.filter((skill) => matchesQuery(skill, query));\n\n // Apply category filter if provided\n if (flags.category) {\n results = results.filter((skill) =>\n matchesCategory(skill, flags.category as string),\n );\n }\n\n // Sort results by name\n results.sort((a, b) => a.name.localeCompare(b.name));\n\n // Display results\n this.log(\"\");\n if (results.length === 0) {\n this.warn(`No skills found matching \"${query}\"`);\n if (flags.category) {\n this.logInfo(`Category filter: ${flags.category}`);\n }\n } else {\n this.logInfo(\n `Found ${results.length} skill${results.length === 1 ? \"\" : \"s\"} matching \"${query}\"`,\n );\n if (flags.category) {\n this.logInfo(`Category filter: ${flags.category}`);\n }\n this.log(\"\");\n\n // Use @oclif/table for table output\n printTable({\n data: results.map((skill) => ({\n id: skill.alias || skill.id,\n category: skill.category,\n description: truncate(skill.description, MAX_DESCRIPTION_WIDTH),\n })),\n columns: [\n { key: \"id\", name: \"ID\" },\n { key: \"category\", name: \"Category\" },\n { key: \"description\", name: \"Description\" },\n ],\n headerOptions: { bold: true },\n });\n }\n this.log(\"\");\n } catch (error) {\n this.handleError(error);\n }\n }\n}\n","export {\n SkillSearch,\n type SkillSearchProps,\n type SkillSearchResult,\n} from \"./skill-search.js\";\n"],"mappings":"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","names":[]}
@@ -1,43 +1,43 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getPluginInfo
4
- } from "../chunk-YKXBGCFD.js";
4
+ } from "../chunk-57Y5RALO.js";
5
5
  import {
6
6
  validatePluginManifest
7
- } from "../chunk-CIY5UBRB.js";
8
- import "../chunk-3ZCB5K33.js";
9
- import "../chunk-MYAVQ23U.js";
7
+ } from "../chunk-NDY25DTL.js";
8
+ import "../chunk-SGJ23HIP.js";
10
9
  import {
11
10
  compileAllAgents,
12
11
  resolveSkillReference
13
- } from "../chunk-SEBPPFUW.js";
14
- import "../chunk-3HBTELJN.js";
12
+ } from "../chunk-I4TPKIYX.js";
13
+ import "../chunk-ED4E6Q2T.js";
14
+ import "../chunk-CJEHB4TB.js";
15
15
  import {
16
16
  loadSkillsMatrixFromSource
17
- } from "../chunk-DKGL77IY.js";
18
- import "../chunk-QGGSLMO3.js";
19
- import "../chunk-NGBFJJ7Q.js";
20
- import {
21
- loadGlobalConfig,
22
- resolveSource
23
- } from "../chunk-QESUUPOE.js";
24
- import "../chunk-A3J6IAXK.js";
17
+ } from "../chunk-CPZOTVCI.js";
18
+ import "../chunk-B7CCVP6Q.js";
19
+ import "../chunk-IMDW5ZUP.js";
25
20
  import {
26
21
  BaseCommand,
27
22
  EXIT_CODES
28
- } from "../chunk-SYQ7R2JO.js";
23
+ } from "../chunk-EHS3TWWP.js";
24
+ import {
25
+ loadGlobalConfig,
26
+ resolveSource
27
+ } from "../chunk-V46GGCCI.js";
29
28
  import {
30
29
  verbose
31
- } from "../chunk-TOPAIL5W.js";
30
+ } from "../chunk-3U3R4NCG.js";
32
31
  import {
33
32
  fileExists,
34
33
  readFile
35
- } from "../chunk-MMDXNZPF.js";
34
+ } from "../chunk-TKFPKEV3.js";
35
+ import "../chunk-76DWXGQE.js";
36
36
  import {
37
37
  init_esm_shims
38
38
  } from "../chunk-DHET7RCE.js";
39
39
 
40
- // src/cli-v2/commands/test-imports.ts
40
+ // src/cli/commands/test-imports.ts
41
41
  init_esm_shims();
42
42
  var TestImports = class extends BaseCommand {
43
43
  static summary = "Test that lib imports work (temporary command)";
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli-v2/commands/test-imports.ts"],"sourcesContent":["import { BaseCommand } from \"../base-command.js\";\n\n// Test imports from the existing lib\nimport { loadGlobalConfig, resolveSource } from \"../lib/config.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { getPluginInfo } from \"../lib/plugin-info.js\";\nimport { loadSkillsMatrixFromSource } from \"../lib/source-loader.js\";\nimport { validatePluginManifest } from \"../lib/plugin-validator.js\";\nimport { compileAllAgents } from \"../lib/compiler.js\";\nimport { resolveSkillReference } from \"../lib/resolver.js\";\nimport { fileExists, readFile } from \"../utils/fs.js\";\nimport { verbose } from \"../utils/logger.js\";\n\nexport default class TestImports extends BaseCommand {\n static summary = \"Test that lib imports work (temporary command)\";\n static hidden = true; // Hide from help\n\n async run(): Promise<void> {\n this.log(\"Testing imports from cli/lib/...\");\n\n // Test config loading from init hook\n this.log(\"\\nConfig from init hook:\");\n if (this.sourceConfig) {\n this.log(` ✓ Config loaded successfully`);\n this.log(` Source: ${this.sourceConfig.source}`);\n this.log(` Origin: ${this.sourceConfig.sourceOrigin}`);\n if (this.sourceConfig.marketplace) {\n this.log(` Marketplace: ${this.sourceConfig.marketplace}`);\n }\n } else {\n this.warn(\" Config not loaded - init hook may have failed\");\n }\n\n // Test lib/ utilities\n this.log(\"\\nLib utilities:\");\n this.log(` EXIT_CODES.SUCCESS = ${EXIT_CODES.SUCCESS}`);\n this.log(\n ` loadGlobalConfig is a function: ${typeof loadGlobalConfig === \"function\"}`,\n );\n this.log(\n ` resolveSource is a function: ${typeof resolveSource === \"function\"}`,\n );\n this.log(\n ` getPluginInfo is a function: ${typeof getPluginInfo === \"function\"}`,\n );\n this.log(\n ` loadSkillsMatrixFromSource is a function: ${typeof loadSkillsMatrixFromSource === \"function\"}`,\n );\n this.log(\n ` validatePluginManifest is a function: ${typeof validatePluginManifest === \"function\"}`,\n );\n this.log(\n ` compileAllAgents is a function: ${typeof compileAllAgents === \"function\"}`,\n );\n this.log(\n ` resolveSkillReference is a function: ${typeof resolveSkillReference === \"function\"}`,\n );\n\n // Test utils/ utilities\n this.log(\"\\nUtils utilities:\");\n this.log(` fileExists is a function: ${typeof fileExists === \"function\"}`);\n this.log(` readFile is a function: ${typeof readFile === \"function\"}`);\n this.log(` verbose is a function: ${typeof verbose === \"function\"}`);\n\n this.log(\"\\n✓ All imports successful!\");\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAaA,IAAqB,cAArB,cAAyC,YAAY;AAAA,EACnD,OAAO,UAAU;AAAA,EACjB,OAAO,SAAS;AAAA;AAAA,EAEhB,MAAM,MAAqB;AACzB,SAAK,IAAI,kCAAkC;AAG3C,SAAK,IAAI,0BAA0B;AACnC,QAAI,KAAK,cAAc;AACrB,WAAK,IAAI,qCAAgC;AACzC,WAAK,IAAI,aAAa,KAAK,aAAa,MAAM,EAAE;AAChD,WAAK,IAAI,aAAa,KAAK,aAAa,YAAY,EAAE;AACtD,UAAI,KAAK,aAAa,aAAa;AACjC,aAAK,IAAI,kBAAkB,KAAK,aAAa,WAAW,EAAE;AAAA,MAC5D;AAAA,IACF,OAAO;AACL,WAAK,KAAK,iDAAiD;AAAA,IAC7D;AAGA,SAAK,IAAI,kBAAkB;AAC3B,SAAK,IAAI,0BAA0B,WAAW,OAAO,EAAE;AACvD,SAAK;AAAA,MACH,qCAAqC,OAAO,qBAAqB,UAAU;AAAA,IAC7E;AACA,SAAK;AAAA,MACH,kCAAkC,OAAO,kBAAkB,UAAU;AAAA,IACvE;AACA,SAAK;AAAA,MACH,kCAAkC,OAAO,kBAAkB,UAAU;AAAA,IACvE;AACA,SAAK;AAAA,MACH,+CAA+C,OAAO,+BAA+B,UAAU;AAAA,IACjG;AACA,SAAK;AAAA,MACH,2CAA2C,OAAO,2BAA2B,UAAU;AAAA,IACzF;AACA,SAAK;AAAA,MACH,qCAAqC,OAAO,qBAAqB,UAAU;AAAA,IAC7E;AACA,SAAK;AAAA,MACH,0CAA0C,OAAO,0BAA0B,UAAU;AAAA,IACvF;AAGA,SAAK,IAAI,oBAAoB;AAC7B,SAAK,IAAI,+BAA+B,OAAO,eAAe,UAAU,EAAE;AAC1E,SAAK,IAAI,6BAA6B,OAAO,aAAa,UAAU,EAAE;AACtE,SAAK,IAAI,4BAA4B,OAAO,YAAY,UAAU,EAAE;AAEpE,SAAK,IAAI,kCAA6B;AAAA,EACxC;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/cli/commands/test-imports.ts"],"sourcesContent":["import { BaseCommand } from \"../base-command.js\";\n\n// Test imports from the existing lib\nimport { loadGlobalConfig, resolveSource } from \"../lib/config.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { getPluginInfo } from \"../lib/plugin-info.js\";\nimport { loadSkillsMatrixFromSource } from \"../lib/source-loader.js\";\nimport { validatePluginManifest } from \"../lib/plugin-validator.js\";\nimport { compileAllAgents } from \"../lib/compiler.js\";\nimport { resolveSkillReference } from \"../lib/resolver.js\";\nimport { fileExists, readFile } from \"../utils/fs.js\";\nimport { verbose } from \"../utils/logger.js\";\n\nexport default class TestImports extends BaseCommand {\n static summary = \"Test that lib imports work (temporary command)\";\n static hidden = true; // Hide from help\n\n async run(): Promise<void> {\n this.log(\"Testing imports from cli/lib/...\");\n\n // Test config loading from init hook\n this.log(\"\\nConfig from init hook:\");\n if (this.sourceConfig) {\n this.log(` ✓ Config loaded successfully`);\n this.log(` Source: ${this.sourceConfig.source}`);\n this.log(` Origin: ${this.sourceConfig.sourceOrigin}`);\n if (this.sourceConfig.marketplace) {\n this.log(` Marketplace: ${this.sourceConfig.marketplace}`);\n }\n } else {\n this.warn(\" Config not loaded - init hook may have failed\");\n }\n\n // Test lib/ utilities\n this.log(\"\\nLib utilities:\");\n this.log(` EXIT_CODES.SUCCESS = ${EXIT_CODES.SUCCESS}`);\n this.log(\n ` loadGlobalConfig is a function: ${typeof loadGlobalConfig === \"function\"}`,\n );\n this.log(\n ` resolveSource is a function: ${typeof resolveSource === \"function\"}`,\n );\n this.log(\n ` getPluginInfo is a function: ${typeof getPluginInfo === \"function\"}`,\n );\n this.log(\n ` loadSkillsMatrixFromSource is a function: ${typeof loadSkillsMatrixFromSource === \"function\"}`,\n );\n this.log(\n ` validatePluginManifest is a function: ${typeof validatePluginManifest === \"function\"}`,\n );\n this.log(\n ` compileAllAgents is a function: ${typeof compileAllAgents === \"function\"}`,\n );\n this.log(\n ` resolveSkillReference is a function: ${typeof resolveSkillReference === \"function\"}`,\n );\n\n // Test utils/ utilities\n this.log(\"\\nUtils utilities:\");\n this.log(` fileExists is a function: ${typeof fileExists === \"function\"}`);\n this.log(` readFile is a function: ${typeof readFile === \"function\"}`);\n this.log(` verbose is a function: ${typeof verbose === \"function\"}`);\n\n this.log(\"\\n✓ All imports successful!\");\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAaA,IAAqB,cAArB,cAAyC,YAAY;AAAA,EACnD,OAAO,UAAU;AAAA,EACjB,OAAO,SAAS;AAAA;AAAA,EAEhB,MAAM,MAAqB;AACzB,SAAK,IAAI,kCAAkC;AAG3C,SAAK,IAAI,0BAA0B;AACnC,QAAI,KAAK,cAAc;AACrB,WAAK,IAAI,qCAAgC;AACzC,WAAK,IAAI,aAAa,KAAK,aAAa,MAAM,EAAE;AAChD,WAAK,IAAI,aAAa,KAAK,aAAa,YAAY,EAAE;AACtD,UAAI,KAAK,aAAa,aAAa;AACjC,aAAK,IAAI,kBAAkB,KAAK,aAAa,WAAW,EAAE;AAAA,MAC5D;AAAA,IACF,OAAO;AACL,WAAK,KAAK,iDAAiD;AAAA,IAC7D;AAGA,SAAK,IAAI,kBAAkB;AAC3B,SAAK,IAAI,0BAA0B,WAAW,OAAO,EAAE;AACvD,SAAK;AAAA,MACH,qCAAqC,OAAO,qBAAqB,UAAU;AAAA,IAC7E;AACA,SAAK;AAAA,MACH,kCAAkC,OAAO,kBAAkB,UAAU;AAAA,IACvE;AACA,SAAK;AAAA,MACH,kCAAkC,OAAO,kBAAkB,UAAU;AAAA,IACvE;AACA,SAAK;AAAA,MACH,+CAA+C,OAAO,+BAA+B,UAAU;AAAA,IACjG;AACA,SAAK;AAAA,MACH,2CAA2C,OAAO,2BAA2B,UAAU;AAAA,IACzF;AACA,SAAK;AAAA,MACH,qCAAqC,OAAO,qBAAqB,UAAU;AAAA,IAC7E;AACA,SAAK;AAAA,MACH,0CAA0C,OAAO,0BAA0B,UAAU;AAAA,IACvF;AAGA,SAAK,IAAI,oBAAoB;AAC7B,SAAK,IAAI,+BAA+B,OAAO,eAAe,UAAU,EAAE;AAC1E,SAAK,IAAI,6BAA6B,OAAO,aAAa,UAAU,EAAE;AACtE,SAAK,IAAI,4BAA4B,OAAO,YAAY,UAAU,EAAE;AAEpE,SAAK,IAAI,kCAA6B;AAAA,EACxC;AACF;","names":[]}