@claude-collective/cli 0.2.0 → 0.6.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 (166) hide show
  1. package/CHANGELOG.md +113 -0
  2. package/README.md +1 -1
  3. package/dist/chunk-367K3JB3.js +84 -0
  4. package/dist/chunk-367K3JB3.js.map +1 -0
  5. package/dist/chunk-6ESUJMM7.js +54 -0
  6. package/dist/chunk-6ESUJMM7.js.map +1 -0
  7. package/dist/chunk-6OY6ZYQF.js +93 -0
  8. package/dist/chunk-6OY6ZYQF.js.map +1 -0
  9. package/dist/chunk-6WEQADPL.js +307 -0
  10. package/dist/chunk-6WEQADPL.js.map +1 -0
  11. package/dist/chunk-AU7XVCLO.js +91 -0
  12. package/dist/chunk-AU7XVCLO.js.map +1 -0
  13. package/dist/chunk-AZP2AA5M.js +425 -0
  14. package/dist/chunk-AZP2AA5M.js.map +1 -0
  15. package/dist/chunk-D4IQAT27.js +114 -0
  16. package/dist/chunk-D4IQAT27.js.map +1 -0
  17. package/dist/chunk-DHET7RCE.js +50 -0
  18. package/dist/chunk-DHET7RCE.js.map +1 -0
  19. package/dist/chunk-DHFFRMF6.js +31 -0
  20. package/dist/chunk-DHFFRMF6.js.map +1 -0
  21. package/dist/chunk-FKU7VSUD.js +453 -0
  22. package/dist/chunk-FKU7VSUD.js.map +1 -0
  23. package/dist/chunk-J2Y4A3LP.js +478 -0
  24. package/dist/chunk-J2Y4A3LP.js.map +1 -0
  25. package/dist/chunk-JMQGWQZU.js +607 -0
  26. package/dist/chunk-JMQGWQZU.js.map +1 -0
  27. package/dist/chunk-JY4RO76L.js +73 -0
  28. package/dist/chunk-JY4RO76L.js.map +1 -0
  29. package/dist/chunk-M7YCPFIX.js +108 -0
  30. package/dist/chunk-M7YCPFIX.js.map +1 -0
  31. package/dist/chunk-MJSFR562.js +57 -0
  32. package/dist/chunk-MJSFR562.js.map +1 -0
  33. package/dist/chunk-MMDXNZPF.js +69 -0
  34. package/dist/chunk-MMDXNZPF.js.map +1 -0
  35. package/dist/chunk-MYAVQ23U.js +356 -0
  36. package/dist/chunk-MYAVQ23U.js.map +1 -0
  37. package/dist/chunk-OSQDDJXX.js +146 -0
  38. package/dist/chunk-OSQDDJXX.js.map +1 -0
  39. package/dist/chunk-QESUUPOE.js +241 -0
  40. package/dist/chunk-QESUUPOE.js.map +1 -0
  41. package/dist/chunk-SJYG4EJZ.js +57 -0
  42. package/dist/chunk-SJYG4EJZ.js.map +1 -0
  43. package/dist/chunk-SYQ7R2JO.js +95 -0
  44. package/dist/chunk-SYQ7R2JO.js.map +1 -0
  45. package/dist/chunk-TD643KB3.js +245 -0
  46. package/dist/chunk-TD643KB3.js.map +1 -0
  47. package/dist/chunk-TFV6Z7F7.js +129 -0
  48. package/dist/chunk-TFV6Z7F7.js.map +1 -0
  49. package/dist/chunk-TGOHJCQ4.js +83 -0
  50. package/dist/chunk-TGOHJCQ4.js.map +1 -0
  51. package/dist/chunk-TOPAIL5W.js +22 -0
  52. package/dist/chunk-TOPAIL5W.js.map +1 -0
  53. package/dist/chunk-U4VYHKPM.js +110 -0
  54. package/dist/chunk-U4VYHKPM.js.map +1 -0
  55. package/dist/chunk-UFWNMW3G.js +392 -0
  56. package/dist/chunk-UFWNMW3G.js.map +1 -0
  57. package/dist/chunk-UNHCZRO4.js +64 -0
  58. package/dist/chunk-UNHCZRO4.js.map +1 -0
  59. package/dist/chunk-URDV4OCP.js +308 -0
  60. package/dist/chunk-URDV4OCP.js.map +1 -0
  61. package/dist/chunk-YI6JVSFO.js +43 -0
  62. package/dist/chunk-YI6JVSFO.js.map +1 -0
  63. package/dist/chunk-YNSNRR5D.js +184 -0
  64. package/dist/chunk-YNSNRR5D.js.map +1 -0
  65. package/dist/chunk-Z6DLWTBY.js +46 -0
  66. package/dist/chunk-Z6DLWTBY.js.map +1 -0
  67. package/dist/chunk-ZDQIUHAM.js +89 -0
  68. package/dist/chunk-ZDQIUHAM.js.map +1 -0
  69. package/dist/chunk-ZSKHDU5P.js +124 -0
  70. package/dist/chunk-ZSKHDU5P.js.map +1 -0
  71. package/dist/cli-v2/defaults/agent-mappings.yaml +185 -0
  72. package/dist/commands/build/marketplace.js +295 -0
  73. package/dist/commands/build/marketplace.js.map +1 -0
  74. package/dist/commands/build/plugins.js +362 -0
  75. package/dist/commands/build/plugins.js.map +1 -0
  76. package/dist/commands/build/stack.js +169 -0
  77. package/dist/commands/build/stack.js.map +1 -0
  78. package/dist/commands/compile.js +461 -0
  79. package/dist/commands/compile.js.map +1 -0
  80. package/dist/commands/config/get.js +60 -0
  81. package/dist/commands/config/get.js.map +1 -0
  82. package/dist/commands/config/index.js +22 -0
  83. package/dist/commands/config/index.js.map +1 -0
  84. package/dist/commands/config/path.js +35 -0
  85. package/dist/commands/config/path.js.map +1 -0
  86. package/dist/commands/config/set-project.js +61 -0
  87. package/dist/commands/config/set-project.js.map +1 -0
  88. package/dist/commands/config/set.js +60 -0
  89. package/dist/commands/config/set.js.map +1 -0
  90. package/dist/commands/config/show.js +13 -0
  91. package/dist/commands/config/show.js.map +1 -0
  92. package/dist/commands/config/unset-project.js +57 -0
  93. package/dist/commands/config/unset-project.js.map +1 -0
  94. package/dist/commands/config/unset.js +56 -0
  95. package/dist/commands/config/unset.js.map +1 -0
  96. package/dist/commands/diff.js +755 -0
  97. package/dist/commands/diff.js.map +1 -0
  98. package/dist/commands/doctor.js +413 -0
  99. package/dist/commands/doctor.js.map +1 -0
  100. package/dist/commands/edit.js +253 -0
  101. package/dist/commands/edit.js.map +1 -0
  102. package/dist/commands/eject.js +208 -0
  103. package/dist/commands/eject.js.map +1 -0
  104. package/dist/commands/info.js +205 -0
  105. package/dist/commands/info.js.map +1 -0
  106. package/dist/commands/init.js +914 -0
  107. package/dist/commands/init.js.map +1 -0
  108. package/dist/commands/list.js +44 -0
  109. package/dist/commands/list.js.map +1 -0
  110. package/dist/commands/new/agent.js +230 -0
  111. package/dist/commands/new/agent.js.map +1 -0
  112. package/dist/commands/new/skill.js +204 -0
  113. package/dist/commands/new/skill.js.map +1 -0
  114. package/dist/commands/outdated.js +242 -0
  115. package/dist/commands/outdated.js.map +1 -0
  116. package/dist/commands/search.js +115 -0
  117. package/dist/commands/search.js.map +1 -0
  118. package/dist/commands/test-imports.js +92 -0
  119. package/dist/commands/test-imports.js.map +1 -0
  120. package/dist/commands/uninstall.js +302 -0
  121. package/dist/commands/uninstall.js.map +1 -0
  122. package/dist/commands/update.js +428 -0
  123. package/dist/commands/update.js.map +1 -0
  124. package/dist/commands/validate.js +375 -0
  125. package/dist/commands/validate.js.map +1 -0
  126. package/dist/commands/version/bump.js +95 -0
  127. package/dist/commands/version/bump.js.map +1 -0
  128. package/dist/commands/version/index.js +70 -0
  129. package/dist/commands/version/index.js.map +1 -0
  130. package/dist/commands/version/set.js +101 -0
  131. package/dist/commands/version/set.js.map +1 -0
  132. package/dist/commands/version/show.js +70 -0
  133. package/dist/commands/version/show.js.map +1 -0
  134. package/dist/components/common/confirm.js +9 -0
  135. package/dist/components/common/confirm.js.map +1 -0
  136. package/dist/components/common/message.js +24 -0
  137. package/dist/components/common/message.js.map +1 -0
  138. package/dist/components/common/spinner.js +14 -0
  139. package/dist/components/common/spinner.js.map +1 -0
  140. package/dist/components/wizard/selection-header.js +11 -0
  141. package/dist/components/wizard/selection-header.js.map +1 -0
  142. package/dist/components/wizard/step-approach.js +11 -0
  143. package/dist/components/wizard/step-approach.js.map +1 -0
  144. package/dist/components/wizard/step-category.js +12 -0
  145. package/dist/components/wizard/step-category.js.map +1 -0
  146. package/dist/components/wizard/step-confirm.js +12 -0
  147. package/dist/components/wizard/step-confirm.js.map +1 -0
  148. package/dist/components/wizard/step-stack.js +11 -0
  149. package/dist/components/wizard/step-stack.js.map +1 -0
  150. package/dist/components/wizard/step-subcategory.js +13 -0
  151. package/dist/components/wizard/step-subcategory.js.map +1 -0
  152. package/dist/components/wizard/wizard.js +19 -0
  153. package/dist/components/wizard/wizard.js.map +1 -0
  154. package/dist/hooks/init.js +41 -0
  155. package/dist/hooks/init.js.map +1 -0
  156. package/dist/index.js +10 -0
  157. package/dist/index.js.map +1 -0
  158. package/dist/magic-string.es-RGXYGAW3.js +1316 -0
  159. package/dist/magic-string.es-RGXYGAW3.js.map +1 -0
  160. package/dist/stores/wizard-store.js +10 -0
  161. package/dist/stores/wizard-store.js.map +1 -0
  162. package/dist/stores/wizard-store.test.js +15991 -0
  163. package/dist/stores/wizard-store.test.js.map +1 -0
  164. package/package.json +44 -25
  165. package/dist/cli/index.js +0 -6314
  166. package/dist/cli/index.js.map +0 -1
