prpm 0.2.0 → 1.0.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 (48) hide show
  1. package/dist/index.js +14257 -109
  2. package/package.json +11 -9
  3. package/dist/__tests__/e2e/test-helpers.js +0 -153
  4. package/dist/commands/buy-credits.js +0 -224
  5. package/dist/commands/catalog.js +0 -365
  6. package/dist/commands/collections.js +0 -655
  7. package/dist/commands/config.js +0 -161
  8. package/dist/commands/credits.js +0 -186
  9. package/dist/commands/index.js +0 -184
  10. package/dist/commands/info.js +0 -78
  11. package/dist/commands/init.js +0 -684
  12. package/dist/commands/install.js +0 -829
  13. package/dist/commands/list.js +0 -198
  14. package/dist/commands/login.js +0 -316
  15. package/dist/commands/outdated.js +0 -130
  16. package/dist/commands/playground.js +0 -637
  17. package/dist/commands/popular.js +0 -33
  18. package/dist/commands/publish.js +0 -803
  19. package/dist/commands/schema.js +0 -41
  20. package/dist/commands/search.js +0 -446
  21. package/dist/commands/starred.js +0 -147
  22. package/dist/commands/subscribe.js +0 -211
  23. package/dist/commands/telemetry.js +0 -104
  24. package/dist/commands/trending.js +0 -86
  25. package/dist/commands/uninstall.js +0 -120
  26. package/dist/commands/update.js +0 -121
  27. package/dist/commands/upgrade.js +0 -121
  28. package/dist/commands/whoami.js +0 -83
  29. package/dist/core/claude-config.js +0 -91
  30. package/dist/core/cursor-config.js +0 -130
  31. package/dist/core/downloader.js +0 -64
  32. package/dist/core/errors.js +0 -29
  33. package/dist/core/filesystem.js +0 -246
  34. package/dist/core/lockfile.js +0 -292
  35. package/dist/core/marketplace-converter.js +0 -224
  36. package/dist/core/prompts.js +0 -62
  37. package/dist/core/registry-client.js +0 -305
  38. package/dist/core/schema-validator.js +0 -74
  39. package/dist/core/telemetry.js +0 -253
  40. package/dist/core/user-config.js +0 -147
  41. package/dist/types/registry.js +0 -12
  42. package/dist/types.js +0 -9
  43. package/dist/utils/license-extractor.js +0 -122
  44. package/dist/utils/multi-package.js +0 -117
  45. package/dist/utils/parallel-publisher.js +0 -144
  46. package/dist/utils/script-executor.js +0 -72
  47. package/dist/utils/snippet-extractor.js +0 -77
  48. package/dist/utils/webapp-url.js +0 -44
