@agents-inc/cli 0.85.0 → 0.87.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 (121) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/{chunk-6VGBO6SZ.js → chunk-5M6Q5UQO.js} +2 -2
  3. package/dist/chunk-5UJJQFET.js +564 -0
  4. package/dist/chunk-5UJJQFET.js.map +1 -0
  5. package/dist/{chunk-TXW257CU.js → chunk-7FFNNDJQ.js} +181 -202
  6. package/dist/chunk-7FFNNDJQ.js.map +1 -0
  7. package/dist/{chunk-YJ2URWF7.js → chunk-B6MYECV6.js} +2 -2
  8. package/dist/{chunk-G2MINRWX.js → chunk-C5IYJ42F.js} +2 -2
  9. package/dist/{chunk-7UZUDHP7.js → chunk-CXWBVBDM.js} +2 -2
  10. package/dist/{chunk-CYPCJ536.js → chunk-FBZR46GC.js} +92 -92
  11. package/dist/chunk-FBZR46GC.js.map +1 -0
  12. package/dist/{chunk-LTFGEVTM.js → chunk-HH3AWXF4.js} +3 -3
  13. package/dist/{chunk-2XVLQDNI.js → chunk-HSLVCKVQ.js} +3 -3
  14. package/dist/{chunk-TAQGYJIS.js → chunk-HZ2IBXVQ.js} +3 -3
  15. package/dist/{chunk-LN76TJJP.js → chunk-HZQOFFKA.js} +10 -10
  16. package/dist/{chunk-W7LHI54P.js → chunk-I44YG6VI.js} +2 -2
  17. package/dist/{chunk-FT46LN7K.js → chunk-I5AZKNNL.js} +7 -8
  18. package/dist/chunk-I5AZKNNL.js.map +1 -0
  19. package/dist/chunk-J6PI73YV.js +68 -0
  20. package/dist/chunk-J6PI73YV.js.map +1 -0
  21. package/dist/{chunk-L7COG2EX.js → chunk-LZ7XQ3IU.js} +2 -2
  22. package/dist/{chunk-LMR7VAP3.js → chunk-MMTMXLI4.js} +2 -2
  23. package/dist/chunk-N6A7A4RA.js +16 -0
  24. package/dist/chunk-N6A7A4RA.js.map +1 -0
  25. package/dist/{chunk-WJKD6EGK.js → chunk-NUU3U43A.js} +5 -6
  26. package/dist/chunk-NUU3U43A.js.map +1 -0
  27. package/dist/{chunk-YYIWB42G.js → chunk-Q4DMIPZB.js} +2 -2
  28. package/dist/{chunk-YSLDMYWP.js → chunk-SGZOFIFF.js} +2 -2
  29. package/dist/{chunk-FKXD3EXJ.js → chunk-TMTUTUEV.js} +42 -228
  30. package/dist/chunk-TMTUTUEV.js.map +1 -0
  31. package/dist/{chunk-WCCWQ56J.js → chunk-UNEJKTLP.js} +3 -3
  32. package/dist/{chunk-ZGD7PLLC.js → chunk-ZOWRO7UQ.js} +3 -3
  33. package/dist/commands/build/marketplace.js +3 -3
  34. package/dist/commands/build/plugins.js +5 -5
  35. package/dist/commands/build/stack.js +5 -5
  36. package/dist/commands/compile.js +77 -171
  37. package/dist/commands/compile.js.map +1 -1
  38. package/dist/commands/config/index.js +5 -5
  39. package/dist/commands/config/path.js +4 -4
  40. package/dist/commands/config/show.js +5 -5
  41. package/dist/commands/diff.js +161 -167
  42. package/dist/commands/diff.js.map +1 -1
  43. package/dist/commands/doctor.js +68 -83
  44. package/dist/commands/doctor.js.map +1 -1
  45. package/dist/commands/edit.js +275 -209
  46. package/dist/commands/edit.js.map +1 -1
  47. package/dist/commands/eject.js +206 -124
  48. package/dist/commands/eject.js.map +1 -1
  49. package/dist/commands/import/skill.js +175 -144
  50. package/dist/commands/import/skill.js.map +1 -1
  51. package/dist/commands/info.js +58 -102
  52. package/dist/commands/info.js.map +1 -1
  53. package/dist/commands/init.js +19 -16
  54. package/dist/commands/list.js +4 -4
  55. package/dist/commands/new/agent.js +124 -102
  56. package/dist/commands/new/agent.js.map +1 -1
  57. package/dist/commands/new/marketplace.js +6 -6
  58. package/dist/commands/new/marketplace.js.map +1 -1
  59. package/dist/commands/new/skill.js +328 -15
  60. package/dist/commands/new/skill.js.map +1 -1
  61. package/dist/commands/outdated.js +16 -24
  62. package/dist/commands/outdated.js.map +1 -1
  63. package/dist/commands/search.js +166 -132
  64. package/dist/commands/search.js.map +1 -1
  65. package/dist/commands/uninstall.js +269 -189
  66. package/dist/commands/uninstall.js.map +1 -1
  67. package/dist/commands/update.js +238 -219
  68. package/dist/commands/update.js.map +1 -1
  69. package/dist/commands/validate.js +4 -4
  70. package/dist/components/skill-search/skill-search.js +2 -1
  71. package/dist/components/wizard/category-grid.test.js +4 -4
  72. package/dist/components/wizard/domain-selection.js +5 -5
  73. package/dist/components/wizard/help-modal.js +5 -5
  74. package/dist/components/wizard/source-grid.test.js +4 -4
  75. package/dist/components/wizard/stack-selection.js +5 -5
  76. package/dist/components/wizard/step-agents.js +5 -5
  77. package/dist/components/wizard/step-agents.test.js +5 -5
  78. package/dist/components/wizard/step-build.js +5 -5
  79. package/dist/components/wizard/step-build.test.js +5 -5
  80. package/dist/components/wizard/step-confirm.test.js +4 -4
  81. package/dist/components/wizard/step-settings.js +4 -4
  82. package/dist/components/wizard/step-settings.test.js +7 -7
  83. package/dist/components/wizard/step-sources.js +5 -5
  84. package/dist/components/wizard/step-sources.test.js +5 -5
  85. package/dist/components/wizard/step-stack.js +6 -6
  86. package/dist/components/wizard/step-stack.test.js +6 -6
  87. package/dist/components/wizard/wizard-layout.js +6 -6
  88. package/dist/components/wizard/wizard.js +14 -14
  89. package/dist/hooks/init.js +19 -16
  90. package/dist/hooks/init.js.map +1 -1
  91. package/dist/{loader-GT2A7R7U.js → loader-GSEGPK64.js} +3 -3
  92. package/dist/{source-loader-TNQW4P47.js → source-loader-OGFTIRIX.js} +4 -4
  93. package/dist/{source-manager-INRXRFJE.js → source-manager-FMMDDVZA.js} +4 -4
  94. package/dist/stores/wizard-store.js +4 -4
  95. package/dist/stores/wizard-store.test.js +4 -4
  96. package/package.json +1 -1
  97. package/dist/chunk-AABH2HSE.js +0 -340
  98. package/dist/chunk-AABH2HSE.js.map +0 -1
  99. package/dist/chunk-CYPCJ536.js.map +0 -1
  100. package/dist/chunk-FKXD3EXJ.js.map +0 -1
  101. package/dist/chunk-FT46LN7K.js.map +0 -1
  102. package/dist/chunk-TXW257CU.js.map +0 -1
  103. package/dist/chunk-WJKD6EGK.js.map +0 -1
  104. /package/dist/{chunk-6VGBO6SZ.js.map → chunk-5M6Q5UQO.js.map} +0 -0
  105. /package/dist/{chunk-YJ2URWF7.js.map → chunk-B6MYECV6.js.map} +0 -0
  106. /package/dist/{chunk-G2MINRWX.js.map → chunk-C5IYJ42F.js.map} +0 -0
  107. /package/dist/{chunk-7UZUDHP7.js.map → chunk-CXWBVBDM.js.map} +0 -0
  108. /package/dist/{chunk-LTFGEVTM.js.map → chunk-HH3AWXF4.js.map} +0 -0
  109. /package/dist/{chunk-2XVLQDNI.js.map → chunk-HSLVCKVQ.js.map} +0 -0
  110. /package/dist/{chunk-TAQGYJIS.js.map → chunk-HZ2IBXVQ.js.map} +0 -0
  111. /package/dist/{chunk-LN76TJJP.js.map → chunk-HZQOFFKA.js.map} +0 -0
  112. /package/dist/{chunk-W7LHI54P.js.map → chunk-I44YG6VI.js.map} +0 -0
  113. /package/dist/{chunk-L7COG2EX.js.map → chunk-LZ7XQ3IU.js.map} +0 -0
  114. /package/dist/{chunk-LMR7VAP3.js.map → chunk-MMTMXLI4.js.map} +0 -0
  115. /package/dist/{chunk-YYIWB42G.js.map → chunk-Q4DMIPZB.js.map} +0 -0
  116. /package/dist/{chunk-YSLDMYWP.js.map → chunk-SGZOFIFF.js.map} +0 -0
  117. /package/dist/{chunk-WCCWQ56J.js.map → chunk-UNEJKTLP.js.map} +0 -0
  118. /package/dist/{chunk-ZGD7PLLC.js.map → chunk-ZOWRO7UQ.js.map} +0 -0
  119. /package/dist/{loader-GT2A7R7U.js.map → loader-GSEGPK64.js.map} +0 -0
  120. /package/dist/{source-loader-TNQW4P47.js.map → source-loader-OGFTIRIX.js.map} +0 -0
  121. /package/dist/{source-manager-INRXRFJE.js.map → source-manager-FMMDDVZA.js.map} +0 -0