@@ -0,0 +1,295 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ DEFAULT_VERSION
4
+ } from "../../chunk-SJYG4EJZ.js";
5
+ import {
6
+ BaseCommand,
7
+ EXIT_CODES
8
+ } from "../../chunk-SYQ7R2JO.js";
9
+ import {
10
+ setVerbose,
11
+ verbose
12
+ } from "../../chunk-TOPAIL5W.js";
13
+ import {
14
+ ensureDir,
15
+ glob,
16
+ readFile,
17
+ writeFile
18
+ } from "../../chunk-MMDXNZPF.js";
19
+ import {
20
+ init_esm_shims
21
+ } from "../../chunk-DHET7RCE.js";
22
+
23
+ // src/cli-v2/commands/build/marketplace.ts
24
+ init_esm_shims();
25
+ import { Flags } from "@oclif/core";
26
+ import path2 from "path";
27
+
28
+ // src/cli-v2/lib/marketplace-generator.ts
29
+ init_esm_shims();
30
+ import path from "path";
31
+ var PLUGIN_MANIFEST_PATH = ".claude-plugin/plugin.json";
32
+ var MARKETPLACE_SCHEMA_URL = "https://anthropic.com/claude-code/marketplace.schema.json";
33
+ var CATEGORY_PATTERNS = [
34
+ { pattern: /^skill-setup-/, category: "setup" },
35
+ { pattern: /^skill-backend-/, category: "backend" },
36
+ { pattern: /^skill-frontend-/, category: "frontend" },
37
+ { pattern: /^skill-cli-/, category: "cli" },
38
+ // CLI-specific technologies
39
+ {
40
+ pattern: /^skill-(commander|clack|inquirer|ora|chalk|picocolors)/,
41
+ category: "cli"
42
+ },
43
+ // These patterns match common backend technologies
44
+ {
45
+ pattern: /^skill-(express|fastify|hono|drizzle|prisma)/,
46
+ category: "backend"
47
+ },
48
+ { pattern: /^skill-better-auth/, category: "backend" },
49
+ // Frontend frameworks and libraries
50
+ {
51
+ pattern: /^skill-(react|vue|angular|solid|next|nuxt|remix)/,
52
+ category: "frontend"
53
+ },
54
+ { pattern: /^skill-(tailwind|scss|cva|shadcn|radix)/, category: "frontend" },
55
+ {
56
+ pattern: /^skill-(framer-motion|css-animations|view-transitions)/,
57
+ category: "frontend"
58
+ },
59
+ {
60
+ pattern: /^skill-(zustand|mobx|redux|jotai|pinia|ngrx)/,
61
+ category: "frontend"
62
+ },
63
+ // Testing
64
+ {
65
+ pattern: /^skill-(vitest|cypress|playwright|jest|testing)/,
66
+ category: "testing"
67
+ },
68
+ { pattern: /^skill-(react-testing|vue-test|karma)/, category: "testing" },
69
+ // API/Data
70
+ {
71
+ pattern: /^skill-(react-query|swr|trpc|graphql|msw|mocks)/,
72
+ category: "api"
73
+ },
74
+ { pattern: /^skill-(websockets|socket-io|sse)/, category: "api" },
75
+ // Observability
76
+ { pattern: /^skill-(posthog|axiom|pino|sentry)/, category: "observability" },
77
+ // Mobile
78
+ { pattern: /^skill-(expo|react-native)/, category: "mobile" },
79
+ // DevOps/CI
80
+ { pattern: /^skill-github-actions/, category: "devops" },
81
+ // Tooling
82
+ { pattern: /^skill-(turborepo|storybook|tooling)/, category: "tooling" },
83
+ // Security
84
+ { pattern: /^skill-security/, category: "security" },
85
+ { pattern: /^skill-(react-hook-form|vee-validate|zod)/, category: "forms" },
86
+ { pattern: /^skill-(react-intl|next-intl|vue-i18n)/, category: "i18n" }
87
+ ];
88
+ function inferCategory(pluginName) {
89
+ for (const { pattern, category } of CATEGORY_PATTERNS) {
90
+ if (pattern.test(pluginName)) {
91
+ return category;
92
+ }
93
+ }
94
+ return void 0;
95
+ }
96
+ async function readPluginManifest(pluginDir) {
97
+ const manifestPath = path.join(pluginDir, PLUGIN_MANIFEST_PATH);
98
+ try {
99
+ const content = await readFile(manifestPath);
100
+ return JSON.parse(content);
101
+ } catch {
102
+ return null;
103
+ }
104
+ }
105
+ function toMarketplacePlugin(manifest, pluginRoot, pluginDirName) {
106
+ const category = inferCategory(manifest.name);
107
+ const plugin = {
108
+ name: manifest.name,
109
+ source: `./${pluginRoot}/${pluginDirName}`,
110
+ description: manifest.description,
111
+ version: manifest.version,
112
+ author: manifest.author,
113
+ keywords: manifest.keywords
114
+ };
115
+ if (category) {
116
+ plugin.category = category;
117
+ }
118
+ return plugin;
119
+ }
120
+ async function generateMarketplace(pluginsDir, options) {
121
+ verbose(`Scanning plugins directory: ${pluginsDir}`);
122
+ const manifestFiles = await glob(`**/${PLUGIN_MANIFEST_PATH}`, pluginsDir);
123
+ verbose(`Found ${manifestFiles.length} plugin manifests`);
124
+ const plugins = [];
125
+ for (const manifestFile of manifestFiles) {
126
+ const pluginDirName = manifestFile.split("/")[0];
127
+ const pluginDir = path.join(pluginsDir, pluginDirName);
128
+ const manifest = await readPluginManifest(pluginDir);
129
+ if (!manifest) {
130
+ verbose(` [WARN] Could not read manifest: ${manifestFile}`);
131
+ continue;
132
+ }
133
+ const plugin = toMarketplacePlugin(
134
+ manifest,
135
+ options.pluginRoot.replace(/^\.\//, ""),
136
+ pluginDirName
137
+ );
138
+ plugins.push(plugin);
139
+ verbose(` [OK] ${plugin.name}`);
140
+ }
141
+ plugins.sort((a, b) => a.name.localeCompare(b.name));
142
+ const marketplace = {
143
+ $schema: MARKETPLACE_SCHEMA_URL,
144
+ name: options.name,
145
+ version: options.version ?? "1.0.0",
146
+ owner: {
147
+ name: options.ownerName
148
+ },
149
+ metadata: {
150
+ pluginRoot: options.pluginRoot
151
+ },
152
+ plugins
153
+ };
154
+ if (options.description) {
155
+ marketplace.description = options.description;
156
+ }
157
+ if (options.ownerEmail) {
158
+ marketplace.owner.email = options.ownerEmail;
159
+ }
160
+ return marketplace;
161
+ }
162
+ async function writeMarketplace(outputPath, marketplace) {
163
+ await ensureDir(path.dirname(outputPath));
164
+ const content = JSON.stringify(marketplace, null, 2) + "\n";
165
+ await writeFile(outputPath, content);
166
+ }
167
+ function getMarketplaceStats(marketplace) {
168
+ const byCategory = {};
169
+ for (const plugin of marketplace.plugins) {
170
+ const category = plugin.category ?? "uncategorized";
171
+ byCategory[category] = (byCategory[category] ?? 0) + 1;
172
+ }
173
+ return {
174
+ total: marketplace.plugins.length,
175
+ byCategory
176
+ };
177
+ }
178
+
179
+ // src/cli-v2/commands/build/marketplace.ts
180
+ var DEFAULT_PLUGINS_DIR = "dist/plugins";
181
+ var DEFAULT_OUTPUT_FILE = ".claude-plugin/marketplace.json";
182
+ var DEFAULT_NAME = "claude-collective";
183
+ var DEFAULT_DESCRIPTION = "Community skills and stacks for Claude Code";
184
+ var DEFAULT_OWNER_NAME = "Claude Collective";
185
+ var DEFAULT_OWNER_EMAIL = "hello@claude-collective.com";
186
+ var BuildMarketplace = class _BuildMarketplace extends BaseCommand {
187
+ static summary = "Generate marketplace.json from built plugins (requires skills repo)";
188
+ static description = "Generate marketplace.json from built plugins. This command scans the plugins directory and generates a marketplace manifest file.";
189
+ static examples = [
190
+ "<%= config.bin %> <%= command.id %>",
191
+ "<%= config.bin %> <%= command.id %> --plugins-dir dist/stacks",
192
+ "<%= config.bin %> <%= command.id %> --output .claude-plugin/market.json",
193
+ "<%= config.bin %> <%= command.id %> --name my-marketplace --version 2.0.0"
194
+ ];
195
+ static flags = {
196
+ ...BaseCommand.baseFlags,
197
+ "plugins-dir": Flags.string({
198
+ char: "p",
199
+ description: "Plugins directory",
200
+ default: DEFAULT_PLUGINS_DIR
201
+ }),
202
+ output: Flags.string({
203
+ char: "o",
204
+ description: "Output file",
205
+ default: DEFAULT_OUTPUT_FILE
206
+ }),
207
+ name: Flags.string({
208
+ description: "Marketplace name",
209
+ default: DEFAULT_NAME
210
+ }),
211
+ version: Flags.string({
212
+ description: "Marketplace version",
213
+ default: DEFAULT_VERSION
214
+ }),
215
+ description: Flags.string({
216
+ description: "Marketplace description",
217
+ default: DEFAULT_DESCRIPTION
218
+ }),
219
+ "owner-name": Flags.string({
220
+ description: "Owner name",
221
+ default: DEFAULT_OWNER_NAME
222
+ }),
223
+ "owner-email": Flags.string({
224
+ description: "Owner email",
225
+ default: DEFAULT_OWNER_EMAIL
226
+ }),
227
+ verbose: Flags.boolean({
228
+ char: "v",
229
+ description: "Enable verbose logging",
230
+ default: false
231
+ })
232
+ };
233
+ async run() {
234
+ const { flags } = await this.parse(_BuildMarketplace);
235
+ setVerbose(flags.verbose);
236
+ const projectRoot = process.cwd();
237
+ const pluginsDir = path2.resolve(projectRoot, flags["plugins-dir"]);
238
+ const outputPath = path2.resolve(projectRoot, flags.output);
239
+ this.log("");
240
+ this.log("Generating marketplace.json");
241
+ this.log(` Plugins directory: ${pluginsDir}`);
242
+ this.log(` Output file: ${outputPath}`);
243
+ this.log("");
244
+ try {
245
+ this.log("Scanning plugins...");
246
+ const marketplace = await generateMarketplace(pluginsDir, {
247
+ name: flags.name,
248
+ version: flags.version,
249
+ description: flags.description,
250
+ ownerName: flags["owner-name"],
251
+ ownerEmail: flags["owner-email"],
252
+ pluginRoot: `./${flags["plugins-dir"]}`
253
+ });
254
+ const stats = getMarketplaceStats(marketplace);
255
+ this.log(`Found ${stats.total} plugins`);
256
+ this.log("");
257
+ this.log("Category breakdown:");
258
+ const sortedCategories = Object.entries(stats.byCategory).sort(
259
+ ([, a], [, b]) => b - a
260
+ );
261
+ for (const [category, count] of sortedCategories) {
262
+ this.log(` ${category}: ${count}`);
263
+ }
264
+ this.log("Writing marketplace.json...");
265
+ await writeMarketplace(outputPath, marketplace);
266
+ this.log(`Wrote ${outputPath}`);
267
+ this.log("");
268
+ this.log("Sample plugins:");
269
+ const sampleSize = 5;
270
+ for (const plugin of marketplace.plugins.slice(0, sampleSize)) {
271
+ const version = plugin.version ? `v${plugin.version}` : "";
272
+ const category = plugin.category ? `[${plugin.category}]` : "";
273
+ this.log(` ${plugin.name} ${version} ${category}`);
274
+ if (plugin.description) {
275
+ this.log(` ${plugin.description}`);
276
+ }
277
+ }
278
+ if (marketplace.plugins.length > sampleSize) {
279
+ this.log(` ... and ${marketplace.plugins.length - sampleSize} more`);
280
+ }
281
+ this.log("");
282
+ this.logSuccess(`Marketplace generated with ${stats.total} plugins!`);
283
+ this.log("");
284
+ } catch (error) {
285
+ this.log("Generation failed");
286
+ this.error(error instanceof Error ? error.message : String(error), {
287
+ exit: EXIT_CODES.ERROR
288
+ });
289
+ }
290
+ }
291
+ };
292
+ export {
293
+ BuildMarketplace as default
294
+ };
295
+ //# sourceMappingURL=marketplace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/cli-v2/commands/build/marketplace.ts","../../../src/cli-v2/lib/marketplace-generator.ts"],"sourcesContent":["import { Flags } from \"@oclif/core\";\nimport path from \"path\";\nimport { BaseCommand } from \"../../base-command\";\nimport { setVerbose } from \"../../utils/logger\";\nimport {\n generateMarketplace,\n writeMarketplace,\n getMarketplaceStats,\n} from \"../../lib/marketplace-generator\";\nimport { EXIT_CODES } from \"../../lib/exit-codes\";\nimport { DEFAULT_VERSION } from \"../../consts\";\n\nconst DEFAULT_PLUGINS_DIR = \"dist/plugins\";\nconst DEFAULT_OUTPUT_FILE = \".claude-plugin/marketplace.json\";\nconst DEFAULT_NAME = \"claude-collective\";\nconst DEFAULT_DESCRIPTION = \"Community skills and stacks for Claude Code\";\nconst DEFAULT_OWNER_NAME = \"Claude Collective\";\nconst DEFAULT_OWNER_EMAIL = \"hello@claude-collective.com\";\n\nexport default class BuildMarketplace extends BaseCommand {\n static summary =\n \"Generate marketplace.json from built plugins (requires skills repo)\";\n\n static description =\n \"Generate marketplace.json from built plugins. This command scans the plugins directory and generates a marketplace manifest file.\";\n\n static examples = [\n \"<%= config.bin %> <%= command.id %>\",\n \"<%= config.bin %> <%= command.id %> --plugins-dir dist/stacks\",\n \"<%= config.bin %> <%= command.id %> --output .claude-plugin/market.json\",\n \"<%= config.bin %> <%= command.id %> --name my-marketplace --version 2.0.0\",\n ];\n\n static flags = {\n ...BaseCommand.baseFlags,\n \"plugins-dir\": Flags.string({\n char: \"p\",\n description: \"Plugins directory\",\n default: DEFAULT_PLUGINS_DIR,\n }),\n output: Flags.string({\n char: \"o\",\n description: \"Output file\",\n default: DEFAULT_OUTPUT_FILE,\n }),\n name: Flags.string({\n description: \"Marketplace name\",\n default: DEFAULT_NAME,\n }),\n version: Flags.string({\n description: \"Marketplace version\",\n default: DEFAULT_VERSION,\n }),\n description: Flags.string({\n description: \"Marketplace description\",\n default: DEFAULT_DESCRIPTION,\n }),\n \"owner-name\": Flags.string({\n description: \"Owner name\",\n default: DEFAULT_OWNER_NAME,\n }),\n \"owner-email\": Flags.string({\n description: \"Owner email\",\n default: DEFAULT_OWNER_EMAIL,\n }),\n verbose: Flags.boolean({\n char: \"v\",\n description: \"Enable verbose logging\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(BuildMarketplace);\n\n setVerbose(flags.verbose);\n\n const projectRoot = process.cwd();\n const pluginsDir = path.resolve(projectRoot, flags[\"plugins-dir\"]);\n const outputPath = path.resolve(projectRoot, flags.output);\n\n this.log(\"\");\n this.log(\"Generating marketplace.json\");\n this.log(` Plugins directory: ${pluginsDir}`);\n this.log(` Output file: ${outputPath}`);\n this.log(\"\");\n\n try {\n this.log(\"Scanning plugins...\");\n\n const marketplace = await generateMarketplace(pluginsDir, {\n name: flags.name,\n version: flags.version,\n description: flags.description,\n ownerName: flags[\"owner-name\"],\n ownerEmail: flags[\"owner-email\"],\n pluginRoot: `./${flags[\"plugins-dir\"]}`,\n });\n\n const stats = getMarketplaceStats(marketplace);\n this.log(`Found ${stats.total} plugins`);\n\n this.log(\"\");\n this.log(\"Category breakdown:\");\n const sortedCategories = Object.entries(stats.byCategory).sort(\n ([, a], [, b]) => b - a,\n );\n for (const [category, count] of sortedCategories) {\n this.log(` ${category}: ${count}`);\n }\n\n this.log(\"Writing marketplace.json...\");\n await writeMarketplace(outputPath, marketplace);\n this.log(`Wrote ${outputPath}`);\n\n this.log(\"\");\n this.log(\"Sample plugins:\");\n const sampleSize = 5;\n for (const plugin of marketplace.plugins.slice(0, sampleSize)) {\n const version = plugin.version ? `v${plugin.version}` : \"\";\n const category = plugin.category ? `[${plugin.category}]` : \"\";\n this.log(` ${plugin.name} ${version} ${category}`);\n if (plugin.description) {\n this.log(` ${plugin.description}`);\n }\n }\n if (marketplace.plugins.length > sampleSize) {\n this.log(` ... and ${marketplace.plugins.length - sampleSize} more`);\n }\n\n this.log(\"\");\n this.logSuccess(`Marketplace generated with ${stats.total} plugins!`);\n this.log(\"\");\n } catch (error) {\n this.log(\"Generation failed\");\n this.error(error instanceof Error ? error.message : String(error), {\n exit: EXIT_CODES.ERROR,\n });\n }\n }\n}\n","import path from \"path\";\nimport { readFile, writeFile, glob, ensureDir } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport type {\n Marketplace,\n MarketplacePlugin,\n PluginManifest,\n} from \"../../types\";\n\nconst PLUGIN_MANIFEST_PATH = \".claude-plugin/plugin.json\";\nconst MARKETPLACE_SCHEMA_URL =\n \"https://anthropic.com/claude-code/marketplace.schema.json\";\n\nconst CATEGORY_PATTERNS: Array<{ pattern: RegExp; category: string }> = [\n { pattern: /^skill-setup-/, category: \"setup\" },\n { pattern: /^skill-backend-/, category: \"backend\" },\n { pattern: /^skill-frontend-/, category: \"frontend\" },\n { pattern: /^skill-cli-/, category: \"cli\" },\n // CLI-specific technologies\n {\n pattern: /^skill-(commander|clack|inquirer|ora|chalk|picocolors)/,\n category: \"cli\",\n },\n // These patterns match common backend technologies\n {\n pattern: /^skill-(express|fastify|hono|drizzle|prisma)/,\n category: \"backend\",\n },\n { pattern: /^skill-better-auth/, category: \"backend\" },\n // Frontend frameworks and libraries\n {\n pattern: /^skill-(react|vue|angular|solid|next|nuxt|remix)/,\n category: \"frontend\",\n },\n { pattern: /^skill-(tailwind|scss|cva|shadcn|radix)/, category: \"frontend\" },\n {\n pattern: /^skill-(framer-motion|css-animations|view-transitions)/,\n category: \"frontend\",\n },\n {\n pattern: /^skill-(zustand|mobx|redux|jotai|pinia|ngrx)/,\n category: \"frontend\",\n },\n // Testing\n {\n pattern: /^skill-(vitest|cypress|playwright|jest|testing)/,\n category: \"testing\",\n },\n { pattern: /^skill-(react-testing|vue-test|karma)/, category: \"testing\" },\n // API/Data\n {\n pattern: /^skill-(react-query|swr|trpc|graphql|msw|mocks)/,\n category: \"api\",\n },\n { pattern: /^skill-(websockets|socket-io|sse)/, category: \"api\" },\n // Observability\n { pattern: /^skill-(posthog|axiom|pino|sentry)/, category: \"observability\" },\n // Mobile\n { pattern: /^skill-(expo|react-native)/, category: \"mobile\" },\n // DevOps/CI\n { pattern: /^skill-github-actions/, category: \"devops\" },\n // Tooling\n { pattern: /^skill-(turborepo|storybook|tooling)/, category: \"tooling\" },\n // Security\n { pattern: /^skill-security/, category: \"security\" },\n { pattern: /^skill-(react-hook-form|vee-validate|zod)/, category: \"forms\" },\n { pattern: /^skill-(react-intl|next-intl|vue-i18n)/, category: \"i18n\" },\n];\n\nexport interface MarketplaceOptions {\n name: string;\n version?: string;\n description?: string;\n ownerName: string;\n ownerEmail?: string;\n pluginRoot: string;\n}\n\nfunction inferCategory(pluginName: string): string | undefined {\n for (const { pattern, category } of CATEGORY_PATTERNS) {\n if (pattern.test(pluginName)) {\n return category;\n }\n }\n return undefined;\n}\n\nasync function readPluginManifest(\n pluginDir: string,\n): Promise<PluginManifest | null> {\n const manifestPath = path.join(pluginDir, PLUGIN_MANIFEST_PATH);\n\n try {\n const content = await readFile(manifestPath);\n return JSON.parse(content) as PluginManifest;\n } catch {\n return null;\n }\n}\n\nfunction toMarketplacePlugin(\n manifest: PluginManifest,\n pluginRoot: string,\n pluginDirName: string,\n): MarketplacePlugin {\n const category = inferCategory(manifest.name);\n\n const plugin: MarketplacePlugin = {\n name: manifest.name,\n source: `./${pluginRoot}/${pluginDirName}`,\n description: manifest.description,\n version: manifest.version,\n author: manifest.author,\n keywords: manifest.keywords,\n };\n\n if (category) {\n plugin.category = category;\n }\n\n return plugin;\n}\n\nexport async function generateMarketplace(\n pluginsDir: string,\n options: MarketplaceOptions,\n): Promise<Marketplace> {\n verbose(`Scanning plugins directory: ${pluginsDir}`);\n\n const manifestFiles = await glob(`**/${PLUGIN_MANIFEST_PATH}`, pluginsDir);\n verbose(`Found ${manifestFiles.length} plugin manifests`);\n\n const plugins: MarketplacePlugin[] = [];\n\n for (const manifestFile of manifestFiles) {\n const pluginDirName = manifestFile.split(\"/\")[0];\n const pluginDir = path.join(pluginsDir, pluginDirName);\n\n const manifest = await readPluginManifest(pluginDir);\n if (!manifest) {\n verbose(` [WARN] Could not read manifest: ${manifestFile}`);\n continue;\n }\n\n const plugin = toMarketplacePlugin(\n manifest,\n options.pluginRoot.replace(/^\\.\\//, \"\"),\n pluginDirName,\n );\n plugins.push(plugin);\n verbose(` [OK] ${plugin.name}`);\n }\n\n plugins.sort((a, b) => a.name.localeCompare(b.name));\n\n const marketplace: Marketplace = {\n $schema: MARKETPLACE_SCHEMA_URL,\n name: options.name,\n version: options.version ?? \"1.0.0\",\n owner: {\n name: options.ownerName,\n },\n metadata: {\n pluginRoot: options.pluginRoot,\n },\n plugins,\n };\n\n if (options.description) {\n marketplace.description = options.description;\n }\n\n if (options.ownerEmail) {\n marketplace.owner.email = options.ownerEmail;\n }\n\n return marketplace;\n}\n\nexport async function writeMarketplace(\n outputPath: string,\n marketplace: Marketplace,\n): Promise<void> {\n await ensureDir(path.dirname(outputPath));\n const content = JSON.stringify(marketplace, null, 2) + \"\\n\";\n await writeFile(outputPath, content);\n}\n\nexport function getMarketplaceStats(marketplace: Marketplace): {\n total: number;\n byCategory: Record<string, number>;\n} {\n const byCategory: Record<string, number> = {};\n\n for (const plugin of marketplace.plugins) {\n const category = plugin.category ?? \"uncategorized\";\n byCategory[category] = (byCategory[category] ?? 0) + 1;\n }\n\n return {\n total: marketplace.plugins.length,\n byCategory,\n };\n}\n"],"mappings":"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","names":["path","path"]}
@@ -0,0 +1,362 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ generateSkillPluginManifest,
4
+ getPluginManifestPath,
5
+ writePluginManifest
6
+ } from "../../chunk-AU7XVCLO.js";
7
+ import {
8
+ hashSkillFolder
9
+ } from "../../chunk-MJSFR562.js";
10
+ import {
11
+ DEFAULT_VERSION,
12
+ DIRS
13
+ } from "../../chunk-SJYG4EJZ.js";
14
+ import {
15
+ BaseCommand,
16
+ EXIT_CODES
17
+ } from "../../chunk-SYQ7R2JO.js";
18
+ import {
19
+ setVerbose,
20
+ verbose
21
+ } from "../../chunk-TOPAIL5W.js";
22
+ import {
23
+ copy,
24
+ ensureDir,
25
+ fileExists,
26
+ glob,
27
+ readFile,
28
+ writeFile
29
+ } from "../../chunk-MMDXNZPF.js";
30
+ import {
31
+ init_esm_shims
32
+ } from "../../chunk-DHET7RCE.js";
33
+
34
+ // src/cli-v2/commands/build/plugins.ts
35
+ init_esm_shims();
36
+ import { Flags } from "@oclif/core";
37
+ import path2 from "path";
38
+
39
+ // src/cli-v2/lib/skill-plugin-compiler.ts
40
+ init_esm_shims();
41
+ import path from "path";
42
+ import { parse as parseYaml } from "yaml";
43
+ var FRONTMATTER_REGEX = /^---\n([\s\S]*?)\n---/;
44
+ var SKILL_FILES = ["SKILL.md", "reference.md"];
45
+ var SKILL_DIRS = ["examples", "scripts"];
46
+ function parseFrontmatter(content) {
47
+ const match = content.match(FRONTMATTER_REGEX);
48
+ if (!match) return null;
49
+ const yamlContent = match[1];
50
+ const frontmatter = parseYaml(yamlContent);
51
+ if (!frontmatter.name || !frontmatter.description) return null;
52
+ return frontmatter;
53
+ }
54
+ function sanitizeSkillName(name) {
55
+ return name.replace(/\+/g, "-");
56
+ }
57
+ function parseMajorVersion(version) {
58
+ const match = version.match(/^(\d+)\./);
59
+ return match ? parseInt(match[1], 10) : 1;
60
+ }
61
+ function bumpMajorVersion(version) {
62
+ const major = parseMajorVersion(version);
63
+ return `${major + 1}.0.0`;
64
+ }
65
+ var CONTENT_HASH_FILE = ".content-hash";
66
+ async function readExistingManifest(pluginDir) {
67
+ const manifestPath = getPluginManifestPath(pluginDir);
68
+ if (!await fileExists(manifestPath)) {
69
+ return null;
70
+ }
71
+ try {
72
+ const content = await readFile(manifestPath);
73
+ const manifest = JSON.parse(content);
74
+ const hashFilePath = manifestPath.replace("plugin.json", CONTENT_HASH_FILE);
75
+ let contentHash;
76
+ if (await fileExists(hashFilePath)) {
77
+ contentHash = (await readFile(hashFilePath)).trim();
78
+ }
79
+ return {
80
+ version: manifest.version ?? DEFAULT_VERSION,
81
+ contentHash
82
+ };
83
+ } catch {
84
+ return null;
85
+ }
86
+ }
87
+ async function determineVersion(skillPath, pluginDir) {
88
+ const newHash = await hashSkillFolder(skillPath);
89
+ const existing = await readExistingManifest(pluginDir);
90
+ if (!existing) {
91
+ return {
92
+ version: DEFAULT_VERSION,
93
+ contentHash: newHash
94
+ };
95
+ }
96
+ if (existing.contentHash !== newHash) {
97
+ return {
98
+ version: bumpMajorVersion(existing.version),
99
+ contentHash: newHash
100
+ };
101
+ }
102
+ return {
103
+ version: existing.version,
104
+ contentHash: newHash
105
+ };
106
+ }
107
+ function extractSkillName(skillPath) {
108
+ const dirName = path.basename(skillPath);
109
+ const withoutAuthor = dirName.replace(/\s*\(@\w+\)$/, "").trim();
110
+ return sanitizeSkillName(withoutAuthor);
111
+ }
112
+ function extractCategory(skillPath, skillsRoot) {
113
+ const relativePath = path.relative(skillsRoot, skillPath);
114
+ const parts = relativePath.split(path.sep);
115
+ return parts.length > 1 ? parts[0] : void 0;
116
+ }
117
+ function extractAuthor(skillPath) {
118
+ const dirName = path.basename(skillPath);
119
+ const match = dirName.match(/\(@(\w+)\)$/);
120
+ return match ? match[1] : void 0;
121
+ }
122
+ async function readSkillMetadata(skillPath) {
123
+ const metadataPath = path.join(skillPath, "metadata.yaml");
124
+ if (!await fileExists(metadataPath)) {
125
+ return null;
126
+ }
127
+ try {
128
+ const content = await readFile(metadataPath);
129
+ const lines = content.split("\n");
130
+ const yamlContent = lines[0]?.startsWith("# yaml-language-server:") ? lines.slice(1).join("\n") : content;
131
+ return parseYaml(yamlContent);
132
+ } catch {
133
+ return null;
134
+ }
135
+ }
136
+ function generateReadme(skillName, frontmatter, metadata) {
137
+ const lines = [];
138
+ lines.push(`# ${skillName}`);
139
+ lines.push("");
140
+ lines.push(frontmatter.description);
141
+ lines.push("");
142
+ if (metadata?.tags && metadata.tags.length > 0) {
143
+ lines.push("## Tags");
144
+ lines.push("");
145
+ lines.push(metadata.tags.map((t) => `\`${t}\``).join(" "));
146
+ lines.push("");
147
+ }
148
+ lines.push("## Installation");
149
+ lines.push("");
150
+ lines.push("Add this plugin to your Claude Code configuration:");
151
+ lines.push("");
152
+ lines.push("```json");
153
+ lines.push(`{`);
154
+ lines.push(` "plugins": ["skill-${skillName}"]`);
155
+ lines.push(`}`);
156
+ lines.push("```");
157
+ lines.push("");
158
+ lines.push("## Usage");
159
+ lines.push("");
160
+ lines.push(`This skill is automatically available when installed.`);
161
+ if (metadata?.requires && metadata.requires.length > 0) {
162
+ lines.push("");
163
+ lines.push("**Requires:** " + metadata.requires.join(", "));
164
+ }
165
+ lines.push("");
166
+ lines.push("---");
167
+ lines.push("");
168
+ lines.push("*Generated by Claude Collective skill-plugin-compiler*");
169
+ lines.push("");
170
+ return lines.join("\n");
171
+ }
172
+ async function compileSkillPlugin(options) {
173
+ const { skillPath, outputDir, skillName: overrideName } = options;
174
+ const skillName = overrideName ?? extractSkillName(skillPath);
175
+ const author = extractAuthor(skillPath);
176
+ verbose(`Compiling skill plugin: ${skillName} from ${skillPath}`);
177
+ const skillMdPath = path.join(skillPath, "SKILL.md");
178
+ if (!await fileExists(skillMdPath)) {
179
+ throw new Error(
180
+ `Skill '${skillName}' is missing required SKILL.md file. Expected at: ${skillMdPath}`
181
+ );
182
+ }
183
+ const skillMdContent = await readFile(skillMdPath);
184
+ const frontmatter = parseFrontmatter(skillMdContent);
185
+ if (!frontmatter) {
186
+ throw new Error(
187
+ `Skill '${skillName}' has invalid or missing YAML frontmatter in SKILL.md. Required fields: 'name' and 'description'. File: ${skillMdPath}`
188
+ );
189
+ }
190
+ const metadata = await readSkillMetadata(skillPath);
191
+ const pluginDir = path.join(outputDir, `skill-${skillName}`);
192
+ const skillsDir = path.join(pluginDir, "skills", skillName);
193
+ await ensureDir(pluginDir);
194
+ await ensureDir(skillsDir);
195
+ const { version, contentHash } = await determineVersion(skillPath, pluginDir);
196
+ const manifest = generateSkillPluginManifest({
197
+ skillName,
198
+ description: frontmatter.description,
199
+ author: author ? `@${author}` : metadata?.author,
200
+ version,
201
+ keywords: metadata?.tags
202
+ });
203
+ await writePluginManifest(pluginDir, manifest);
204
+ const hashFilePath = getPluginManifestPath(pluginDir).replace(
205
+ "plugin.json",
206
+ CONTENT_HASH_FILE
207
+ );
208
+ await writeFile(hashFilePath, contentHash);
209
+ verbose(` Wrote plugin.json for ${skillName} (v${version})`);
210
+ await writeFile(path.join(skillsDir, "SKILL.md"), skillMdContent);
211
+ verbose(` Copied SKILL.md`);
212
+ for (const fileName of SKILL_FILES) {
213
+ if (fileName === "SKILL.md") continue;
214
+ const sourcePath = path.join(skillPath, fileName);
215
+ if (await fileExists(sourcePath)) {
216
+ const content = await readFile(sourcePath);
217
+ await writeFile(path.join(skillsDir, fileName), content);
218
+ verbose(` Copied ${fileName}`);
219
+ }
220
+ }
221
+ for (const dirName of SKILL_DIRS) {
222
+ const sourceDir = path.join(skillPath, dirName);
223
+ if (await fileExists(sourceDir)) {
224
+ await copy(sourceDir, path.join(skillsDir, dirName));
225
+ verbose(` Copied ${dirName}/`);
226
+ }
227
+ }
228
+ const readme = generateReadme(skillName, frontmatter, metadata);
229
+ await writeFile(path.join(pluginDir, "README.md"), readme);
230
+ verbose(` Generated README.md`);
231
+ return {
232
+ pluginPath: pluginDir,
233
+ manifest,
234
+ skillName
235
+ };
236
+ }
237
+ async function compileAllSkillPlugins(skillsDir, outputDir) {
238
+ const results = [];
239
+ const skillMdFiles = await glob("**/SKILL.md", skillsDir);
240
+ const skillNameMap = /* @__PURE__ */ new Map();
241
+ for (const skillMdFile of skillMdFiles) {
242
+ const skillPath = path.join(skillsDir, path.dirname(skillMdFile));
243
+ const baseName = extractSkillName(skillPath);
244
+ const existing = skillNameMap.get(baseName) ?? [];
245
+ existing.push(skillPath);
246
+ skillNameMap.set(baseName, existing);
247
+ }
248
+ const collidingNames = /* @__PURE__ */ new Set();
249
+ for (const [name, paths] of skillNameMap.entries()) {
250
+ if (paths.length > 1) {
251
+ collidingNames.add(name);
252
+ verbose(`Name collision detected for "${name}": ${paths.length} skills`);
253
+ }
254
+ }
255
+ for (const skillMdFile of skillMdFiles) {
256
+ const skillPath = path.join(skillsDir, path.dirname(skillMdFile));
257
+ const baseName = extractSkillName(skillPath);
258
+ let skillName = baseName;
259
+ if (collidingNames.has(baseName)) {
260
+ const category = extractCategory(skillPath, skillsDir);
261
+ if (category) {
262
+ skillName = `${category}-${baseName}`;
263
+ }
264
+ }
265
+ try {
266
+ const result = await compileSkillPlugin({
267
+ skillPath,
268
+ outputDir,
269
+ skillName
270
+ });
271
+ results.push(result);
272
+ console.log(` [OK] skill-${result.skillName}`);
273
+ } catch (error) {
274
+ const errorMessage = error instanceof Error ? error.message : String(error);
275
+ console.warn(
276
+ ` [WARN] Failed to compile skill 'skill-${skillName}' from ${skillPath}: ${errorMessage}`
277
+ );
278
+ }
279
+ }
280
+ return results;
281
+ }
282
+ function printCompilationSummary(results) {
283
+ console.log(`
284
+ Compiled ${results.length} skill plugins:`);
285
+ for (const result of results) {
286
+ console.log(` - skill-${result.skillName} (v${result.manifest.version})`);
287
+ }
288
+ }
289
+
290
+ // src/cli-v2/commands/build/plugins.ts
291
+ var DEFAULT_OUTPUT_DIR = "dist/plugins";
292
+ var BuildPlugins = class _BuildPlugins extends BaseCommand {
293
+ static summary = "Build skills into standalone plugins (requires skills repo)";
294
+ static description = "Build skills into standalone plugins. By default, compiles all skills. Use --skill to compile a specific skill only.";
295
+ static examples = [
296
+ "<%= config.bin %> <%= command.id %>",
297
+ "<%= config.bin %> <%= command.id %> --skill cli-commander",
298
+ "<%= config.bin %> <%= command.id %> --skills-dir ./src/skills --output-dir ./plugins",
299
+ "<%= config.bin %> <%= command.id %> --verbose"
300
+ ];
301
+ static flags = {
302
+ ...BaseCommand.baseFlags,
303
+ "skills-dir": Flags.string({
304
+ char: "s",
305
+ description: "Skills source directory",
306
+ default: DIRS.skills
307
+ }),
308
+ "output-dir": Flags.string({
309
+ char: "o",
310
+ description: "Output directory",
311
+ default: DEFAULT_OUTPUT_DIR
312
+ }),
313
+ skill: Flags.string({
314
+ description: "Compile only a specific skill (path to skill directory)"
315
+ }),
316
+ verbose: Flags.boolean({
317
+ char: "v",
318
+ description: "Enable verbose logging",
319
+ default: false
320
+ })
321
+ };
322
+ async run() {
323
+ const { flags } = await this.parse(_BuildPlugins);
324
+ setVerbose(flags.verbose);
325
+ const projectRoot = process.cwd();
326
+ const skillsDir = path2.resolve(projectRoot, flags["skills-dir"]);
327
+ const outputDir = path2.resolve(projectRoot, flags["output-dir"]);
328
+ this.log("");
329
+ this.log("Compiling skill plugins");
330
+ this.log(` Skills directory: ${skillsDir}`);
331
+ this.log(` Output directory: ${outputDir}`);
332
+ this.log("");
333
+ try {
334
+ if (flags.skill) {
335
+ const skillPath = path2.resolve(skillsDir, flags.skill);
336
+ this.log(`Compiling skill at ${skillPath}...`);
337
+ const result = await compileSkillPlugin({
338
+ skillPath,
339
+ outputDir
340
+ });
341
+ this.log(`Compiled skill-${result.skillName}`);
342
+ this.log(` Plugin path: ${result.pluginPath}`);
343
+ } else {
344
+ this.log("Finding and compiling all skills...");
345
+ const results = await compileAllSkillPlugins(skillsDir, outputDir);
346
+ this.log(`Compiled ${results.length} skill plugins`);
347
+ printCompilationSummary(results);
348
+ }
349
+ this.log("");
350
+ this.logSuccess("Plugin compilation complete!");
351
+ } catch (error) {
352
+ this.log("Compilation failed");
353
+ this.error(error instanceof Error ? error.message : String(error), {
354
+ exit: EXIT_CODES.ERROR
355
+ });
356
+ }
357
+ }
358
+ };
359
+ export {
360
+ BuildPlugins as default
361
+ };
362
+ //# sourceMappingURL=plugins.js.map