@@ -1,655 +0,0 @@
1
- "use strict";
2
- /**
3
- * Collections command - Manage package collections
4
- */
5
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- var desc = Object.getOwnPropertyDescriptor(m, k);
8
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
- desc = { enumerable: true, get: function() { return m[k]; } };
10
- }
11
- Object.defineProperty(o, k2, desc);
12
- }) : (function(o, m, k, k2) {
13
- if (k2 === undefined) k2 = k;
14
- o[k2] = m[k];
15
- }));
16
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
- Object.defineProperty(o, "default", { enumerable: true, value: v });
18
- }) : function(o, v) {
19
- o["default"] = v;
20
- });
21
- var __importStar = (this && this.__importStar) || (function () {
22
- var ownKeys = function(o) {
23
- ownKeys = Object.getOwnPropertyNames || function (o) {
24
- var ar = [];
25
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
- return ar;
27
- };
28
- return ownKeys(o);
29
- };
30
- return function (mod) {
31
- if (mod && mod.__esModule) return mod;
32
- var result = {};
33
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
- __setModuleDefault(result, mod);
35
- return result;
36
- };
37
- })();
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.handleCollectionsSearch = handleCollectionsSearch;
40
- exports.handleCollectionsList = handleCollectionsList;
41
- exports.handleCollectionInfo = handleCollectionInfo;
42
- exports.handleCollectionPublish = handleCollectionPublish;
43
- exports.handleCollectionInstall = handleCollectionInstall;
44
- exports.createCollectionsCommand = createCollectionsCommand;
45
- const commander_1 = require("commander");
46
- const registry_client_1 = require("@pr-pm/registry-client");
47
- const user_config_1 = require("../core/user-config");
48
- const install_1 = require("./install");
49
- const telemetry_1 = require("../core/telemetry");
50
- const lockfile_1 = require("../core/lockfile");
51
- const errors_1 = require("../core/errors");
52
- /**
53
- * Search collections by query
54
- */
55
- async function handleCollectionsSearch(query, options) {
56
- const startTime = Date.now();
57
- try {
58
- const config = await (0, user_config_1.getConfig)();
59
- const client = (0, registry_client_1.getRegistryClient)(config);
60
- console.log(`šŸ” Searching collections for "${query}"...\n`);
61
- // Use server-side search with full-text index
62
- const result = await client.getCollections({
63
- query,
64
- category: options.category,
65
- tag: options.tag,
66
- official: options.official,
67
- limit: options.limit || 50,
68
- });
69
- if (result.collections.length === 0) {
70
- console.log('No collections found matching your search.');
71
- console.log('\nšŸ’” Try:');
72
- console.log(' - Broadening your search terms');
73
- console.log(' - Checking spelling');
74
- console.log(' - Browsing all: prpm collections list');
75
- return;
76
- }
77
- console.log(`✨ Found ${result.collections.length} collection(s):\n`);
78
- // Group by official vs community
79
- const official = result.collections.filter(c => c.official);
80
- const community = result.collections.filter(c => !c.official);
81
- if (official.length > 0) {
82
- console.log(`šŸ“¦ Official Collections (${official.length}):\n`);
83
- official.forEach(c => {
84
- const fullName = c.name_slug.padEnd(35);
85
- const pkgCount = `(${c.package_count} packages)`.padEnd(15);
86
- console.log(` ${c.icon || 'šŸ“¦'} ${fullName} ${pkgCount} ${c.name}`);
87
- if (c.description) {
88
- console.log(` ${c.description.substring(0, 70)}${c.description.length > 70 ? '...' : ''}`);
89
- }
90
- if (c.author) {
91
- console.log(` šŸ‘¤ by @${c.author}${c.verified ? ' āœ“' : ''}`);
92
- }
93
- console.log(` ā¬‡ļø ${c.downloads.toLocaleString()} installs Ā· ⭐ ${c.stars.toLocaleString()} stars`);
94
- console.log('');
95
- });
96
- }
97
- if (community.length > 0) {
98
- console.log(`\n🌟 Community Collections (${community.length}):\n`);
99
- community.forEach(c => {
100
- const fullName = c.name_slug.padEnd(35);
101
- const pkgCount = `(${c.package_count} packages)`.padEnd(15);
102
- console.log(` ${c.icon || 'šŸ“¦'} ${fullName} ${pkgCount} ${c.name}`);
103
- if (c.description) {
104
- console.log(` ${c.description.substring(0, 70)}${c.description.length > 70 ? '...' : ''}`);
105
- }
106
- if (c.author) {
107
- console.log(` šŸ‘¤ by @${c.author}${c.verified ? ' āœ“' : ''}`);
108
- }
109
- console.log(` ā¬‡ļø ${c.downloads.toLocaleString()} installs Ā· ⭐ ${c.stars.toLocaleString()} stars`);
110
- console.log('');
111
- });
112
- }
113
- // Show results count
114
- console.log(`\nšŸ“Š Found: ${result.collections.length} matching collection${result.collections.length === 1 ? '' : 's'} (searched ${result.total} total)\n`);
115
- console.log(`šŸ’” View details: prpm collection info <collection>`);
116
- console.log(`šŸ’” Install: prpm install <collection>`);
117
- await telemetry_1.telemetry.track({
118
- command: 'collections:search',
119
- success: true,
120
- duration: Date.now() - startTime,
121
- data: {
122
- query: query.substring(0, 100),
123
- count: result.collections.length,
124
- total: result.total,
125
- filters: options,
126
- },
127
- });
128
- }
129
- catch (error) {
130
- const errorMessage = error instanceof Error ? error.message : String(error);
131
- console.error(`\nāŒ Failed to search collections: ${errorMessage}`);
132
- await telemetry_1.telemetry.track({
133
- command: 'collections:search',
134
- success: false,
135
- error: errorMessage,
136
- duration: Date.now() - startTime,
137
- });
138
- throw new errors_1.CLIError(`\nāŒ Failed to search collections: ${errorMessage}`, 1);
139
- }
140
- finally {
141
- await telemetry_1.telemetry.shutdown();
142
- }
143
- }
144
- /**
145
- * List available collections
146
- */
147
- async function handleCollectionsList(options) {
148
- const startTime = Date.now();
149
- try {
150
- const config = await (0, user_config_1.getConfig)();
151
- const client = (0, registry_client_1.getRegistryClient)(config);
152
- console.log('šŸ“¦ Searching collections...\n');
153
- const result = await client.getCollections({
154
- category: options.category,
155
- tag: options.tag,
156
- official: options.official,
157
- scope: options.scope,
158
- limit: 500, // Increased limit to show more collections
159
- });
160
- if (result.collections.length === 0) {
161
- console.log('No collections found matching your criteria.');
162
- return;
163
- }
164
- // Group by official vs community
165
- const official = result.collections.filter(c => c.official);
166
- const community = result.collections.filter(c => !c.official);
167
- if (official.length > 0) {
168
- console.log(`šŸ“¦ Official Collections (${official.length}):\n`);
169
- official.forEach(c => {
170
- const fullName = c.name_slug.padEnd(35);
171
- const pkgCount = `(${c.package_count} packages)`.padEnd(15);
172
- console.log(` ${c.icon || 'šŸ“¦'} ${fullName} ${pkgCount} ${c.name}`);
173
- if (c.description) {
174
- console.log(` ${c.description.substring(0, 70)}${c.description.length > 70 ? '...' : ''}`);
175
- }
176
- if (c.author) {
177
- console.log(` šŸ‘¤ by @${c.author}${c.verified ? ' āœ“' : ''}`);
178
- }
179
- console.log(` ā¬‡ļø ${c.downloads.toLocaleString()} installs Ā· ⭐ ${c.stars.toLocaleString()} stars`);
180
- console.log('');
181
- });
182
- }
183
- if (community.length > 0) {
184
- console.log(`\n🌟 Community Collections (${community.length}):\n`);
185
- community.forEach(c => {
186
- const fullName = c.name_slug.padEnd(35);
187
- const pkgCount = `(${c.package_count} packages)`.padEnd(15);
188
- console.log(` ${c.icon || 'šŸ“¦'} ${fullName} ${pkgCount} ${c.name}`);
189
- if (c.description) {
190
- console.log(` ${c.description.substring(0, 70)}${c.description.length > 70 ? '...' : ''}`);
191
- }
192
- if (c.author) {
193
- console.log(` šŸ‘¤ by @${c.author}${c.verified ? ' āœ“' : ''}`);
194
- }
195
- console.log(` ā¬‡ļø ${c.downloads.toLocaleString()} installs Ā· ⭐ ${c.stars.toLocaleString()} stars`);
196
- console.log('');
197
- });
198
- }
199
- // Show total from API (which includes all collections, not just the ones returned)
200
- const showing = result.collections.length;
201
- const total = result.total;
202
- if (showing < total) {
203
- console.log(`\nšŸ“Š Showing ${showing} of ${total} collection${total === 1 ? '' : 's'}\n`);
204
- }
205
- else {
206
- console.log(`\nšŸ“Š Total: ${total} collection${total === 1 ? '' : 's'}\n`);
207
- }
208
- console.log(`šŸ’” View details: prpm collection info <collection>`);
209
- console.log(`šŸ’” Install: prpm install <collection>`);
210
- await telemetry_1.telemetry.track({
211
- command: 'collections:list',
212
- success: true,
213
- duration: Date.now() - startTime,
214
- data: {
215
- count: result.collections.length,
216
- total: result.total,
217
- filters: options,
218
- },
219
- });
220
- }
221
- catch (error) {
222
- const errorMessage = error instanceof Error ? error.message : String(error);
223
- console.error(`\nāŒ Failed to list collections: ${errorMessage}`);
224
- await telemetry_1.telemetry.track({
225
- command: 'collections:list',
226
- success: false,
227
- error: errorMessage,
228
- duration: Date.now() - startTime,
229
- });
230
- throw new errors_1.CLIError(`\nāŒ Failed to list collections: ${errorMessage}`, 1);
231
- }
232
- finally {
233
- await telemetry_1.telemetry.shutdown();
234
- }
235
- }
236
- /**
237
- * Show collection details
238
- */
239
- async function handleCollectionInfo(collectionSpec) {
240
- const startTime = Date.now();
241
- try {
242
- // Parse collection spec: @scope/name_slug, scope/name_slug, or just name_slug (defaults to 'collection' scope)
243
- let scope;
244
- let name_slug;
245
- let version;
246
- const matchWithScope = collectionSpec.match(/^@?([^/]+)\/([^/@]+)(?:@(.+))?$/);
247
- if (matchWithScope) {
248
- // Has explicit scope: @scope/name or scope/name
249
- [, scope, name_slug, version] = matchWithScope;
250
- }
251
- else {
252
- // No scope, assume 'collection' scope: just name or name@version
253
- const matchNoScope = collectionSpec.match(/^([^/@]+)(?:@(.+))?$/);
254
- if (!matchNoScope) {
255
- throw new Error('Invalid collection format. Use: name, @scope/name, or scope/name (optionally with @version)');
256
- }
257
- [, name_slug, version] = matchNoScope;
258
- scope = 'collection'; // Default scope
259
- }
260
- const config = await (0, user_config_1.getConfig)();
261
- const client = (0, registry_client_1.getRegistryClient)(config);
262
- console.log(`šŸ“¦ Loading collection: ${scope === 'collection' ? name_slug : `@${scope}/${name_slug}`}...\n`);
263
- const collection = await client.getCollection(scope, name_slug, version);
264
- // Header
265
- console.log(`${collection.icon || 'šŸ“¦'} ${collection.name}`);
266
- console.log(`${'='.repeat(collection.name.length + 2)}`);
267
- console.log('');
268
- console.log(collection.description);
269
- console.log('');
270
- // Stats
271
- console.log('šŸ“Š Stats:');
272
- console.log(` Downloads: ${collection.downloads.toLocaleString()}`);
273
- console.log(` Stars: ${collection.stars.toLocaleString()}`);
274
- console.log(` Version: ${collection.version}`);
275
- console.log(` Packages: ${collection.packages.length}`);
276
- if (collection.author) {
277
- console.log(` Author: ${collection.author}${collection.verified ? ' āœ“' : ''}`);
278
- }
279
- if (collection.category) {
280
- console.log(` Category: ${collection.category}`);
281
- }
282
- if (collection.tags && collection.tags.length > 0) {
283
- console.log(` Tags: ${collection.tags.join(', ')}`);
284
- }
285
- console.log('');
286
- // Packages
287
- console.log('šŸ“‹ Included Packages:');
288
- console.log('');
289
- const requiredPkgs = collection.packages.filter(p => p.required);
290
- const optionalPkgs = collection.packages.filter(p => !p.required);
291
- if (requiredPkgs.length > 0) {
292
- console.log(' Required:');
293
- requiredPkgs.forEach((pkg, i) => {
294
- console.log(` ${i + 1}. āœ“ ${pkg?.package?.name}@${pkg.version || 'latest'}`);
295
- if (pkg.package && pkg.package.description) {
296
- console.log(` ${pkg.package.description}`);
297
- }
298
- if (pkg.reason) {
299
- console.log(` šŸ’” ${pkg.reason}`);
300
- }
301
- console.log('');
302
- });
303
- }
304
- if (optionalPkgs.length > 0) {
305
- console.log(' Optional:');
306
- optionalPkgs.forEach((pkg, i) => {
307
- console.log(` ${i + 1}. ā—‹ ${pkg?.package?.name}@${pkg.version || 'latest'}`);
308
- if (pkg.package && pkg.package.description) {
309
- console.log(` ${pkg.package.description}`);
310
- }
311
- if (pkg.reason) {
312
- console.log(` šŸ’” ${pkg.reason}`);
313
- }
314
- console.log('');
315
- });
316
- }
317
- // Installation
318
- console.log('šŸ’” Install:');
319
- if (scope === 'collection') {
320
- console.log(` prpm install ${name_slug}`);
321
- if (optionalPkgs.length > 0) {
322
- console.log(` prpm install ${name_slug} --skip-optional # Skip optional packages`);
323
- }
324
- }
325
- else {
326
- console.log(` prpm install @${scope}/${name_slug}`);
327
- if (optionalPkgs.length > 0) {
328
- console.log(` prpm install @${scope}/${name_slug} --skip-optional # Skip optional packages`);
329
- }
330
- }
331
- console.log('');
332
- await telemetry_1.telemetry.track({
333
- command: 'collections:info',
334
- success: true,
335
- duration: Date.now() - startTime,
336
- data: {
337
- scope,
338
- name_slug,
339
- packageCount: collection.packages.length,
340
- },
341
- });
342
- }
343
- catch (error) {
344
- const errorMessage = error instanceof Error ? error.message : String(error);
345
- console.error(`\nāŒ Failed to get collection info: ${errorMessage}`);
346
- await telemetry_1.telemetry.track({
347
- command: 'collections:info',
348
- success: false,
349
- error: errorMessage,
350
- duration: Date.now() - startTime,
351
- });
352
- throw new errors_1.CLIError(`\nāŒ Failed to get collection info: ${errorMessage}`, 1);
353
- }
354
- finally {
355
- await telemetry_1.telemetry.shutdown();
356
- }
357
- }
358
- /**
359
- * Publish/create a collection
360
- */
361
- async function handleCollectionPublish(manifestPath = './collection.json') {
362
- const startTime = Date.now();
363
- try {
364
- const config = await (0, user_config_1.getConfig)();
365
- const client = (0, registry_client_1.getRegistryClient)(config);
366
- // Check authentication
367
- if (!config.token) {
368
- console.error('\nāŒ Authentication required. Run `prpm login` first.\n');
369
- throw new errors_1.CLIError('\nāŒ Authentication required. Run `prpm login` first.', 1);
370
- }
371
- console.log('šŸ“¦ Publishing collection...\n');
372
- // Read collection manifest
373
- const fs = await Promise.resolve().then(() => __importStar(require('fs/promises')));
374
- const manifestContent = await fs.readFile(manifestPath, 'utf-8');
375
- const manifest = JSON.parse(manifestContent);
376
- // Validate manifest
377
- const required = ['id', 'name', 'description', 'packages'];
378
- const missing = required.filter(field => !manifest[field]);
379
- if (missing.length > 0) {
380
- throw new Error(`Missing required fields: ${missing.join(', ')}`);
381
- }
382
- // Validate id format (must be lowercase alphanumeric with hyphens)
383
- if (!/^[a-z0-9-]+$/.test(manifest.id)) {
384
- throw new Error('Collection id must be lowercase alphanumeric with hyphens only');
385
- }
386
- // Validate name length
387
- if (manifest.name.length < 3) {
388
- throw new Error('Collection name must be at least 3 characters');
389
- }
390
- // Validate description length
391
- if (manifest.description.length < 10) {
392
- throw new Error('Collection description must be at least 10 characters');
393
- }
394
- // Validate packages array
395
- if (!Array.isArray(manifest.packages) || manifest.packages.length === 0) {
396
- throw new Error('Collection must include at least one package');
397
- }
398
- // Validate each package
399
- manifest.packages.forEach((pkg, idx) => {
400
- if (!pkg.packageId) {
401
- throw new Error(`Package at index ${idx} is missing packageId`);
402
- }
403
- });
404
- console.log(`šŸ” Validating collection manifest...`);
405
- console.log(` Collection: ${manifest.name}`);
406
- console.log(` ID: ${manifest.id}`);
407
- console.log(` Packages: ${manifest.packages.length}`);
408
- console.log('');
409
- // Publish to registry
410
- console.log('šŸš€ Publishing to registry...\n');
411
- const result = await client.createCollection({
412
- id: manifest.id,
413
- name: manifest.name,
414
- description: manifest.description,
415
- category: manifest.category,
416
- tags: manifest.tags,
417
- packages: manifest.packages.map((pkg) => ({
418
- packageId: pkg.packageId,
419
- version: pkg.version,
420
- required: pkg.required !== false,
421
- reason: pkg.reason,
422
- })),
423
- icon: manifest.icon,
424
- });
425
- console.log(`āœ… Collection published successfully!`);
426
- console.log(` Scope: ${result.scope}`);
427
- console.log(` Name: ${result.name_slug}`);
428
- console.log(` Version: ${result.version || '1.0.0'}`);
429
- console.log('');
430
- console.log(`šŸ’” View: prpm collection info @${result.scope}/${result.name_slug}`);
431
- console.log(`šŸ’” Install: prpm install @${result.scope}/${result.name_slug}`);
432
- console.log('');
433
- await telemetry_1.telemetry.track({
434
- command: 'collections:publish',
435
- success: true,
436
- duration: Date.now() - startTime,
437
- data: {
438
- id: manifest.id,
439
- packageCount: manifest.packages.length,
440
- },
441
- });
442
- }
443
- catch (error) {
444
- const errorMessage = error instanceof Error ? error.message : String(error);
445
- console.error(`\nāŒ Failed to publish collection: ${errorMessage}\n`);
446
- await telemetry_1.telemetry.track({
447
- command: 'collections:publish',
448
- success: false,
449
- error: errorMessage,
450
- duration: Date.now() - startTime,
451
- });
452
- throw new errors_1.CLIError(`\nāŒ Failed to publish collection: ${errorMessage}`, 1);
453
- }
454
- finally {
455
- await telemetry_1.telemetry.shutdown();
456
- }
457
- }
458
- /**
459
- * Install a collection
460
- */
461
- async function handleCollectionInstall(collectionSpec, options) {
462
- const startTime = Date.now();
463
- let packagesInstalled = 0;
464
- let packagesFailed = 0;
465
- try {
466
- // Parse collection spec: @scope/name_slug, scope/name_slug, or just name_slug (defaults to 'collection' scope)
467
- let scope;
468
- let name_slug;
469
- let version;
470
- const matchWithScope = collectionSpec.match(/^@?([^/]+)\/([^/@]+)(?:@(.+))?$/);
471
- if (matchWithScope) {
472
- // Has explicit scope: @scope/name or scope/name
473
- [, scope, name_slug, version] = matchWithScope;
474
- }
475
- else {
476
- // No scope, assume 'collection' scope: just name or name@version
477
- const matchNoScope = collectionSpec.match(/^([^/@]+)(?:@(.+))?$/);
478
- if (!matchNoScope) {
479
- throw new Error('Invalid collection format. Use: name, @scope/name, or scope/name (optionally with @version)');
480
- }
481
- [, name_slug, version] = matchNoScope;
482
- scope = 'collection'; // Default scope
483
- }
484
- const config = await (0, user_config_1.getConfig)();
485
- const client = (0, registry_client_1.getRegistryClient)(config);
486
- // Get collection installation plan
487
- console.log(`šŸ“¦ Installing collection: ${scope === 'collection' ? name_slug : `@${scope}/${name_slug}`}...\n`);
488
- const installResult = await client.installCollection({
489
- scope,
490
- id: name_slug,
491
- version,
492
- format: options.format,
493
- skipOptional: options.skipOptional,
494
- });
495
- const collection = installResult.collection;
496
- const packages = installResult.packagesToInstall;
497
- console.log(`šŸ“¦ ${collection.name}`);
498
- console.log(` ${packages.length} packages to install\n`);
499
- if (options.dryRun) {
500
- console.log('šŸ” Dry run - would install:\n');
501
- packages.forEach((pkg, i) => {
502
- const required = pkg.required ? 'āœ“' : 'ā—‹';
503
- console.log(` ${i + 1}/${packages.length} ${required} ${pkg.packageId}@${pkg.version} (${pkg.format})`);
504
- });
505
- console.log('');
506
- return;
507
- }
508
- // Install packages sequentially
509
- const installedPackageIds = [];
510
- let hasClaudeHooks = false;
511
- for (let i = 0; i < packages.length; i++) {
512
- const pkg = packages[i];
513
- const progress = `${i + 1}/${packages.length}`;
514
- try {
515
- console.log(`\n ${progress} Installing ${pkg.packageId}@${pkg.version}...`);
516
- // Only pass 'as' format if user explicitly requested it via --as flag
517
- // Otherwise, handleInstall will use this priority order:
518
- // 1. defaultFormat from .prpmrc config
519
- // 2. Auto-detection based on existing directories
520
- // 3. Package native format
521
- const installOptions = {
522
- fromCollection: {
523
- scope,
524
- name_slug,
525
- version: collection.version || version || '1.0.0',
526
- },
527
- };
528
- // Only set 'as' if user explicitly provided a format
529
- if (options.format) {
530
- installOptions.as = options.format;
531
- }
532
- // Track if this collection contains Claude hooks
533
- if (pkg.format === 'claude' && pkg.subtype === 'hook') {
534
- hasClaudeHooks = true;
535
- }
536
- await (0, install_1.handleInstall)(`${pkg.packageId}@${pkg.version}`, installOptions);
537
- console.log(` ${progress} āœ“ ${pkg.packageId}`);
538
- installedPackageIds.push(pkg.packageId);
539
- packagesInstalled++;
540
- }
541
- catch (error) {
542
- const errorMessage = error instanceof Error ? error.message : String(error);
543
- console.error(` ${progress} āœ— ${pkg.packageId}: ${errorMessage}`);
544
- packagesFailed++;
545
- if (pkg.required) {
546
- throw new Error(`Failed to install required package: ${pkg.packageId}`);
547
- }
548
- }
549
- }
550
- // Update lockfile with collection info
551
- const lockfile = (await (0, lockfile_1.readLockfile)()) || (0, lockfile_1.createLockfile)();
552
- const collectionKey = `@${scope}/${name_slug}`;
553
- (0, lockfile_1.addCollectionToLockfile)(lockfile, collectionKey, {
554
- scope,
555
- name_slug,
556
- version: collection.version || version || '1.0.0',
557
- packages: installedPackageIds,
558
- });
559
- await (0, lockfile_1.writeLockfile)(lockfile);
560
- console.log(`\nāœ… Collection installed successfully!`);
561
- console.log(` ${packagesInstalled}/${packages.length} packages installed`);
562
- if (packagesFailed > 0) {
563
- console.log(` ${packagesFailed} optional packages failed`);
564
- }
565
- console.log(` šŸ”’ Collection tracked in lock file`);
566
- // Show Claude hooks warning if any were installed
567
- if (hasClaudeHooks) {
568
- console.log(`\nāš ļø This collection includes Claude hooks that execute automatically.`);
569
- console.log(` šŸ“– Review hook configurations in .claude/settings.json`);
570
- }
571
- console.log('');
572
- await telemetry_1.telemetry.track({
573
- command: 'collections:install',
574
- success: true,
575
- duration: Date.now() - startTime,
576
- data: {
577
- scope,
578
- name_slug,
579
- packageCount: packages.length,
580
- installed: packagesInstalled,
581
- failed: packagesFailed,
582
- format: options.format,
583
- },
584
- });
585
- }
586
- catch (error) {
587
- const errorMessage = error instanceof Error ? error.message : String(error);
588
- console.error(`\nāŒ Failed to install collection: ${errorMessage}`);
589
- await telemetry_1.telemetry.track({
590
- command: 'collections:install',
591
- success: false,
592
- error: errorMessage,
593
- duration: Date.now() - startTime,
594
- data: {
595
- installed: packagesInstalled,
596
- failed: packagesFailed,
597
- },
598
- });
599
- throw new errors_1.CLIError(`\nāŒ Failed to install collection: ${errorMessage}`, 1);
600
- }
601
- finally {
602
- await telemetry_1.telemetry.shutdown();
603
- }
604
- }
605
- /**
606
- * Create collections command group
607
- */
608
- function createCollectionsCommand() {
609
- const command = new commander_1.Command('collections');
610
- command
611
- .description('Manage package collections')
612
- .alias('collection')
613
- .action(async (options) => {
614
- await handleCollectionsList(options);
615
- });
616
- // Search subcommand
617
- command
618
- .command('search <query>')
619
- .description('Search for collections')
620
- .option('--category <category>', 'Filter by category')
621
- .option('--tag <tag>', 'Filter by tag')
622
- .option('--official', 'Show only official collections')
623
- .option('--limit <number>', 'Number of results to show', '50')
624
- .action(async (query, options) => {
625
- await handleCollectionsSearch(query, {
626
- category: options.category,
627
- tag: options.tag,
628
- official: options.official,
629
- limit: options.limit ? parseInt(options.limit, 10) : 50,
630
- });
631
- });
632
- // List subcommand
633
- command
634
- .command('list')
635
- .description('List available collections')
636
- .option('--category <category>', 'Filter by category')
637
- .option('--tag <tag>', 'Filter by tag')
638
- .option('--official', 'Show only official collections')
639
- .option('--scope <scope>', 'Filter by scope')
640
- .action(handleCollectionsList);
641
- // Info subcommand
642
- command
643
- .command('info <collection>')
644
- .description('Show collection details')
645
- .action(handleCollectionInfo);
646
- // Publish subcommand
647
- command
648
- .command('publish [manifest]')
649
- .description('Publish a collection from collection.json')
650
- .action(async (manifest) => {
651
- await handleCollectionPublish(manifest);
652
- });
653
- // Install handled by main install command with @scope/id syntax
654
- return command;
655
- }