@@ -1,21 +1,22 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- compareLocalSkillsWithSource,
4
- detectInstallation,
5
- loadSkillsMatrixFromSource
6
- } from "../chunk-FKXD3EXJ.js";
7
- import "../chunk-YJ2URWF7.js";
8
- import {
9
- typedEntries
10
- } from "../chunk-ANXHMG32.js";
3
+ compareSkillsWithSource,
4
+ detectProject,
5
+ loadSource
6
+ } from "../chunk-5UJJQFET.js";
7
+ import "../chunk-N6A7A4RA.js";
8
+ import "../chunk-FBZR46GC.js";
9
+ import "../chunk-TMTUTUEV.js";
10
+ import "../chunk-B6MYECV6.js";
11
+ import "../chunk-ANXHMG32.js";
11
12
  import {
12
13
  BaseCommand,
13
14
  EXIT_CODES
14
- } from "../chunk-LMR7VAP3.js";
15
+ } from "../chunk-MMTMXLI4.js";
15
16
  import {
16
17
  fileExists,
17
18
  getErrorMessage
18
- } from "../chunk-WJKD6EGK.js";
19
+ } from "../chunk-NUU3U43A.js";
19
20
  import "../chunk-6XWHJHNZ.js";
20
21
  import {
21
22
  CLI_BIN_NAME,
@@ -73,8 +74,8 @@ var Outdated = class _Outdated extends BaseCommand {
73
74
  };
74
75
  async run() {
75
76
  const { flags } = await this.parse(_Outdated);
76
- const installation = await detectInstallation();
77
- const projectDir = installation?.projectDir ?? process.cwd();
77
+ const detected = await detectProject();
78
+ const projectDir = detected?.installation.projectDir ?? process.cwd();
78
79
  try {
79
80
  const projectLocalPath = path.join(projectDir, LOCAL_SKILLS_PATH);
80
81
  const homeDir = os.homedir();
@@ -99,24 +100,15 @@ var Outdated = class _Outdated extends BaseCommand {
99
100
  if (!flags.json) {
100
101
  this.log("Loading skills...");
101
102
  }
102
- const { matrix, sourcePath, isLocal } = await loadSkillsMatrixFromSource({
103
+ const { sourceResult } = await loadSource({
103
104
  sourceFlag: flags.source,
104
105
  projectDir
105
106
  });
107
+ const { matrix, sourcePath, isLocal } = sourceResult;
106
108
  if (!flags.json) {
107
109
  this.log(`Loaded from ${isLocal ? "local" : "remote"}: ${sourcePath}`);
108
110
  }
109
- const sourceSkills = {};
110
- for (const [skillId, skill] of typedEntries(matrix.skills)) {
111
- if (!skill) continue;
112
- if (!skill.local) {
113
- sourceSkills[skillId] = { path: skill.path };
114
- }
115
- }
116
- const projectResults = hasProject ? await compareLocalSkillsWithSource(projectDir, sourcePath, sourceSkills) : [];
117
- const globalResults = hasGlobal ? await compareLocalSkillsWithSource(homeDir, sourcePath, sourceSkills) : [];
118
- const seenIds = new Set(projectResults.map((r) => r.id));
119
- const results = [...projectResults, ...globalResults.filter((r) => !seenIds.has(r.id))];
111
+ const { merged: results } = await compareSkillsWithSource(projectDir, sourcePath, matrix);
120
112
  const summary = calculateSummary(results);
121
113
  if (flags.json) {
122
114
  this.log(
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/commands/outdated.ts"],"sourcesContent":["import { Flags } from \"@oclif/core\";\nimport { printTable } from \"@oclif/table\";\nimport os from \"os\";\nimport path from \"path\";\nimport { countBy } from \"remeda\";\n\nimport { BaseCommand } from \"../base-command.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\nimport { loadSkillsMatrixFromSource } from \"../lib/loading/index.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { detectInstallation } from \"../lib/installation/index.js\";\nimport { compareLocalSkillsWithSource, type SkillComparisonResult } from \"../lib/skills/index.js\";\nimport { fileExists } from \"../utils/fs.js\";\nimport { CLI_BIN_NAME, LOCAL_SKILLS_PATH } from \"../consts.js\";\nimport { typedEntries } from \"../utils/typed-object.js\";\n\ntype ComparisonSummary = {\n outdated: number;\n current: number;\n localOnly: number;\n};\n\nfunction calculateSummary(results: SkillComparisonResult[]): ComparisonSummary {\n const counts = countBy(results, (r) => r.status);\n return {\n outdated: counts[\"outdated\"] ?? 0,\n current: counts[\"current\"] ?? 0,\n localOnly: counts[\"local-only\"] ?? 0,\n };\n}\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 = \"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 examples = [\n {\n description: \"Check for outdated skills\",\n command: \"<%= config.bin %> <%= command.id %>\",\n },\n {\n description: \"Output results as JSON\",\n command: \"<%= config.bin %> <%= command.id %> --json\",\n },\n {\n description: \"Check against a custom source\",\n command: \"<%= config.bin %> <%= command.id %> --source github:org/marketplace\",\n },\n ];\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 installation = await detectInstallation();\n const projectDir = installation?.projectDir ?? process.cwd();\n\n try {\n const projectLocalPath = path.join(projectDir, LOCAL_SKILLS_PATH);\n const homeDir = os.homedir();\n const globalLocalPath = path.join(homeDir, LOCAL_SKILLS_PATH);\n const hasProject = await fileExists(projectLocalPath);\n const hasGlobal = projectDir !== homeDir && (await fileExists(globalLocalPath));\n\n if (!hasProject && !hasGlobal) {\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(\n `No local skills found. Run \\`${CLI_BIN_NAME} init\\` or \\`${CLI_BIN_NAME} edit\\` first.`,\n );\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 const sourceSkills: Record<string, { path: string }> = {};\n for (const [skillId, skill] of typedEntries(matrix.skills)) {\n if (!skill) continue;\n if (!skill.local) {\n sourceSkills[skillId] = { path: skill.path };\n }\n }\n\n // Check both project-scoped and global-scoped local skills\n const projectResults = hasProject\n ? await compareLocalSkillsWithSource(projectDir, sourcePath, sourceSkills)\n : [];\n const globalResults = hasGlobal\n ? await compareLocalSkillsWithSource(homeDir, sourcePath, sourceSkills)\n : [];\n\n // Merge results, project-scoped takes precedence\n const seenIds = new Set(projectResults.map((r) => r.id));\n const results = [...projectResults, ...globalResults.filter((r) => !seenIds.has(r.id))];\n const summary = calculateSummary(results);\n\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 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 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 if (summary.outdated > 0) {\n this.error(\"Some skills are outdated\", { exit: EXIT_CODES.ERROR });\n }\n } catch (error) {\n const message = getErrorMessage(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 os from \"os\";\nimport path from \"path\";\nimport { countBy } from \"remeda\";\n\nimport { BaseCommand } from \"../base-command.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { loadSource, compareSkillsWithSource, detectProject } from \"../lib/operations/index.js\";\nimport { type SkillComparisonResult } from \"../lib/skills/index.js\";\nimport { fileExists } from \"../utils/fs.js\";\nimport { CLI_BIN_NAME, LOCAL_SKILLS_PATH } from \"../consts.js\";\n\ntype ComparisonSummary = {\n outdated: number;\n current: number;\n localOnly: number;\n};\n\nfunction calculateSummary(results: SkillComparisonResult[]): ComparisonSummary {\n const counts = countBy(results, (r) => r.status);\n return {\n outdated: counts[\"outdated\"] ?? 0,\n current: counts[\"current\"] ?? 0,\n localOnly: counts[\"local-only\"] ?? 0,\n };\n}\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 = \"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 examples = [\n {\n description: \"Check for outdated skills\",\n command: \"<%= config.bin %> <%= command.id %>\",\n },\n {\n description: \"Output results as JSON\",\n command: \"<%= config.bin %> <%= command.id %> --json\",\n },\n {\n description: \"Check against a custom source\",\n command: \"<%= config.bin %> <%= command.id %> --source github:org/marketplace\",\n },\n ];\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 detected = await detectProject();\n const projectDir = detected?.installation.projectDir ?? process.cwd();\n\n try {\n const projectLocalPath = path.join(projectDir, LOCAL_SKILLS_PATH);\n const homeDir = os.homedir();\n const globalLocalPath = path.join(homeDir, LOCAL_SKILLS_PATH);\n const hasProject = await fileExists(projectLocalPath);\n const hasGlobal = projectDir !== homeDir && (await fileExists(globalLocalPath));\n\n if (!hasProject && !hasGlobal) {\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(\n `No local skills found. Run \\`${CLI_BIN_NAME} init\\` or \\`${CLI_BIN_NAME} edit\\` first.`,\n );\n }\n return;\n }\n\n if (!flags.json) {\n this.log(\"Loading skills...\");\n }\n\n const { sourceResult } = await loadSource({\n sourceFlag: flags.source,\n projectDir,\n });\n const { matrix, sourcePath, isLocal } = sourceResult;\n\n if (!flags.json) {\n this.log(`Loaded from ${isLocal ? \"local\" : \"remote\"}: ${sourcePath}`);\n }\n\n const { merged: results } = await compareSkillsWithSource(projectDir, sourcePath, matrix);\n const summary = calculateSummary(results);\n\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 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 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 if (summary.outdated > 0) {\n this.error(\"Some skills are outdated\", { exit: EXIT_CODES.ERROR });\n }\n } catch (error) {\n const message = getErrorMessage(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,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  SkillSearch
4
- } from "../chunk-FT46LN7K.js";
4
+ } from "../chunk-I5AZKNNL.js";
5
5
  import "../chunk-HEQVUIHQ.js";
6
6
  import "../chunk-U3IGFMCY.js";
7
7
  import "../chunk-HK53FRMU.js";
@@ -10,26 +10,32 @@ import {
10
10
  STATUS_MESSAGES,
11
11
  SUCCESS_MESSAGES
12
12
  } from "../chunk-B7KZLXHV.js";
13
+ import {
14
+ loadSource
15
+ } from "../chunk-5UJJQFET.js";
16
+ import {
17
+ truncateText
18
+ } from "../chunk-N6A7A4RA.js";
19
+ import "../chunk-FBZR46GC.js";
13
20
  import {
14
21
  fetchFromSource,
15
- loadSkillsMatrixFromSource,
16
22
  resolveAllSources
17
- } from "../chunk-FKXD3EXJ.js";
23
+ } from "../chunk-TMTUTUEV.js";
18
24
  import {
19
25
  parseFrontmatter
20
- } from "../chunk-YJ2URWF7.js";
26
+ } from "../chunk-B6MYECV6.js";
21
27
  import "../chunk-ANXHMG32.js";
22
28
  import {
23
29
  BaseCommand,
24
30
  EXIT_CODES
25
- } from "../chunk-LMR7VAP3.js";
31
+ } from "../chunk-MMTMXLI4.js";
26
32
  import {
27
33
  copy,
28
34
  ensureDir,
29
35
  fileExists,
30
36
  listDirectories,
31
37
  readFile
32
- } from "../chunk-WJKD6EGK.js";
38
+ } from "../chunk-NUU3U43A.js";
33
39
  import "../chunk-6XWHJHNZ.js";
34
40
  import {
35
41
  DEFAULT_SKILLS_SUBDIR,
@@ -55,70 +61,6 @@ init_esm_shims();
55
61
  // src/cli/commands/search.tsx
56
62
  import { jsx } from "react/jsx-runtime";
57
63
  var MAX_DESCRIPTION_WIDTH = 50;
58
- function truncate(str, maxLength) {
59
- if (str.length <= maxLength) return str;
60
- return `${str.slice(0, maxLength - 3)}...`;
61
- }
62
- function matchesQuery(skill, query) {
63
- const lowerQuery = query.toLowerCase();
64
- if (skill.id.toLowerCase().includes(lowerQuery)) return true;
65
- if (skill.displayName.toLowerCase().includes(lowerQuery)) return true;
66
- if (skill.slug.toLowerCase().includes(lowerQuery)) return true;
67
- if (skill.description.toLowerCase().includes(lowerQuery)) return true;
68
- if (skill.category.toLowerCase().includes(lowerQuery)) return true;
69
- return false;
70
- }
71
- function matchesCategory(skill, category) {
72
- const lowerCategory = category.toLowerCase();
73
- return skill.category.toLowerCase().includes(lowerCategory);
74
- }
75
- function toSourcedSkill(skill, sourceName, sourceUrl) {
76
- return {
77
- ...skill,
78
- sourceName,
79
- sourceUrl
80
- };
81
- }
82
- async function fetchSkillsFromSource(source, forceRefresh) {
83
- try {
84
- const result = await fetchFromSource(source.url, { forceRefresh });
85
- const skillsDir = path.join(result.path, DEFAULT_SKILLS_SUBDIR);
86
- if (!await fileExists(skillsDir)) {
87
- return [];
88
- }
89
- const skillDirs = await listDirectories(skillsDir);
90
- const skills = [];
91
- for (const skillDir of skillDirs) {
92
- const skillMdPath = path.join(skillsDir, skillDir, STANDARD_FILES.SKILL_MD);
93
- if (!await fileExists(skillMdPath)) continue;
94
- const content = await readFile(skillMdPath);
95
- const frontmatter = parseFrontmatter(content, skillMdPath);
96
- if (!frontmatter) continue;
97
- skills.push({
98
- id: frontmatter.name,
99
- description: frontmatter.description,
100
- // Boundary cast: directory name used as slug for third-party source skill
101
- slug: skillDir,
102
- displayName: skillDir,
103
- // Boundary cast: external source skills have no real category; "imported" is a display-only placeholder
104
- category: "imported",
105
- author: `@${source.name}`,
106
- conflictsWith: [],
107
- isRecommended: false,
108
- requires: [],
109
- alternatives: [],
110
- discourages: [],
111
- compatibleWith: [],
112
- sourceName: source.name,
113
- sourceUrl: source.url,
114
- path: path.join(skillsDir, skillDir)
115
- });
116
- }
117
- return skills;
118
- } catch {
119
- return [];
120
- }
121
- }
122
64
  var Search = class _Search extends BaseCommand {
123
65
  static summary = "Search available skills";
124
66
  static description = "Search skills by ID, alias, description, or category. Run without arguments or with -i for interactive mode with multi-select.";
@@ -174,44 +116,9 @@ var Search = class _Search extends BaseCommand {
174
116
  }
175
117
  }
176
118
  async runInteractive(initialQuery, forceRefresh, projectDir) {
177
- this.log("Loading skills from all sources...");
178
119
  try {
179
- const { matrix, sourcePath } = await loadSkillsMatrixFromSource({
180
- sourceFlag: void 0,
181
- projectDir,
182
- forceRefresh
183
- });
184
- const primarySkills = Object.values(matrix.skills).filter((skill) => skill !== void 0).map((skill) => toSourcedSkill(skill, "marketplace", sourcePath));
185
- const { extras } = await resolveAllSources(projectDir);
186
- const extraSkillArrays = await Promise.all(
187
- extras.map((source) => fetchSkillsFromSource(source, forceRefresh))
188
- );
189
- const allSkills = [...primarySkills, ...extraSkillArrays.flat()];
190
- const sourceCount = 1 + extras.length;
191
- this.log(`Loaded ${allSkills.length} skills from ${sourceCount} source(s)`);
192
- this.log("");
193
- const searchResultPromise = new Promise((resolve) => {
194
- const { waitUntilExit } = render(
195
- /* @__PURE__ */ jsx(
196
- SkillSearch,
197
- {
198
- skills: allSkills,
199
- sourceCount,
200
- initialQuery,
201
- onComplete: (result) => {
202
- resolve(result);
203
- },
204
- onCancel: () => {
205
- resolve({ selectedSkills: [], cancelled: true });
206
- }
207
- }
208
- )
209
- );
210
- waitUntilExit().then(() => {
211
- resolve({ selectedSkills: [], cancelled: true });
212
- });
213
- });
214
- const searchResult = await searchResultPromise;
120
+ const { allSkills, sourceCount } = await this.loadAllSourceSkills(forceRefresh, projectDir);
121
+ const searchResult = await this.showSearchUI(allSkills, sourceCount, initialQuery);
215
122
  if (searchResult.cancelled) {
216
123
  this.log("Search cancelled");
217
124
  this.exit(EXIT_CODES.CANCELLED);
@@ -220,42 +127,87 @@ var Search = class _Search extends BaseCommand {
220
127
  this.log("No skills selected");
221
128
  return;
222
129
  }
223
- this.log("");
224
- this.log(`Importing ${searchResult.selectedSkills.length} skill(s)...`);
225
- const destDir = path.join(projectDir, LOCAL_SKILLS_PATH);
226
- for (const skill of searchResult.selectedSkills) {
227
- if (skill.path) {
228
- const destPath = path.join(destDir, skill.id);
229
- await ensureDir(path.dirname(destPath));
230
- await copy(skill.path, destPath);
231
- this.logSuccess(`Imported: ${skill.id}`);
232
- } else {
233
- this.warn(`Skipping ${skill.id}: No source path available`);
234
- }
235
- }
236
- this.log("");
237
- this.logSuccess(SUCCESS_MESSAGES.IMPORT_COMPLETE);
238
- this.log(`Skills location: ${destDir}`);
239
- this.log(INFO_MESSAGES.RUN_COMPILE);
130
+ await this.importSelectedSkills(searchResult.selectedSkills, projectDir);
240
131
  } catch (error) {
241
132
  this.handleError(error);
242
133
  }
243
134
  }
135
+ async loadAllSourceSkills(forceRefresh, projectDir) {
136
+ this.log("Loading skills from all sources...");
137
+ const { sourceResult } = await loadSource({
138
+ sourceFlag: void 0,
139
+ projectDir,
140
+ forceRefresh
141
+ });
142
+ const { matrix, sourcePath } = sourceResult;
143
+ const primarySkills = Object.values(matrix.skills).filter((skill) => skill !== void 0).map((skill) => toSourcedSkill(skill, "marketplace", sourcePath));
144
+ const { extras } = await resolveAllSources(projectDir);
145
+ const extraSkillArrays = await Promise.all(
146
+ extras.map((source) => fetchSkillsFromExternalSource(source, forceRefresh))
147
+ );
148
+ const allSkills = [...primarySkills, ...extraSkillArrays.flat()];
149
+ const sourceCount = 1 + extras.length;
150
+ this.log(`Loaded ${allSkills.length} skills from ${sourceCount} source(s)`);
151
+ this.log("");
152
+ return { allSkills, sourceCount };
153
+ }
154
+ async showSearchUI(allSkills, sourceCount, initialQuery) {
155
+ const searchResultPromise = new Promise((resolve) => {
156
+ const { waitUntilExit } = render(
157
+ /* @__PURE__ */ jsx(
158
+ SkillSearch,
159
+ {
160
+ skills: allSkills,
161
+ sourceCount,
162
+ initialQuery,
163
+ onComplete: (result) => {
164
+ resolve(result);
165
+ },
166
+ onCancel: () => {
167
+ resolve({ selectedSkills: [], cancelled: true });
168
+ }
169
+ }
170
+ )
171
+ );
172
+ waitUntilExit().then(() => {
173
+ resolve({ selectedSkills: [], cancelled: true });
174
+ });
175
+ });
176
+ return searchResultPromise;
177
+ }
178
+ async importSelectedSkills(skills, projectDir) {
179
+ this.log("");
180
+ this.log(`Importing ${skills.length} skill(s)...`);
181
+ const copyResults = await copySearchedSkillsToLocal(skills, projectDir);
182
+ for (const result of copyResults) {
183
+ if (result.copied) {
184
+ this.logSuccess(`Imported: ${result.id}`);
185
+ } else {
186
+ this.warn(`Skipping ${result.id}: ${result.reason}`);
187
+ }
188
+ }
189
+ const destDir = path.join(projectDir, LOCAL_SKILLS_PATH);
190
+ this.log("");
191
+ this.logSuccess(SUCCESS_MESSAGES.IMPORT_COMPLETE);
192
+ this.log(`Skills location: ${destDir}`);
193
+ this.log(INFO_MESSAGES.RUN_COMPILE);
194
+ }
244
195
  async runStatic(query, flags) {
245
196
  try {
246
197
  this.log(STATUS_MESSAGES.LOADING_SKILLS);
247
- const { matrix, sourcePath, isLocal } = await loadSkillsMatrixFromSource({
248
- sourceFlag: flags.source
198
+ const { sourceResult } = await loadSource({
199
+ sourceFlag: flags.source,
200
+ projectDir: process.cwd()
249
201
  });
202
+ const { matrix, sourcePath, isLocal } = sourceResult;
250
203
  this.log(`Loaded from ${isLocal ? "local" : "remote"}: ${sourcePath}`);
251
204
  const allSkills = Object.values(matrix.skills).filter(
252
205
  (skill) => skill !== void 0
253
206
  );
254
- let results = allSkills.filter((skill) => matchesQuery(skill, query));
255
- if (flags.category) {
256
- results = results.filter((skill) => matchesCategory(skill, flags.category));
257
- }
258
- results = sortBy(results, (r) => r.displayName.toLowerCase());
207
+ const results = sortBy(
208
+ filterSkillsByQuery(allSkills, { query, category: flags.category }),
209
+ (r) => r.displayName.toLowerCase()
210
+ );
259
211
  this.log("");
260
212
  if (results.length === 0) {
261
213
  this.warn(`No skills found matching "${query}"`);
@@ -274,7 +226,7 @@ var Search = class _Search extends BaseCommand {
274
226
  data: results.map((skill) => ({
275
227
  id: skill.displayName,
276
228
  category: skill.category,
277
- description: truncate(skill.description, MAX_DESCRIPTION_WIDTH)
229
+ description: truncateText(skill.description, MAX_DESCRIPTION_WIDTH)
278
230
  })),
279
231
  columns: [
280
232
  { key: "id", name: "ID" },
@@ -290,6 +242,88 @@ var Search = class _Search extends BaseCommand {
290
242
  }
291
243
  }
292
244
  };
245
+ async function fetchSkillsFromExternalSource(source, forceRefresh) {
246
+ try {
247
+ const result = await fetchFromSource(source.url, { forceRefresh });
248
+ const skillsDir = path.join(result.path, DEFAULT_SKILLS_SUBDIR);
249
+ if (!await fileExists(skillsDir)) {
250
+ return [];
251
+ }
252
+ const skillDirs = await listDirectories(skillsDir);
253
+ const skills = [];
254
+ for (const skillDir of skillDirs) {
255
+ const skillMdPath = path.join(skillsDir, skillDir, STANDARD_FILES.SKILL_MD);
256
+ if (!await fileExists(skillMdPath)) continue;
257
+ const content = await readFile(skillMdPath);
258
+ const frontmatter = parseFrontmatter(content, skillMdPath);
259
+ if (!frontmatter) continue;
260
+ skills.push({
261
+ id: frontmatter.name,
262
+ description: frontmatter.description,
263
+ // Boundary cast: directory name used as slug for third-party source skill
264
+ slug: skillDir,
265
+ displayName: skillDir,
266
+ // Boundary cast: external source skills have no real category; "imported" is a display-only placeholder
267
+ category: "imported",
268
+ author: `@${source.name}`,
269
+ conflictsWith: [],
270
+ isRecommended: false,
271
+ requires: [],
272
+ alternatives: [],
273
+ discourages: [],
274
+ compatibleWith: [],
275
+ sourceName: source.name,
276
+ sourceUrl: source.url,
277
+ path: path.join(skillsDir, skillDir)
278
+ });
279
+ }
280
+ return skills;
281
+ } catch {
282
+ return [];
283
+ }
284
+ }
285
+ function matchesQuery(skill, query) {
286
+ const lowerQuery = query.toLowerCase();
287
+ if (skill.id.toLowerCase().includes(lowerQuery)) return true;
288
+ if (skill.displayName.toLowerCase().includes(lowerQuery)) return true;
289
+ if (skill.slug.toLowerCase().includes(lowerQuery)) return true;
290
+ if (skill.description.toLowerCase().includes(lowerQuery)) return true;
291
+ if (skill.category.toLowerCase().includes(lowerQuery)) return true;
292
+ return false;
293
+ }
294
+ function matchesCategory(skill, category) {
295
+ const lowerCategory = category.toLowerCase();
296
+ return skill.category.toLowerCase().includes(lowerCategory);
297
+ }
298
+ function filterSkillsByQuery(skills, options) {
299
+ let results = skills.filter((skill) => matchesQuery(skill, options.query));
300
+ if (options.category) {
301
+ results = results.filter((skill) => matchesCategory(skill, options.category));
302
+ }
303
+ return results;
304
+ }
305
+ function toSourcedSkill(skill, sourceName, sourceUrl) {
306
+ return {
307
+ ...skill,
308
+ sourceName,
309
+ sourceUrl
310
+ };
311
+ }
312
+ async function copySearchedSkillsToLocal(skills, projectDir) {
313
+ const destDir = path.join(projectDir, LOCAL_SKILLS_PATH);
314
+ const results = [];
315
+ for (const skill of skills) {
316
+ if (skill.path) {
317
+ const destPath = path.join(destDir, skill.id);
318
+ await ensureDir(path.dirname(destPath));
319
+ await copy(skill.path, destPath);
320
+ results.push({ id: skill.id, copied: true });
321
+ } else {
322
+ results.push({ id: skill.id, copied: false, reason: "No source path available" });
323
+ }
324
+ }
325
+ return results;
326
+ }
293
327
  export {
294
328
  Search as default
295
329
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/commands/search.tsx","../../src/cli/components/skill-search/index.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport { printTable } from \"@oclif/table\";\nimport { render } from \"ink\";\nimport path from \"path\";\nimport { sortBy } from \"remeda\";\n\nimport { BaseCommand } from \"../base-command.js\";\nimport { SkillSearch, type SkillSearchResult } from \"../components/skill-search/index.js\";\nimport type { SourcedSkill } from \"../components/skill-search/skill-search.js\";\nimport { DEFAULT_SKILLS_SUBDIR, LOCAL_SKILLS_PATH, STANDARD_FILES } from \"../consts.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { resolveAllSources, type SourceEntry } from \"../lib/configuration/index.js\";\nimport {\n loadSkillsMatrixFromSource,\n fetchFromSource,\n parseFrontmatter,\n} from \"../lib/loading/index.js\";\nimport type { CategoryPath, ResolvedSkill, SkillSlug } from \"../types/index.js\";\nimport { listDirectories, fileExists, readFile, copy, ensureDir } from \"../utils/fs.js\";\nimport { SUCCESS_MESSAGES, STATUS_MESSAGES, INFO_MESSAGES } from \"../utils/messages.js\";\n\nconst MAX_DESCRIPTION_WIDTH = 50;\n\nfunction truncate(str: string, maxLength: number): string {\n if (str.length <= maxLength) return str;\n return `${str.slice(0, maxLength - 3)}...`;\n}\n\nfunction matchesQuery(skill: ResolvedSkill, query: string): boolean {\n const lowerQuery = query.toLowerCase();\n\n if (skill.id.toLowerCase().includes(lowerQuery)) return true;\n if (skill.displayName.toLowerCase().includes(lowerQuery)) return true;\n if (skill.slug.toLowerCase().includes(lowerQuery)) return true;\n if (skill.description.toLowerCase().includes(lowerQuery)) return true;\n if (skill.category.toLowerCase().includes(lowerQuery)) return true;\n\n return false;\n}\n\nfunction matchesCategory(skill: ResolvedSkill, category: string): boolean {\n const lowerCategory = category.toLowerCase();\n return skill.category.toLowerCase().includes(lowerCategory);\n}\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\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 if (!(await fileExists(skillsDir))) {\n return [];\n }\n\n const skillDirs = await listDirectories(skillsDir);\n const skills: SourcedSkill[] = [];\n\n for (const skillDir of skillDirs) {\n const skillMdPath = path.join(skillsDir, skillDir, STANDARD_FILES.SKILL_MD);\n if (!(await fileExists(skillMdPath))) continue;\n\n const content = await readFile(skillMdPath);\n const frontmatter = parseFrontmatter(content, skillMdPath);\n if (!frontmatter) continue;\n\n skills.push({\n id: frontmatter.name,\n description: frontmatter.description,\n // Boundary cast: directory name used as slug for third-party source skill\n slug: skillDir as SkillSlug,\n displayName: skillDir,\n // Boundary cast: external source skills have no real category; \"imported\" is a display-only placeholder\n category: \"imported\" as CategoryPath,\n author: `@${source.name}`,\n conflictsWith: [],\n isRecommended: false,\n requires: [],\n alternatives: [],\n discourages: [],\n compatibleWith: [],\n sourceName: source.name,\n sourceUrl: source.url,\n path: path.join(skillsDir, skillDir),\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 ID, alias, description, or category. \" +\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)\",\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 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 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 const { matrix, sourcePath } = await loadSkillsMatrixFromSource({\n sourceFlag: undefined,\n projectDir,\n forceRefresh,\n });\n\n const primarySkills = Object.values(matrix.skills)\n .filter((skill): skill is ResolvedSkill => skill !== undefined)\n .map((skill) => toSourcedSkill(skill, \"marketplace\", sourcePath));\n\n const { extras } = await resolveAllSources(projectDir);\n\n const extraSkillArrays = await Promise.all(\n extras.map((source) => fetchSkillsFromSource(source, forceRefresh)),\n );\n\n const allSkills: SourcedSkill[] = [...primarySkills, ...extraSkillArrays.flat()];\n const sourceCount = 1 + extras.length;\n\n this.log(`Loaded ${allSkills.length} skills from ${sourceCount} source(s)`);\n this.log(\"\");\n\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 waitUntilExit().then(() => {\n resolve({ selectedSkills: [], cancelled: true });\n });\n });\n\n const searchResult = await searchResultPromise;\n\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 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(SUCCESS_MESSAGES.IMPORT_COMPLETE);\n this.log(`Skills location: ${destDir}`);\n this.log(INFO_MESSAGES.RUN_COMPILE);\n } catch (error) {\n this.handleError(error);\n }\n }\n\n private async runStatic(\n query: string,\n flags: { source?: string; category?: string },\n ): Promise<void> {\n try {\n this.log(STATUS_MESSAGES.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 const allSkills = Object.values(matrix.skills).filter(\n (skill): skill is ResolvedSkill => skill !== undefined,\n );\n\n let results = allSkills.filter((skill) => matchesQuery(skill, query));\n\n if (flags.category) {\n results = results.filter((skill) => matchesCategory(skill, flags.category!));\n }\n\n results = sortBy(results, (r) => r.displayName.toLowerCase());\n\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 printTable({\n data: results.map((skill) => ({\n id: skill.displayName,\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 { SkillSearch, type SkillSearchResult } from \"./skill-search.js\";\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/cli/commands/search.tsx","../../src/cli/components/skill-search/index.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport { printTable } from \"@oclif/table\";\nimport { render } from \"ink\";\nimport path from \"path\";\nimport { sortBy } from \"remeda\";\n\nimport { BaseCommand } from \"../base-command.js\";\nimport {\n SkillSearch,\n type SkillSearchResult,\n type SourcedSkill,\n} from \"../components/skill-search/index.js\";\nimport { DEFAULT_SKILLS_SUBDIR, LOCAL_SKILLS_PATH, STANDARD_FILES } from \"../consts.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { resolveAllSources } from \"../lib/configuration/index.js\";\nimport { loadSource } from \"../lib/operations/index.js\";\nimport { fetchFromSource, parseFrontmatter } from \"../lib/loading/index.js\";\nimport type { SourceEntry } from \"../types/config.js\";\nimport type { CategoryPath, ResolvedSkill, SkillSlug } from \"../types/index.js\";\nimport { copy, ensureDir, fileExists, listDirectories, readFile } from \"../utils/fs.js\";\nimport { SUCCESS_MESSAGES, STATUS_MESSAGES, INFO_MESSAGES } from \"../utils/messages.js\";\nimport { truncateText } from \"../utils/string.js\";\n\nconst MAX_DESCRIPTION_WIDTH = 50;\n\nexport default class Search extends BaseCommand {\n static summary = \"Search available skills\";\n static description =\n \"Search skills by ID, alias, description, or category. \" +\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)\",\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 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 private async runInteractive(\n initialQuery: string | undefined,\n forceRefresh: boolean,\n projectDir: string,\n ): Promise<void> {\n try {\n const { allSkills, sourceCount } = await this.loadAllSourceSkills(forceRefresh, projectDir);\n const searchResult = await this.showSearchUI(allSkills, sourceCount, initialQuery);\n\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 await this.importSelectedSkills(searchResult.selectedSkills, projectDir);\n } catch (error) {\n this.handleError(error);\n }\n }\n\n private async loadAllSourceSkills(\n forceRefresh: boolean,\n projectDir: string,\n ): Promise<{ allSkills: SourcedSkill[]; sourceCount: number }> {\n this.log(\"Loading skills from all sources...\");\n\n const { sourceResult } = await loadSource({\n sourceFlag: undefined,\n projectDir,\n forceRefresh,\n });\n const { matrix, sourcePath } = sourceResult;\n\n const primarySkills = Object.values(matrix.skills)\n .filter((skill): skill is ResolvedSkill => skill !== undefined)\n .map((skill) => toSourcedSkill(skill, \"marketplace\", sourcePath));\n\n const { extras } = await resolveAllSources(projectDir);\n\n const extraSkillArrays = await Promise.all(\n extras.map((source) => fetchSkillsFromExternalSource(source, forceRefresh)),\n );\n\n const allSkills: SourcedSkill[] = [...primarySkills, ...extraSkillArrays.flat()];\n const sourceCount = 1 + extras.length;\n\n this.log(`Loaded ${allSkills.length} skills from ${sourceCount} source(s)`);\n this.log(\"\");\n\n return { allSkills, sourceCount };\n }\n\n private async showSearchUI(\n allSkills: SourcedSkill[],\n sourceCount: number,\n initialQuery: string | undefined,\n ): Promise<SkillSearchResult> {\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 waitUntilExit().then(() => {\n resolve({ selectedSkills: [], cancelled: true });\n });\n });\n\n return searchResultPromise;\n }\n\n private async importSelectedSkills(skills: SourcedSkill[], projectDir: string): Promise<void> {\n this.log(\"\");\n this.log(`Importing ${skills.length} skill(s)...`);\n\n const copyResults = await copySearchedSkillsToLocal(skills, projectDir);\n\n for (const result of copyResults) {\n if (result.copied) {\n this.logSuccess(`Imported: ${result.id}`);\n } else {\n this.warn(`Skipping ${result.id}: ${result.reason}`);\n }\n }\n\n const destDir = path.join(projectDir, LOCAL_SKILLS_PATH);\n this.log(\"\");\n this.logSuccess(SUCCESS_MESSAGES.IMPORT_COMPLETE);\n this.log(`Skills location: ${destDir}`);\n this.log(INFO_MESSAGES.RUN_COMPILE);\n }\n\n private async runStatic(\n query: string,\n flags: { source?: string; category?: string },\n ): Promise<void> {\n try {\n this.log(STATUS_MESSAGES.LOADING_SKILLS);\n\n const { sourceResult } = await loadSource({\n sourceFlag: flags.source,\n projectDir: process.cwd(),\n });\n const { matrix, sourcePath, isLocal } = sourceResult;\n\n this.log(`Loaded from ${isLocal ? \"local\" : \"remote\"}: ${sourcePath}`);\n\n const allSkills = Object.values(matrix.skills).filter(\n (skill): skill is ResolvedSkill => skill !== undefined,\n );\n\n const results = sortBy(\n filterSkillsByQuery(allSkills, { query, category: flags.category }),\n (r) => r.displayName.toLowerCase(),\n );\n\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 printTable({\n data: results.map((skill) => ({\n id: skill.displayName,\n category: skill.category,\n description: truncateText(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\ntype FilterSkillsOptions = {\n query: string;\n category?: string;\n};\n\ntype CopySearchedSkillResult = {\n id: string;\n copied: boolean;\n /** Reason when `copied` is false */\n reason?: string;\n};\n\nasync function fetchSkillsFromExternalSource(\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 if (!(await fileExists(skillsDir))) {\n return [];\n }\n\n const skillDirs = await listDirectories(skillsDir);\n const skills: SourcedSkill[] = [];\n\n for (const skillDir of skillDirs) {\n const skillMdPath = path.join(skillsDir, skillDir, STANDARD_FILES.SKILL_MD);\n if (!(await fileExists(skillMdPath))) continue;\n\n const content = await readFile(skillMdPath);\n const frontmatter = parseFrontmatter(content, skillMdPath);\n if (!frontmatter) continue;\n\n skills.push({\n id: frontmatter.name,\n description: frontmatter.description,\n // Boundary cast: directory name used as slug for third-party source skill\n slug: skillDir as SkillSlug,\n displayName: skillDir,\n // Boundary cast: external source skills have no real category; \"imported\" is a display-only placeholder\n category: \"imported\" as CategoryPath,\n author: `@${source.name}`,\n conflictsWith: [],\n isRecommended: false,\n requires: [],\n alternatives: [],\n discourages: [],\n compatibleWith: [],\n sourceName: source.name,\n sourceUrl: source.url,\n path: path.join(skillsDir, skillDir),\n });\n }\n\n return skills;\n } catch {\n // Source unavailable, return empty\n return [];\n }\n}\n\nfunction matchesQuery(skill: ResolvedSkill, query: string): boolean {\n const lowerQuery = query.toLowerCase();\n\n if (skill.id.toLowerCase().includes(lowerQuery)) return true;\n if (skill.displayName.toLowerCase().includes(lowerQuery)) return true;\n if (skill.slug.toLowerCase().includes(lowerQuery)) return true;\n if (skill.description.toLowerCase().includes(lowerQuery)) return true;\n if (skill.category.toLowerCase().includes(lowerQuery)) return true;\n\n return false;\n}\n\nfunction matchesCategory(skill: ResolvedSkill, category: string): boolean {\n const lowerCategory = category.toLowerCase();\n return skill.category.toLowerCase().includes(lowerCategory);\n}\n\nfunction filterSkillsByQuery(\n skills: ResolvedSkill[],\n options: FilterSkillsOptions,\n): ResolvedSkill[] {\n let results = skills.filter((skill) => matchesQuery(skill, options.query));\n\n if (options.category) {\n results = results.filter((skill) => matchesCategory(skill, options.category!));\n }\n\n return results;\n}\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\nasync function copySearchedSkillsToLocal(\n skills: SourcedSkill[],\n projectDir: string,\n): Promise<CopySearchedSkillResult[]> {\n const destDir = path.join(projectDir, LOCAL_SKILLS_PATH);\n const results: CopySearchedSkillResult[] = [];\n\n for (const skill of skills) {\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 results.push({ id: skill.id, copied: true });\n } else {\n results.push({ id: skill.id, copied: false, reason: \"No source path available\" });\n }\n }\n\n return results;\n}\n","export { SkillSearch, type SkillSearchResult, type SourcedSkill } from \"./skill-search.js\";\n"],"mappings":"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","names":[]}