prpm 0.0.21 → 0.1.1
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.
- package/dist/commands/list.js +2 -0
- package/dist/commands/popular.js +1 -1
- package/dist/commands/publish.js +125 -15
- package/dist/commands/search.js +2 -2
- package/dist/commands/trending.js +2 -2
- package/dist/core/filesystem.js +2 -0
- package/package.json +3 -3
- package/schemas/prpm-manifest.schema.json +146 -0
package/dist/commands/list.js
CHANGED
package/dist/commands/popular.js
CHANGED
|
@@ -25,7 +25,7 @@ async function handlePopular(options) {
|
|
|
25
25
|
function createPopularCommand() {
|
|
26
26
|
return new commander_1.Command('popular')
|
|
27
27
|
.description('Show popular packages (all time)')
|
|
28
|
-
.option('--format <format>', 'Filter by format (cursor, claude, continue, windsurf, copilot, kiro, generic)')
|
|
28
|
+
.option('--format <format>', 'Filter by format (cursor, claude, continue, windsurf, copilot, kiro, agents.md, generic)')
|
|
29
29
|
.option('--subtype <subtype>', 'Filter by subtype (rule, agent, skill, slash-command, prompt, workflow, tool, template, collection)')
|
|
30
30
|
.action(async (options) => {
|
|
31
31
|
await handlePopular(options);
|
package/dist/commands/publish.js
CHANGED
|
@@ -54,7 +54,7 @@ const snippet_extractor_1 = require("../utils/snippet-extractor");
|
|
|
54
54
|
/**
|
|
55
55
|
* Try to find and load manifest files
|
|
56
56
|
* Checks for:
|
|
57
|
-
* 1. prpm.json (native format) - returns single manifest or array of packages
|
|
57
|
+
* 1. prpm.json (native format) - returns single manifest or array of packages and collections
|
|
58
58
|
* 2. .claude/marketplace.json (Claude format) - returns all plugins as separate manifests
|
|
59
59
|
* 3. .claude-plugin/marketplace.json (Claude format - alternative location) - returns all plugins
|
|
60
60
|
*/
|
|
@@ -66,6 +66,12 @@ async function findAndLoadManifests() {
|
|
|
66
66
|
try {
|
|
67
67
|
const content = await (0, promises_1.readFile)(prpmJsonPath, 'utf-8');
|
|
68
68
|
const manifest = JSON.parse(content);
|
|
69
|
+
// Extract collections if present
|
|
70
|
+
const collections = [];
|
|
71
|
+
if ('collections' in manifest && Array.isArray(manifest.collections)) {
|
|
72
|
+
const rawCollections = manifest.collections;
|
|
73
|
+
collections.push(...rawCollections);
|
|
74
|
+
}
|
|
69
75
|
// Check if this is a multi-package manifest
|
|
70
76
|
if ('packages' in manifest && Array.isArray(manifest.packages)) {
|
|
71
77
|
const multiManifest = manifest;
|
|
@@ -94,11 +100,15 @@ async function findAndLoadManifests() {
|
|
|
94
100
|
};
|
|
95
101
|
return validateManifest(packageWithDefaults);
|
|
96
102
|
});
|
|
97
|
-
return { manifests: validatedManifests, source: 'prpm.json (multi-package)' };
|
|
103
|
+
return { manifests: validatedManifests, collections, source: 'prpm.json (multi-package)' };
|
|
104
|
+
}
|
|
105
|
+
// Collections-only manifest (no packages)
|
|
106
|
+
if (collections.length > 0) {
|
|
107
|
+
return { manifests: [], collections, source: 'prpm.json (collections-only)' };
|
|
98
108
|
}
|
|
99
109
|
// Single package manifest
|
|
100
110
|
const validated = validateManifest(manifest);
|
|
101
|
-
return { manifests: [validated], source: 'prpm.json' };
|
|
111
|
+
return { manifests: [validated], collections, source: 'prpm.json' };
|
|
102
112
|
}
|
|
103
113
|
catch (error) {
|
|
104
114
|
// Store error for later
|
|
@@ -127,7 +137,7 @@ async function findAndLoadManifests() {
|
|
|
127
137
|
const validated = validateManifest(manifest);
|
|
128
138
|
manifests.push(validated);
|
|
129
139
|
}
|
|
130
|
-
return { manifests, source: '.claude/marketplace.json' };
|
|
140
|
+
return { manifests, collections: [], source: '.claude/marketplace.json' };
|
|
131
141
|
}
|
|
132
142
|
catch (error) {
|
|
133
143
|
// marketplace.json not found or invalid at .claude path, try .claude-plugin
|
|
@@ -147,7 +157,7 @@ async function findAndLoadManifests() {
|
|
|
147
157
|
const validated = validateManifest(manifest);
|
|
148
158
|
manifests.push(validated);
|
|
149
159
|
}
|
|
150
|
-
return { manifests, source: '.claude-plugin/marketplace.json' };
|
|
160
|
+
return { manifests, collections: [], source: '.claude-plugin/marketplace.json' };
|
|
151
161
|
}
|
|
152
162
|
catch (error) {
|
|
153
163
|
// marketplace.json not found or invalid
|
|
@@ -322,13 +332,21 @@ async function handlePublish(options) {
|
|
|
322
332
|
console.log('📦 Publishing package...\n');
|
|
323
333
|
// Read and validate manifests
|
|
324
334
|
console.log('🔍 Validating package manifest(s)...');
|
|
325
|
-
const { manifests, source } = await findAndLoadManifests();
|
|
326
|
-
if (manifests.length > 1) {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
335
|
+
const { manifests, collections, source } = await findAndLoadManifests();
|
|
336
|
+
if (manifests.length > 1 || collections.length > 0) {
|
|
337
|
+
if (manifests.length > 0) {
|
|
338
|
+
console.log(` Found ${manifests.length} package(s) in ${source}`);
|
|
339
|
+
if (options.package) {
|
|
340
|
+
console.log(` Filtering to package: ${options.package}`);
|
|
341
|
+
}
|
|
330
342
|
}
|
|
331
|
-
|
|
343
|
+
if (collections.length > 0) {
|
|
344
|
+
console.log(` Found ${collections.length} collection(s) in ${source}`);
|
|
345
|
+
if (options.collection) {
|
|
346
|
+
console.log(` Filtering to collection: ${options.collection}`);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
console.log(' Will publish each separately\n');
|
|
332
350
|
}
|
|
333
351
|
// Filter to specific package if requested
|
|
334
352
|
let filteredManifests = manifests;
|
|
@@ -373,9 +391,11 @@ async function handlePublish(options) {
|
|
|
373
391
|
throw new Error('Cannot publish packages with duplicate names');
|
|
374
392
|
}
|
|
375
393
|
}
|
|
376
|
-
// Track published packages
|
|
394
|
+
// Track published packages and collections
|
|
377
395
|
const publishedPackages = [];
|
|
378
396
|
const failedPackages = [];
|
|
397
|
+
const publishedCollections = [];
|
|
398
|
+
const failedCollections = [];
|
|
379
399
|
// Publish each manifest (filtered set)
|
|
380
400
|
for (let i = 0; i < filteredManifests.length; i++) {
|
|
381
401
|
const manifest = filteredManifests[i];
|
|
@@ -538,6 +558,94 @@ async function handlePublish(options) {
|
|
|
538
558
|
});
|
|
539
559
|
}
|
|
540
560
|
}
|
|
561
|
+
// Publish collections if present
|
|
562
|
+
if (collections.length > 0) {
|
|
563
|
+
// Filter to specific collection if requested
|
|
564
|
+
let filteredCollections = collections;
|
|
565
|
+
if (options.collection) {
|
|
566
|
+
filteredCollections = collections.filter(c => c.id === options.collection);
|
|
567
|
+
if (filteredCollections.length === 0) {
|
|
568
|
+
throw new Error(`Collection "${options.collection}" not found in manifest. Available collections: ${collections.map(c => c.id).join(', ')}`);
|
|
569
|
+
}
|
|
570
|
+
console.log(` ✓ Found collection "${options.collection}"\n`);
|
|
571
|
+
}
|
|
572
|
+
for (const collection of filteredCollections) {
|
|
573
|
+
if (filteredCollections.length > 1) {
|
|
574
|
+
console.log(`\n${'='.repeat(60)}`);
|
|
575
|
+
console.log(`📚 Publishing collection`);
|
|
576
|
+
console.log(`${'='.repeat(60)}\n`);
|
|
577
|
+
}
|
|
578
|
+
try {
|
|
579
|
+
console.log(`📚 Publishing collection "${collection.name}"...`);
|
|
580
|
+
console.log(` ID: ${collection.id}`);
|
|
581
|
+
console.log(` Packages: ${collection.packages.length}`);
|
|
582
|
+
console.log('');
|
|
583
|
+
if (options.dryRun) {
|
|
584
|
+
console.log('✅ Dry run successful! Collection is ready to publish.');
|
|
585
|
+
publishedCollections.push({
|
|
586
|
+
id: collection.id,
|
|
587
|
+
name: collection.name,
|
|
588
|
+
version: collection.version || '1.0.0'
|
|
589
|
+
});
|
|
590
|
+
continue;
|
|
591
|
+
}
|
|
592
|
+
// Import and call the collection publish logic
|
|
593
|
+
const { handleCollectionPublish } = await Promise.resolve().then(() => __importStar(require('./collections.js')));
|
|
594
|
+
// Create a temporary manifest object for the collection
|
|
595
|
+
const collectionData = {
|
|
596
|
+
id: collection.id,
|
|
597
|
+
name: collection.name,
|
|
598
|
+
description: collection.description,
|
|
599
|
+
version: collection.version,
|
|
600
|
+
category: collection.category,
|
|
601
|
+
tags: collection.tags,
|
|
602
|
+
icon: collection.icon,
|
|
603
|
+
packages: collection.packages.map(pkg => ({
|
|
604
|
+
packageId: pkg.packageId,
|
|
605
|
+
version: pkg.version,
|
|
606
|
+
required: pkg.required !== false,
|
|
607
|
+
reason: pkg.reason,
|
|
608
|
+
})),
|
|
609
|
+
};
|
|
610
|
+
const result = await client.createCollection(collectionData);
|
|
611
|
+
console.log(`✅ Collection published successfully!`);
|
|
612
|
+
console.log(` Scope: ${result.scope}`);
|
|
613
|
+
console.log(` Name: ${result.name_slug}`);
|
|
614
|
+
console.log(` Version: ${result.version || '1.0.0'}`);
|
|
615
|
+
console.log('');
|
|
616
|
+
console.log(`💡 Install: prpm install collections/${result.name_slug}`);
|
|
617
|
+
console.log('');
|
|
618
|
+
publishedCollections.push({
|
|
619
|
+
id: collection.id,
|
|
620
|
+
name: collection.name,
|
|
621
|
+
version: result.version || '1.0.0'
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
catch (err) {
|
|
625
|
+
const collError = err instanceof Error ? err.message : String(err);
|
|
626
|
+
console.error(`\n❌ Failed to publish collection ${collection.id}: ${collError}\n`);
|
|
627
|
+
failedCollections.push({
|
|
628
|
+
id: collection.id,
|
|
629
|
+
error: collError
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
// Add collection results to summary
|
|
634
|
+
if (publishedCollections.length > 0) {
|
|
635
|
+
console.log(`✅ Successfully published ${publishedCollections.length} collection(s):`);
|
|
636
|
+
publishedCollections.forEach(coll => {
|
|
637
|
+
console.log(` - ${coll.name} (${coll.id}) v${coll.version}`);
|
|
638
|
+
});
|
|
639
|
+
console.log('');
|
|
640
|
+
}
|
|
641
|
+
if (failedCollections.length > 0) {
|
|
642
|
+
console.log(`❌ Failed to publish ${failedCollections.length} collection(s):`);
|
|
643
|
+
failedCollections.forEach(coll => {
|
|
644
|
+
console.log(` - ${coll.id}: ${coll.error}`);
|
|
645
|
+
});
|
|
646
|
+
console.log('');
|
|
647
|
+
}
|
|
648
|
+
}
|
|
541
649
|
// Print summary if multiple packages
|
|
542
650
|
if (manifests.length > 1) {
|
|
543
651
|
console.log(`\n${'='.repeat(60)}`);
|
|
@@ -569,8 +677,9 @@ async function handlePublish(options) {
|
|
|
569
677
|
}
|
|
570
678
|
}
|
|
571
679
|
}
|
|
572
|
-
|
|
573
|
-
|
|
680
|
+
// Success if we published any packages OR collections
|
|
681
|
+
success = publishedPackages.length > 0 || publishedCollections.length > 0;
|
|
682
|
+
if (failedPackages.length > 0 && publishedPackages.length === 0 && publishedCollections.length === 0) {
|
|
574
683
|
process.exit(1);
|
|
575
684
|
}
|
|
576
685
|
}
|
|
@@ -628,11 +737,12 @@ async function handlePublish(options) {
|
|
|
628
737
|
*/
|
|
629
738
|
function createPublishCommand() {
|
|
630
739
|
return new commander_1.Command('publish')
|
|
631
|
-
.description('Publish
|
|
740
|
+
.description('Publish packages and collections to the registry')
|
|
632
741
|
.option('--access <type>', 'Package access (public or private) - overrides manifest setting')
|
|
633
742
|
.option('--tag <tag>', 'NPM-style tag (e.g., latest, beta)', 'latest')
|
|
634
743
|
.option('--dry-run', 'Validate package without publishing')
|
|
635
744
|
.option('--package <name>', 'Publish only a specific package from multi-package manifest')
|
|
745
|
+
.option('--collection <id>', 'Publish only a specific collection from manifest')
|
|
636
746
|
.action(async (options) => {
|
|
637
747
|
await handlePublish(options);
|
|
638
748
|
process.exit(0);
|
package/dist/commands/search.js
CHANGED
|
@@ -391,7 +391,7 @@ function createSearchCommand() {
|
|
|
391
391
|
command
|
|
392
392
|
.description('Search for packages in the registry')
|
|
393
393
|
.argument('[query]', 'Search query (optional when using --format/--subtype or --author)')
|
|
394
|
-
.option('--format <format>', 'Filter by package format (cursor, claude, continue, windsurf, copilot, kiro, generic, mcp)')
|
|
394
|
+
.option('--format <format>', 'Filter by package format (cursor, claude, continue, windsurf, copilot, kiro, agents.md, generic, mcp)')
|
|
395
395
|
.option('--subtype <subtype>', 'Filter by package subtype (rule, agent, skill, slash-command, prompt, workflow, tool, template, collection)')
|
|
396
396
|
.option('--author <username>', 'Filter by author username')
|
|
397
397
|
.option('--limit <number>', 'Number of results per page', '20')
|
|
@@ -404,7 +404,7 @@ function createSearchCommand() {
|
|
|
404
404
|
const author = options.author;
|
|
405
405
|
const limit = options.limit ? parseInt(options.limit, 10) : 20;
|
|
406
406
|
const page = options.page ? parseInt(options.page, 10) : 1;
|
|
407
|
-
const validFormats = ['cursor', 'claude', 'continue', 'windsurf', 'copilot', 'kiro', 'generic', 'mcp'];
|
|
407
|
+
const validFormats = ['cursor', 'claude', 'continue', 'windsurf', 'copilot', 'kiro', 'agents.md', 'generic', 'mcp'];
|
|
408
408
|
const validSubtypes = ['rule', 'agent', 'skill', 'slash-command', 'prompt', 'collection', 'chatmode'];
|
|
409
409
|
if (options.format && !validFormats.includes(format)) {
|
|
410
410
|
console.error(`❌ Format must be one of: ${validFormats.join(', ')}`);
|
|
@@ -62,14 +62,14 @@ function createTrendingCommand() {
|
|
|
62
62
|
const command = new commander_1.Command('trending');
|
|
63
63
|
command
|
|
64
64
|
.description('Show trending packages')
|
|
65
|
-
.option('--format <format>', 'Filter by format (cursor, claude, continue, windsurf, copilot, kiro, generic)')
|
|
65
|
+
.option('--format <format>', 'Filter by format (cursor, claude, continue, windsurf, copilot, kiro, agents.md, generic)')
|
|
66
66
|
.option('--subtype <subtype>', 'Filter by subtype (rule, agent, skill, slash-command, prompt, workflow, tool, template, collection)')
|
|
67
67
|
.option('--limit <number>', 'Number of packages to show', '10')
|
|
68
68
|
.action(async (options) => {
|
|
69
69
|
const format = options.format;
|
|
70
70
|
const subtype = options.subtype;
|
|
71
71
|
const limit = options.limit ? parseInt(options.limit, 10) : 10;
|
|
72
|
-
const validFormats = ['cursor', 'claude', 'continue', 'windsurf', 'copilot', 'kiro', 'generic', 'mcp'];
|
|
72
|
+
const validFormats = ['cursor', 'claude', 'continue', 'windsurf', 'copilot', 'kiro', 'agents.md', 'generic', 'mcp'];
|
|
73
73
|
const validSubtypes = ['rule', 'agent', 'skill', 'slash-command', 'prompt', 'workflow', 'tool', 'template', 'collection'];
|
|
74
74
|
if (options.format && !validFormats.includes(format)) {
|
|
75
75
|
console.error(`❌ Format must be one of: ${validFormats.join(', ')}`);
|
package/dist/core/filesystem.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prpm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Prompt Package Manager CLI - Install and manage prompt-based files",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"license": "MIT",
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@octokit/rest": "^22.0.0",
|
|
48
|
-
"@pr-pm/registry-client": "^1.
|
|
49
|
-
"@pr-pm/types": "^0.
|
|
48
|
+
"@pr-pm/registry-client": "^1.3.0",
|
|
49
|
+
"@pr-pm/types": "^0.2.0",
|
|
50
50
|
"ajv": "^8.17.1",
|
|
51
51
|
"ajv-formats": "^3.0.1",
|
|
52
52
|
"commander": "^11.1.0",
|
|
@@ -367,6 +367,100 @@
|
|
|
367
367
|
"$ref": "#"
|
|
368
368
|
},
|
|
369
369
|
"minItems": 1
|
|
370
|
+
},
|
|
371
|
+
"collections": {
|
|
372
|
+
"type": "array",
|
|
373
|
+
"description": "Array of collections to publish. Collections bundle multiple packages together for easier installation.",
|
|
374
|
+
"items": {
|
|
375
|
+
"type": "object",
|
|
376
|
+
"required": ["id", "name", "description", "packages"],
|
|
377
|
+
"properties": {
|
|
378
|
+
"id": {
|
|
379
|
+
"type": "string",
|
|
380
|
+
"description": "Unique collection identifier (kebab-case)",
|
|
381
|
+
"pattern": "^[a-z0-9-]+$",
|
|
382
|
+
"minLength": 3,
|
|
383
|
+
"maxLength": 100,
|
|
384
|
+
"examples": ["nextjs-complete", "fullstack-setup", "react-essentials"]
|
|
385
|
+
},
|
|
386
|
+
"name": {
|
|
387
|
+
"type": "string",
|
|
388
|
+
"description": "Display name of the collection",
|
|
389
|
+
"minLength": 3,
|
|
390
|
+
"maxLength": 100,
|
|
391
|
+
"examples": ["Next.js Complete", "Full Stack Setup"]
|
|
392
|
+
},
|
|
393
|
+
"description": {
|
|
394
|
+
"type": "string",
|
|
395
|
+
"description": "What this collection provides",
|
|
396
|
+
"minLength": 10,
|
|
397
|
+
"maxLength": 500
|
|
398
|
+
},
|
|
399
|
+
"version": {
|
|
400
|
+
"type": "string",
|
|
401
|
+
"description": "Semantic version of the collection",
|
|
402
|
+
"pattern": "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?(\\+[a-zA-Z0-9.-]+)?$",
|
|
403
|
+
"examples": ["1.0.0", "2.1.0"]
|
|
404
|
+
},
|
|
405
|
+
"category": {
|
|
406
|
+
"type": "string",
|
|
407
|
+
"description": "Collection category",
|
|
408
|
+
"enum": ["development", "testing", "deployment", "data-science", "devops", "design", "documentation", "security", "performance", "general"],
|
|
409
|
+
"examples": ["development", "testing"]
|
|
410
|
+
},
|
|
411
|
+
"tags": {
|
|
412
|
+
"type": "array",
|
|
413
|
+
"description": "Tags for discoverability (kebab-case)",
|
|
414
|
+
"items": {
|
|
415
|
+
"type": "string",
|
|
416
|
+
"pattern": "^[a-z0-9-]+$"
|
|
417
|
+
},
|
|
418
|
+
"minItems": 1,
|
|
419
|
+
"maxItems": 10,
|
|
420
|
+
"examples": [["react", "typescript", "nextjs"], ["python", "data-science", "ml"]]
|
|
421
|
+
},
|
|
422
|
+
"icon": {
|
|
423
|
+
"type": "string",
|
|
424
|
+
"description": "Emoji or icon for the collection",
|
|
425
|
+
"maxLength": 10,
|
|
426
|
+
"examples": ["⚛️", "🚀", "📦"]
|
|
427
|
+
},
|
|
428
|
+
"packages": {
|
|
429
|
+
"type": "array",
|
|
430
|
+
"description": "Array of packages included in this collection",
|
|
431
|
+
"items": {
|
|
432
|
+
"type": "object",
|
|
433
|
+
"required": ["packageId"],
|
|
434
|
+
"properties": {
|
|
435
|
+
"packageId": {
|
|
436
|
+
"type": "string",
|
|
437
|
+
"description": "Package identifier to include",
|
|
438
|
+
"minLength": 1,
|
|
439
|
+
"examples": ["typescript-strict", "react-best-practices"]
|
|
440
|
+
},
|
|
441
|
+
"version": {
|
|
442
|
+
"type": "string",
|
|
443
|
+
"description": "Version range (semver) or 'latest'",
|
|
444
|
+
"examples": ["^1.0.0", "~2.1.0", "1.0.0", "latest"]
|
|
445
|
+
},
|
|
446
|
+
"required": {
|
|
447
|
+
"type": "boolean",
|
|
448
|
+
"description": "Whether this package is required (true) or optional (false)",
|
|
449
|
+
"default": true
|
|
450
|
+
},
|
|
451
|
+
"reason": {
|
|
452
|
+
"type": "string",
|
|
453
|
+
"description": "Explanation of why this package is included",
|
|
454
|
+
"maxLength": 200,
|
|
455
|
+
"examples": ["Enforces strict TypeScript type safety", "React component best practices"]
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
"minItems": 1
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
},
|
|
463
|
+
"minItems": 1
|
|
370
464
|
}
|
|
371
465
|
},
|
|
372
466
|
"additionalProperties": false,
|
|
@@ -549,6 +643,58 @@
|
|
|
549
643
|
]
|
|
550
644
|
}
|
|
551
645
|
]
|
|
646
|
+
},
|
|
647
|
+
{
|
|
648
|
+
"name": "@username/multi-package-with-collection",
|
|
649
|
+
"version": "1.0.0",
|
|
650
|
+
"description": "Repository with both packages and a collection",
|
|
651
|
+
"author": "Your Name",
|
|
652
|
+
"license": "MIT",
|
|
653
|
+
"packages": [
|
|
654
|
+
{
|
|
655
|
+
"name": "typescript-rules",
|
|
656
|
+
"version": "1.0.0",
|
|
657
|
+
"description": "TypeScript coding standards",
|
|
658
|
+
"format": "cursor",
|
|
659
|
+
"subtype": "rule",
|
|
660
|
+
"tags": ["typescript", "cursor"],
|
|
661
|
+
"files": [".cursor/rules/typescript.mdc"]
|
|
662
|
+
},
|
|
663
|
+
{
|
|
664
|
+
"name": "react-patterns",
|
|
665
|
+
"version": "1.0.0",
|
|
666
|
+
"description": "React best practices",
|
|
667
|
+
"format": "claude",
|
|
668
|
+
"subtype": "skill",
|
|
669
|
+
"tags": ["react", "best-practices"],
|
|
670
|
+
"files": [".claude/skills/react-patterns/SKILL.md"]
|
|
671
|
+
}
|
|
672
|
+
],
|
|
673
|
+
"collections": [
|
|
674
|
+
{
|
|
675
|
+
"id": "fullstack-setup",
|
|
676
|
+
"name": "Full Stack Setup",
|
|
677
|
+
"description": "Complete full-stack development setup with TypeScript and React",
|
|
678
|
+
"version": "1.0.0",
|
|
679
|
+
"category": "development",
|
|
680
|
+
"tags": ["typescript", "react", "fullstack"],
|
|
681
|
+
"icon": "🚀",
|
|
682
|
+
"packages": [
|
|
683
|
+
{
|
|
684
|
+
"packageId": "typescript-rules",
|
|
685
|
+
"version": "^1.0.0",
|
|
686
|
+
"required": true,
|
|
687
|
+
"reason": "TypeScript coding standards for the project"
|
|
688
|
+
},
|
|
689
|
+
{
|
|
690
|
+
"packageId": "react-patterns",
|
|
691
|
+
"version": "^1.0.0",
|
|
692
|
+
"required": true,
|
|
693
|
+
"reason": "React component best practices"
|
|
694
|
+
}
|
|
695
|
+
]
|
|
696
|
+
}
|
|
697
|
+
]
|
|
552
698
|
}
|
|
553
699
|
]
|
|
554
700
|
}
|