prpm 0.0.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/README.md +928 -0
- package/dist/commands/add.js +107 -0
- package/dist/commands/collections.js +409 -0
- package/dist/commands/deps.js +92 -0
- package/dist/commands/index.js +124 -0
- package/dist/commands/info.js +81 -0
- package/dist/commands/install.js +252 -0
- package/dist/commands/list.js +89 -0
- package/dist/commands/login.js +219 -0
- package/dist/commands/outdated.js +127 -0
- package/dist/commands/popular.js +27 -0
- package/dist/commands/publish.js +217 -0
- package/dist/commands/remove.js +43 -0
- package/dist/commands/search.js +179 -0
- package/dist/commands/telemetry.js +103 -0
- package/dist/commands/trending.js +75 -0
- package/dist/commands/update.js +120 -0
- package/dist/commands/upgrade.js +120 -0
- package/dist/commands/whoami.js +51 -0
- package/dist/core/config.js +91 -0
- package/dist/core/downloader.js +64 -0
- package/dist/core/filesystem.js +94 -0
- package/dist/core/lockfile.js +182 -0
- package/dist/core/registry-client.js +265 -0
- package/dist/core/telemetry.js +170 -0
- package/dist/core/user-config.js +79 -0
- package/dist/index.js +69 -0
- package/dist/types.js +5 -0
- package/package.json +67 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Add command implementation
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handleAdd = handleAdd;
|
|
7
|
+
exports.createAddCommand = createAddCommand;
|
|
8
|
+
const commander_1 = require("commander");
|
|
9
|
+
const downloader_1 = require("../core/downloader");
|
|
10
|
+
const filesystem_1 = require("../core/filesystem");
|
|
11
|
+
const config_1 = require("../core/config");
|
|
12
|
+
const telemetry_1 = require("../core/telemetry");
|
|
13
|
+
// Extract repository info from GitHub URL for popularity tracking
|
|
14
|
+
function extractRepoFromUrl(url) {
|
|
15
|
+
try {
|
|
16
|
+
// Handle raw GitHub URLs: https://raw.githubusercontent.com/user/repo/branch/path
|
|
17
|
+
const rawMatch = url.match(/raw\.githubusercontent\.com\/([^\/]+)\/([^\/]+)/);
|
|
18
|
+
if (rawMatch) {
|
|
19
|
+
return `${rawMatch[1]}/${rawMatch[2]}`;
|
|
20
|
+
}
|
|
21
|
+
// Handle regular GitHub URLs: https://github.com/user/repo
|
|
22
|
+
const githubMatch = url.match(/github\.com\/([^\/]+)\/([^\/]+)/);
|
|
23
|
+
if (githubMatch) {
|
|
24
|
+
return `${githubMatch[1]}/${githubMatch[2]}`;
|
|
25
|
+
}
|
|
26
|
+
return 'unknown';
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return 'unknown';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Add a prompt package from a URL
|
|
34
|
+
*/
|
|
35
|
+
async function handleAdd(url, type) {
|
|
36
|
+
const startTime = Date.now();
|
|
37
|
+
let success = false;
|
|
38
|
+
let error;
|
|
39
|
+
try {
|
|
40
|
+
console.log(`š„ Downloading from ${url}...`);
|
|
41
|
+
// Download the file
|
|
42
|
+
const content = await (0, downloader_1.downloadFile)(url);
|
|
43
|
+
// Extract filename and generate ID
|
|
44
|
+
const filename = (0, downloader_1.extractFilename)(url);
|
|
45
|
+
const id = (0, filesystem_1.generateId)(filename);
|
|
46
|
+
// Determine destination
|
|
47
|
+
const destDir = (0, filesystem_1.getDestinationDir)(type);
|
|
48
|
+
const destPath = `${destDir}/${filename}`;
|
|
49
|
+
// Save the file
|
|
50
|
+
console.log(`š¾ Saving to ${destPath}...`);
|
|
51
|
+
await (0, filesystem_1.saveFile)(destPath, content);
|
|
52
|
+
// Create package record
|
|
53
|
+
const pkg = {
|
|
54
|
+
id,
|
|
55
|
+
type,
|
|
56
|
+
url,
|
|
57
|
+
dest: destPath
|
|
58
|
+
};
|
|
59
|
+
// Update configuration
|
|
60
|
+
await (0, config_1.addPackage)(pkg);
|
|
61
|
+
console.log(`ā
Successfully added ${id} (${type})`);
|
|
62
|
+
console.log(` š Saved to: ${destPath}`);
|
|
63
|
+
success = true;
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
error = err instanceof Error ? err.message : String(err);
|
|
67
|
+
console.error(`ā Failed to add package: ${error}`);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
// Track telemetry
|
|
72
|
+
await telemetry_1.telemetry.track({
|
|
73
|
+
command: 'add',
|
|
74
|
+
success,
|
|
75
|
+
error,
|
|
76
|
+
duration: Date.now() - startTime,
|
|
77
|
+
data: {
|
|
78
|
+
type,
|
|
79
|
+
url: url.substring(0, 100), // Truncate long URLs
|
|
80
|
+
filename: (0, downloader_1.extractFilename)(url),
|
|
81
|
+
// Package popularity tracking
|
|
82
|
+
packageId: (0, filesystem_1.generateId)((0, downloader_1.extractFilename)(url)),
|
|
83
|
+
packageType: type,
|
|
84
|
+
sourceRepo: extractRepoFromUrl(url),
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Create the add command
|
|
91
|
+
*/
|
|
92
|
+
function createAddCommand() {
|
|
93
|
+
const command = new commander_1.Command('add');
|
|
94
|
+
command
|
|
95
|
+
.description('Add a prompt package from a URL')
|
|
96
|
+
.argument('<url>', 'Raw GitHub URL to the prompt file')
|
|
97
|
+
.option('--as <type>', 'Package type (cursor or claude)', 'cursor')
|
|
98
|
+
.action(async (url, options) => {
|
|
99
|
+
const type = options.as;
|
|
100
|
+
if (type !== 'cursor' && type !== 'claude') {
|
|
101
|
+
console.error('ā Type must be either "cursor" or "claude"');
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
await handleAdd(url, type);
|
|
105
|
+
});
|
|
106
|
+
return command;
|
|
107
|
+
}
|
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Collections command - Manage package collections
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handleCollectionsSearch = handleCollectionsSearch;
|
|
7
|
+
exports.handleCollectionsList = handleCollectionsList;
|
|
8
|
+
exports.handleCollectionInfo = handleCollectionInfo;
|
|
9
|
+
exports.handleCollectionInstall = handleCollectionInstall;
|
|
10
|
+
exports.createCollectionsCommand = createCollectionsCommand;
|
|
11
|
+
const commander_1 = require("commander");
|
|
12
|
+
const registry_client_1 = require("@prpm/registry-client");
|
|
13
|
+
const user_config_1 = require("../core/user-config");
|
|
14
|
+
const install_1 = require("./install");
|
|
15
|
+
const telemetry_1 = require("../core/telemetry");
|
|
16
|
+
/**
|
|
17
|
+
* Search collections by query
|
|
18
|
+
*/
|
|
19
|
+
async function handleCollectionsSearch(query, options) {
|
|
20
|
+
const startTime = Date.now();
|
|
21
|
+
try {
|
|
22
|
+
const config = await (0, user_config_1.getConfig)();
|
|
23
|
+
const client = (0, registry_client_1.getRegistryClient)(config);
|
|
24
|
+
console.log(`š Searching collections for "${query}"...\n`);
|
|
25
|
+
// Get all collections and filter by query
|
|
26
|
+
const result = await client.getCollections({
|
|
27
|
+
category: options.category,
|
|
28
|
+
tag: options.tag,
|
|
29
|
+
official: options.official,
|
|
30
|
+
limit: options.limit || 50,
|
|
31
|
+
});
|
|
32
|
+
// Filter collections by search query (name, description, tags)
|
|
33
|
+
const queryLower = query.toLowerCase();
|
|
34
|
+
const filtered = result.collections.filter(c => c.name.toLowerCase().includes(queryLower) ||
|
|
35
|
+
c.description.toLowerCase().includes(queryLower) ||
|
|
36
|
+
c.tags.some(tag => tag.toLowerCase().includes(queryLower)) ||
|
|
37
|
+
c.id.toLowerCase().includes(queryLower));
|
|
38
|
+
if (filtered.length === 0) {
|
|
39
|
+
console.log('No collections found matching your search.');
|
|
40
|
+
console.log('\nš” Try:');
|
|
41
|
+
console.log(' - Broadening your search terms');
|
|
42
|
+
console.log(' - Checking spelling');
|
|
43
|
+
console.log(' - Browsing all: prpm collections list');
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
console.log(`⨠Found ${filtered.length} collection(s):\n`);
|
|
47
|
+
// Group by official vs community
|
|
48
|
+
const official = filtered.filter(c => c.official);
|
|
49
|
+
const community = filtered.filter(c => !c.official);
|
|
50
|
+
if (official.length > 0) {
|
|
51
|
+
console.log('š¦ Official Collections:\n');
|
|
52
|
+
official.forEach(c => {
|
|
53
|
+
const fullName = `@${c.scope}/${c.id}`.padEnd(35);
|
|
54
|
+
const pkgCount = `(${c.package_count} packages)`.padEnd(15);
|
|
55
|
+
console.log(` ${c.icon || 'š¦'} ${fullName} ${pkgCount} ${c.name}`);
|
|
56
|
+
if (c.description) {
|
|
57
|
+
console.log(` ${c.description.substring(0, 70)}${c.description.length > 70 ? '...' : ''}`);
|
|
58
|
+
}
|
|
59
|
+
console.log(` ā¬ļø ${c.downloads.toLocaleString()} installs Ā· ā ${c.stars.toLocaleString()} stars`);
|
|
60
|
+
console.log('');
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
if (community.length > 0) {
|
|
64
|
+
console.log('\nš Community Collections:\n');
|
|
65
|
+
community.forEach(c => {
|
|
66
|
+
const fullName = `@${c.scope}/${c.id}`.padEnd(35);
|
|
67
|
+
const pkgCount = `(${c.package_count} packages)`.padEnd(15);
|
|
68
|
+
console.log(` ${c.icon || 'š¦'} ${fullName} ${pkgCount} ${c.name}`);
|
|
69
|
+
if (c.description) {
|
|
70
|
+
console.log(` ${c.description.substring(0, 70)}${c.description.length > 70 ? '...' : ''}`);
|
|
71
|
+
}
|
|
72
|
+
console.log(` ā¬ļø ${c.downloads.toLocaleString()} installs Ā· ā ${c.stars.toLocaleString()} stars`);
|
|
73
|
+
console.log('');
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
console.log(`\nš” View details: prpm collection info <collection>`);
|
|
77
|
+
console.log(`š” Install: prpm install @collection/<name>`);
|
|
78
|
+
await telemetry_1.telemetry.track({
|
|
79
|
+
command: 'collections:search',
|
|
80
|
+
success: true,
|
|
81
|
+
duration: Date.now() - startTime,
|
|
82
|
+
data: {
|
|
83
|
+
query: query.substring(0, 100),
|
|
84
|
+
count: filtered.length,
|
|
85
|
+
filters: options,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
91
|
+
console.error(`\nā Failed to search collections: ${errorMessage}`);
|
|
92
|
+
await telemetry_1.telemetry.track({
|
|
93
|
+
command: 'collections:search',
|
|
94
|
+
success: false,
|
|
95
|
+
error: errorMessage,
|
|
96
|
+
duration: Date.now() - startTime,
|
|
97
|
+
});
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* List available collections
|
|
103
|
+
*/
|
|
104
|
+
async function handleCollectionsList(options) {
|
|
105
|
+
const startTime = Date.now();
|
|
106
|
+
try {
|
|
107
|
+
const config = await (0, user_config_1.getConfig)();
|
|
108
|
+
const client = (0, registry_client_1.getRegistryClient)(config);
|
|
109
|
+
console.log('š¦ Searching collections...\n');
|
|
110
|
+
const result = await client.getCollections({
|
|
111
|
+
category: options.category,
|
|
112
|
+
tag: options.tag,
|
|
113
|
+
official: options.official,
|
|
114
|
+
scope: options.scope,
|
|
115
|
+
limit: 50,
|
|
116
|
+
});
|
|
117
|
+
if (result.collections.length === 0) {
|
|
118
|
+
console.log('No collections found matching your criteria.');
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
// Group by official vs community
|
|
122
|
+
const official = result.collections.filter(c => c.official);
|
|
123
|
+
const community = result.collections.filter(c => !c.official);
|
|
124
|
+
if (official.length > 0) {
|
|
125
|
+
console.log('š¦ Official Collections:\n');
|
|
126
|
+
official.forEach(c => {
|
|
127
|
+
const fullName = `@${c.scope}/${c.id}`.padEnd(35);
|
|
128
|
+
const pkgCount = `(${c.package_count} packages)`.padEnd(15);
|
|
129
|
+
console.log(` ${c.icon || 'š¦'} ${fullName} ${pkgCount} ${c.name}`);
|
|
130
|
+
if (c.description) {
|
|
131
|
+
console.log(` ${c.description.substring(0, 70)}${c.description.length > 70 ? '...' : ''}`);
|
|
132
|
+
}
|
|
133
|
+
console.log(` ā¬ļø ${c.downloads.toLocaleString()} installs Ā· ā ${c.stars.toLocaleString()} stars`);
|
|
134
|
+
console.log('');
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
if (community.length > 0) {
|
|
138
|
+
console.log('\nš Community Collections:\n');
|
|
139
|
+
community.forEach(c => {
|
|
140
|
+
const fullName = `@${c.scope}/${c.id}`.padEnd(35);
|
|
141
|
+
const pkgCount = `(${c.package_count} packages)`.padEnd(15);
|
|
142
|
+
console.log(` ${c.icon || 'š¦'} ${fullName} ${pkgCount} ${c.name}`);
|
|
143
|
+
if (c.description) {
|
|
144
|
+
console.log(` ${c.description.substring(0, 70)}${c.description.length > 70 ? '...' : ''}`);
|
|
145
|
+
}
|
|
146
|
+
console.log(` ā¬ļø ${c.downloads.toLocaleString()} installs Ā· ā ${c.stars.toLocaleString()} stars`);
|
|
147
|
+
console.log('');
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
console.log(`\nš” View details: prpm collection info <collection>`);
|
|
151
|
+
console.log(`š” Install: prpm install @collection/<name>`);
|
|
152
|
+
await telemetry_1.telemetry.track({
|
|
153
|
+
command: 'collections:list',
|
|
154
|
+
success: true,
|
|
155
|
+
duration: Date.now() - startTime,
|
|
156
|
+
data: {
|
|
157
|
+
count: result.collections.length,
|
|
158
|
+
filters: options,
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
164
|
+
console.error(`\nā Failed to list collections: ${errorMessage}`);
|
|
165
|
+
await telemetry_1.telemetry.track({
|
|
166
|
+
command: 'collections:list',
|
|
167
|
+
success: false,
|
|
168
|
+
error: errorMessage,
|
|
169
|
+
duration: Date.now() - startTime,
|
|
170
|
+
});
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Show collection details
|
|
176
|
+
*/
|
|
177
|
+
async function handleCollectionInfo(collectionSpec) {
|
|
178
|
+
const startTime = Date.now();
|
|
179
|
+
try {
|
|
180
|
+
// Parse collection spec: @scope/id or scope/id
|
|
181
|
+
const match = collectionSpec.match(/^@?([^/]+)\/([^/@]+)(?:@(.+))?$/);
|
|
182
|
+
if (!match) {
|
|
183
|
+
throw new Error('Invalid collection format. Use: @scope/id or scope/id[@version]');
|
|
184
|
+
}
|
|
185
|
+
const [, scope, id, version] = match;
|
|
186
|
+
const config = await (0, user_config_1.getConfig)();
|
|
187
|
+
const client = (0, registry_client_1.getRegistryClient)(config);
|
|
188
|
+
console.log(`š¦ Loading collection: @${scope}/${id}...\n`);
|
|
189
|
+
const collection = await client.getCollection(scope, id, version);
|
|
190
|
+
// Header
|
|
191
|
+
console.log(`${collection.icon || 'š¦'} ${collection.name}`);
|
|
192
|
+
console.log(`${'='.repeat(collection.name.length + 2)}`);
|
|
193
|
+
console.log('');
|
|
194
|
+
console.log(collection.description);
|
|
195
|
+
console.log('');
|
|
196
|
+
// Stats
|
|
197
|
+
console.log('š Stats:');
|
|
198
|
+
console.log(` Downloads: ${collection.downloads.toLocaleString()}`);
|
|
199
|
+
console.log(` Stars: ${collection.stars.toLocaleString()}`);
|
|
200
|
+
console.log(` Version: ${collection.version}`);
|
|
201
|
+
console.log(` Packages: ${collection.packages.length}`);
|
|
202
|
+
console.log(` Author: ${collection.author}${collection.verified ? ' ā' : ''}`);
|
|
203
|
+
if (collection.category) {
|
|
204
|
+
console.log(` Category: ${collection.category}`);
|
|
205
|
+
}
|
|
206
|
+
if (collection.tags && collection.tags.length > 0) {
|
|
207
|
+
console.log(` Tags: ${collection.tags.join(', ')}`);
|
|
208
|
+
}
|
|
209
|
+
console.log('');
|
|
210
|
+
// Packages
|
|
211
|
+
console.log('š Included Packages:');
|
|
212
|
+
console.log('');
|
|
213
|
+
const requiredPkgs = collection.packages.filter(p => p.required);
|
|
214
|
+
const optionalPkgs = collection.packages.filter(p => !p.required);
|
|
215
|
+
if (requiredPkgs.length > 0) {
|
|
216
|
+
console.log(' Required:');
|
|
217
|
+
requiredPkgs.forEach((pkg, i) => {
|
|
218
|
+
console.log(` ${i + 1}. ā ${pkg.packageId}@${pkg.version || 'latest'}`);
|
|
219
|
+
if (pkg.package) {
|
|
220
|
+
console.log(` ${pkg.package.description || pkg.package.display_name}`);
|
|
221
|
+
}
|
|
222
|
+
if (pkg.reason) {
|
|
223
|
+
console.log(` š” ${pkg.reason}`);
|
|
224
|
+
}
|
|
225
|
+
console.log('');
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
if (optionalPkgs.length > 0) {
|
|
229
|
+
console.log(' Optional:');
|
|
230
|
+
optionalPkgs.forEach((pkg, i) => {
|
|
231
|
+
console.log(` ${i + 1}. ā ${pkg.packageId}@${pkg.version || 'latest'}`);
|
|
232
|
+
if (pkg.package) {
|
|
233
|
+
console.log(` ${pkg.package.description || pkg.package.display_name}`);
|
|
234
|
+
}
|
|
235
|
+
if (pkg.reason) {
|
|
236
|
+
console.log(` š” ${pkg.reason}`);
|
|
237
|
+
}
|
|
238
|
+
console.log('');
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
// Installation
|
|
242
|
+
console.log('š” Install:');
|
|
243
|
+
console.log(` prpm install @${scope}/${id}`);
|
|
244
|
+
if (optionalPkgs.length > 0) {
|
|
245
|
+
console.log(` prpm install @${scope}/${id} --skip-optional # Skip optional packages`);
|
|
246
|
+
}
|
|
247
|
+
console.log('');
|
|
248
|
+
await telemetry_1.telemetry.track({
|
|
249
|
+
command: 'collections:info',
|
|
250
|
+
success: true,
|
|
251
|
+
duration: Date.now() - startTime,
|
|
252
|
+
data: {
|
|
253
|
+
scope,
|
|
254
|
+
id,
|
|
255
|
+
packageCount: collection.packages.length,
|
|
256
|
+
},
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
catch (error) {
|
|
260
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
261
|
+
console.error(`\nā Failed to get collection info: ${errorMessage}`);
|
|
262
|
+
await telemetry_1.telemetry.track({
|
|
263
|
+
command: 'collections:info',
|
|
264
|
+
success: false,
|
|
265
|
+
error: errorMessage,
|
|
266
|
+
duration: Date.now() - startTime,
|
|
267
|
+
});
|
|
268
|
+
process.exit(1);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Install a collection
|
|
273
|
+
*/
|
|
274
|
+
async function handleCollectionInstall(collectionSpec, options) {
|
|
275
|
+
const startTime = Date.now();
|
|
276
|
+
let packagesInstalled = 0;
|
|
277
|
+
let packagesFailed = 0;
|
|
278
|
+
try {
|
|
279
|
+
// Parse collection spec
|
|
280
|
+
const match = collectionSpec.match(/^@?([^/]+)\/([^/@]+)(?:@(.+))?$/);
|
|
281
|
+
if (!match) {
|
|
282
|
+
throw new Error('Invalid collection format. Use: @scope/id or scope/id[@version]');
|
|
283
|
+
}
|
|
284
|
+
const [, scope, id, version] = match;
|
|
285
|
+
const config = await (0, user_config_1.getConfig)();
|
|
286
|
+
const client = (0, registry_client_1.getRegistryClient)(config);
|
|
287
|
+
// Get collection installation plan
|
|
288
|
+
console.log(`š¦ Installing collection: @${scope}/${id}...\n`);
|
|
289
|
+
const installResult = await client.installCollection({
|
|
290
|
+
scope,
|
|
291
|
+
id,
|
|
292
|
+
version,
|
|
293
|
+
format: options.format,
|
|
294
|
+
skipOptional: options.skipOptional,
|
|
295
|
+
});
|
|
296
|
+
const collection = installResult.collection;
|
|
297
|
+
const packages = installResult.packagesToInstall;
|
|
298
|
+
console.log(`š¦ ${collection.name}`);
|
|
299
|
+
console.log(` ${packages.length} packages to install\n`);
|
|
300
|
+
if (options.dryRun) {
|
|
301
|
+
console.log('š Dry run - would install:\n');
|
|
302
|
+
packages.forEach((pkg, i) => {
|
|
303
|
+
const required = pkg.required ? 'ā' : 'ā';
|
|
304
|
+
console.log(` ${i + 1}/${packages.length} ${required} ${pkg.packageId}@${pkg.version} (${pkg.format})`);
|
|
305
|
+
});
|
|
306
|
+
console.log('');
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
// Install packages sequentially
|
|
310
|
+
for (let i = 0; i < packages.length; i++) {
|
|
311
|
+
const pkg = packages[i];
|
|
312
|
+
const progress = `${i + 1}/${packages.length}`;
|
|
313
|
+
try {
|
|
314
|
+
console.log(`\n ${progress} Installing ${pkg.packageId}@${pkg.version}...`);
|
|
315
|
+
await (0, install_1.handleInstall)(`${pkg.packageId}@${pkg.version}`, {
|
|
316
|
+
as: pkg.format,
|
|
317
|
+
});
|
|
318
|
+
console.log(` ${progress} ā ${pkg.packageId}`);
|
|
319
|
+
packagesInstalled++;
|
|
320
|
+
}
|
|
321
|
+
catch (error) {
|
|
322
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
323
|
+
console.error(` ${progress} ā ${pkg.packageId}: ${errorMessage}`);
|
|
324
|
+
packagesFailed++;
|
|
325
|
+
if (pkg.required) {
|
|
326
|
+
throw new Error(`Failed to install required package: ${pkg.packageId}`);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
console.log(`\nā
Collection installed successfully!`);
|
|
331
|
+
console.log(` ${packagesInstalled}/${packages.length} packages installed`);
|
|
332
|
+
if (packagesFailed > 0) {
|
|
333
|
+
console.log(` ${packagesFailed} optional packages failed`);
|
|
334
|
+
}
|
|
335
|
+
console.log('');
|
|
336
|
+
await telemetry_1.telemetry.track({
|
|
337
|
+
command: 'collections:install',
|
|
338
|
+
success: true,
|
|
339
|
+
duration: Date.now() - startTime,
|
|
340
|
+
data: {
|
|
341
|
+
scope,
|
|
342
|
+
id,
|
|
343
|
+
packageCount: packages.length,
|
|
344
|
+
installed: packagesInstalled,
|
|
345
|
+
failed: packagesFailed,
|
|
346
|
+
format: options.format,
|
|
347
|
+
},
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
catch (error) {
|
|
351
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
352
|
+
console.error(`\nā Failed to install collection: ${errorMessage}`);
|
|
353
|
+
await telemetry_1.telemetry.track({
|
|
354
|
+
command: 'collections:install',
|
|
355
|
+
success: false,
|
|
356
|
+
error: errorMessage,
|
|
357
|
+
duration: Date.now() - startTime,
|
|
358
|
+
data: {
|
|
359
|
+
installed: packagesInstalled,
|
|
360
|
+
failed: packagesFailed,
|
|
361
|
+
},
|
|
362
|
+
});
|
|
363
|
+
process.exit(1);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Create collections command group
|
|
368
|
+
*/
|
|
369
|
+
function createCollectionsCommand() {
|
|
370
|
+
const command = new commander_1.Command('collections');
|
|
371
|
+
command
|
|
372
|
+
.description('Manage package collections')
|
|
373
|
+
.alias('collection')
|
|
374
|
+
.action(async (options) => {
|
|
375
|
+
await handleCollectionsList(options);
|
|
376
|
+
});
|
|
377
|
+
// Search subcommand
|
|
378
|
+
command
|
|
379
|
+
.command('search <query>')
|
|
380
|
+
.description('Search for collections')
|
|
381
|
+
.option('--category <category>', 'Filter by category')
|
|
382
|
+
.option('--tag <tag>', 'Filter by tag')
|
|
383
|
+
.option('--official', 'Show only official collections')
|
|
384
|
+
.option('--limit <number>', 'Number of results to show', '50')
|
|
385
|
+
.action(async (query, options) => {
|
|
386
|
+
await handleCollectionsSearch(query, {
|
|
387
|
+
category: options.category,
|
|
388
|
+
tag: options.tag,
|
|
389
|
+
official: options.official,
|
|
390
|
+
limit: parseInt(options.limit, 10),
|
|
391
|
+
});
|
|
392
|
+
});
|
|
393
|
+
// List subcommand
|
|
394
|
+
command
|
|
395
|
+
.command('list')
|
|
396
|
+
.description('List available collections')
|
|
397
|
+
.option('--category <category>', 'Filter by category')
|
|
398
|
+
.option('--tag <tag>', 'Filter by tag')
|
|
399
|
+
.option('--official', 'Show only official collections')
|
|
400
|
+
.option('--scope <scope>', 'Filter by scope')
|
|
401
|
+
.action(handleCollectionsList);
|
|
402
|
+
// Info subcommand
|
|
403
|
+
command
|
|
404
|
+
.command('info <collection>')
|
|
405
|
+
.description('Show collection details')
|
|
406
|
+
.action(handleCollectionInfo);
|
|
407
|
+
// Install handled by main install command with @scope/id syntax
|
|
408
|
+
return command;
|
|
409
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Deps command - Show dependency tree for a package
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handleDeps = handleDeps;
|
|
7
|
+
exports.createDepsCommand = createDepsCommand;
|
|
8
|
+
const commander_1 = require("commander");
|
|
9
|
+
const registry_client_1 = require("@prpm/registry-client");
|
|
10
|
+
const user_config_1 = require("../core/user-config");
|
|
11
|
+
const telemetry_1 = require("../core/telemetry");
|
|
12
|
+
/**
|
|
13
|
+
* Display dependency tree
|
|
14
|
+
*/
|
|
15
|
+
async function handleDeps(packageSpec) {
|
|
16
|
+
const startTime = Date.now();
|
|
17
|
+
let success = false;
|
|
18
|
+
let error;
|
|
19
|
+
try {
|
|
20
|
+
// Parse package spec
|
|
21
|
+
const [packageId, version] = packageSpec.split('@');
|
|
22
|
+
console.log(`š¦ Resolving dependencies for ${packageId}${version ? `@${version}` : ''}...\n`);
|
|
23
|
+
const config = await (0, user_config_1.getConfig)();
|
|
24
|
+
const client = (0, registry_client_1.getRegistryClient)(config);
|
|
25
|
+
// Resolve dependency tree
|
|
26
|
+
const result = await client.resolveDependencies(packageId, version);
|
|
27
|
+
if (Object.keys(result.resolved).length === 1) {
|
|
28
|
+
console.log('ā
No dependencies\n');
|
|
29
|
+
success = true;
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
// Display resolved versions
|
|
33
|
+
console.log('š Resolved Dependencies:\n');
|
|
34
|
+
for (const [pkgId, pkgVersion] of Object.entries(result.resolved)) {
|
|
35
|
+
if (pkgId === packageId)
|
|
36
|
+
continue; // Skip root package
|
|
37
|
+
console.log(` ${pkgId}@${pkgVersion}`);
|
|
38
|
+
}
|
|
39
|
+
console.log(`\nš Total: ${Object.keys(result.resolved).length - 1} dependencies\n`);
|
|
40
|
+
// Display tree structure
|
|
41
|
+
console.log('š³ Dependency Tree:\n');
|
|
42
|
+
printTree(result.tree, packageId, '', true);
|
|
43
|
+
success = true;
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
error = err instanceof Error ? err.message : String(err);
|
|
47
|
+
console.error(`\nā Failed to resolve dependencies: ${error}`);
|
|
48
|
+
if (error.includes('Circular dependency')) {
|
|
49
|
+
console.log(`\nš” Tip: This package has a circular dependency which is not allowed.`);
|
|
50
|
+
}
|
|
51
|
+
else if (error.includes('not found')) {
|
|
52
|
+
console.log(`\nš” Tip: Check the package name and version are correct.`);
|
|
53
|
+
}
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
await telemetry_1.telemetry.track({
|
|
58
|
+
command: 'deps',
|
|
59
|
+
success,
|
|
60
|
+
error,
|
|
61
|
+
duration: Date.now() - startTime,
|
|
62
|
+
data: {
|
|
63
|
+
packageId: packageSpec.split('@')[0],
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Print dependency tree recursively
|
|
70
|
+
*/
|
|
71
|
+
function printTree(tree, packageId, prefix = '', isLast = true) {
|
|
72
|
+
const node = tree[packageId];
|
|
73
|
+
if (!node)
|
|
74
|
+
return;
|
|
75
|
+
const deps = node.dependencies || {};
|
|
76
|
+
const depKeys = Object.keys(deps);
|
|
77
|
+
console.log(`${prefix}${isLast ? 'āā' : 'āā'} ${packageId}@${node.version}`);
|
|
78
|
+
depKeys.forEach((depId, index) => {
|
|
79
|
+
const isLastDep = index === depKeys.length - 1;
|
|
80
|
+
const newPrefix = prefix + (isLast ? ' ' : 'ā ');
|
|
81
|
+
printTree(tree, depId, newPrefix, isLastDep);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Create the deps command
|
|
86
|
+
*/
|
|
87
|
+
function createDepsCommand() {
|
|
88
|
+
return new commander_1.Command('deps')
|
|
89
|
+
.description('Show dependency tree for a package')
|
|
90
|
+
.argument('<package>', 'Package to analyze (e.g., react-rules or react-rules@1.2.0)')
|
|
91
|
+
.action(handleDeps);
|
|
92
|
+
}
|