prpm 0.0.1 → 0.0.2

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.
@@ -2,6 +2,39 @@
2
2
  /**
3
3
  * Search command - Search for packages in the registry
4
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
+ })();
5
38
  Object.defineProperty(exports, "__esModule", { value: true });
6
39
  exports.handleSearch = handleSearch;
7
40
  exports.createSearchCommand = createSearchCommand;
@@ -9,6 +42,7 @@ const commander_1 = require("commander");
9
42
  const registry_client_1 = require("@prpm/registry-client");
10
43
  const user_config_1 = require("../core/user-config");
11
44
  const telemetry_1 = require("../core/telemetry");
45
+ const readline = __importStar(require("readline"));
12
46
  /**
13
47
  * Get icon for package type
14
48
  */
@@ -16,6 +50,9 @@ function getTypeIcon(type) {
16
50
  const icons = {
17
51
  skill: 'šŸŽ“',
18
52
  agent: 'šŸ¤–',
53
+ command: '⚔',
54
+ 'slash-command': '⚔',
55
+ 'claude-slash-command': '⚔',
19
56
  rule: 'šŸ“‹',
20
57
  plugin: 'šŸ”Œ',
21
58
  prompt: 'šŸ’¬',
@@ -33,6 +70,10 @@ function getTypeLabel(type) {
33
70
  const labels = {
34
71
  skill: 'Skill',
35
72
  agent: 'Agent',
73
+ command: 'Slash Command',
74
+ 'slash-command': 'Slash Command',
75
+ 'claude-slash-command': 'Slash Command',
76
+ 'claude-agent': 'Agent',
36
77
  rule: 'Rule',
37
78
  plugin: 'Plugin',
38
79
  prompt: 'Prompt',
@@ -49,9 +90,14 @@ function getTypeLabel(type) {
49
90
  function mapTypeToRegistry(cliType) {
50
91
  const typeMap = {
51
92
  rule: { type: 'cursor', tags: ['cursor-rule'] },
52
- skill: { type: 'claude', tags: ['claude-skill'] },
53
- agent: { type: 'claude' },
54
- mcp: { type: 'generic', tags: ['mcp', 'mcp-server'] },
93
+ // Skills are packages with type=claude-skill
94
+ skill: { type: 'claude-skill' },
95
+ // Agents are packages with type=claude-agent or claude (not claude-skill)
96
+ agent: { type: 'claude-agent' },
97
+ // Slash commands are packages with type=claude-slash-command
98
+ command: { type: 'claude-slash-command' },
99
+ 'slash-command': { type: 'claude-slash-command' },
100
+ mcp: { type: 'mcp' },
55
101
  plugin: { type: 'generic', tags: ['plugin'] },
56
102
  prompt: { type: 'generic', tags: ['prompt'] },
57
103
  workflow: { type: 'generic', tags: ['workflow'] },
@@ -60,32 +106,183 @@ function mapTypeToRegistry(cliType) {
60
106
  };
61
107
  return typeMap[cliType] || {};
62
108
  }
109
+ /**
110
+ * Build webapp URL for search results
111
+ */
112
+ function buildWebappUrl(query, options, page = 1) {
113
+ const baseUrl = process.env.PRPM_WEBAPP_URL || 'https://prpm.dev';
114
+ const params = new URLSearchParams();
115
+ if (query)
116
+ params.append('q', query);
117
+ if (options.type)
118
+ params.append('type', options.type);
119
+ if (options.author)
120
+ params.append('author', options.author);
121
+ if (page > 1)
122
+ params.append('page', page.toString());
123
+ return `${baseUrl}/search?${params.toString()}`;
124
+ }
125
+ /**
126
+ * Display search results
127
+ */
128
+ function displayResults(packages, total, page, limit) {
129
+ const startIdx = (page - 1) * limit + 1;
130
+ const endIdx = Math.min(page * limit, total);
131
+ console.log('\n' + '─'.repeat(80));
132
+ console.log(`šŸ“¦ Results ${startIdx}-${endIdx} of ${total}`.padEnd(80));
133
+ console.log('─'.repeat(80) + '\n');
134
+ packages.forEach((pkg, idx) => {
135
+ const num = startIdx + idx;
136
+ const rating = pkg.rating_average ? `⭐ ${pkg.rating_average.toFixed(1)}` : '';
137
+ const downloads = pkg.total_downloads >= 1000
138
+ ? `${(pkg.total_downloads / 1000).toFixed(1)}k`
139
+ : pkg.total_downloads;
140
+ const typeIcon = getTypeIcon(pkg.type);
141
+ const typeLabel = getTypeLabel(pkg.type);
142
+ // Add verified badge
143
+ let verifiedBadge = '';
144
+ if (pkg.featured || pkg.official || pkg.verified) {
145
+ verifiedBadge = ' | āœ… Verified';
146
+ }
147
+ console.log(`\x1b[1m${num}. ${pkg.name}\x1b[0m ${rating}`);
148
+ console.log(` ${pkg.description || 'No description'}`);
149
+ console.log(` ${typeIcon} ${typeLabel} | šŸ“„ ${downloads} downloads | šŸ·ļø ${pkg.tags.slice(0, 3).join(', ')}${verifiedBadge}`);
150
+ console.log();
151
+ });
152
+ console.log('─'.repeat(80));
153
+ }
154
+ /**
155
+ * Prompt user for pagination action
156
+ */
157
+ function promptUser() {
158
+ return new Promise((resolve) => {
159
+ const rl = readline.createInterface({
160
+ input: process.stdin,
161
+ output: process.stdout,
162
+ });
163
+ rl.question('', (answer) => {
164
+ rl.close();
165
+ resolve(answer.trim().toLowerCase());
166
+ });
167
+ });
168
+ }
169
+ /**
170
+ * Interactive pagination handler
171
+ */
172
+ async function handlePagination(query, options, client, searchOptions, initialResult, webappBaseUrl) {
173
+ let currentPage = 1;
174
+ let result = initialResult;
175
+ const totalPages = Math.ceil(result.total / options.limit);
176
+ while (true) {
177
+ // Display current page
178
+ displayResults(result.packages, result.total, currentPage, options.limit);
179
+ // Show navigation options
180
+ console.log('\nšŸ’” \x1b[1mOptions:\x1b[0m');
181
+ if (currentPage < totalPages) {
182
+ console.log(' \x1b[36mn\x1b[0m - Next page');
183
+ }
184
+ if (currentPage > 1) {
185
+ console.log(' \x1b[36mp\x1b[0m - Previous page');
186
+ }
187
+ console.log(' \x1b[36m1-' + result.packages.length + '\x1b[0m - Install package by number');
188
+ console.log(' \x1b[36mw\x1b[0m - View in web browser');
189
+ console.log(' \x1b[36mq\x1b[0m - Quit');
190
+ // Show webapp link
191
+ const webappUrl = buildWebappUrl(query, options, currentPage);
192
+ console.log(`\n🌐 \x1b[2mView in browser: ${webappUrl}\x1b[0m`);
193
+ process.stdout.write('\nšŸ‘‰ ');
194
+ const input = await promptUser();
195
+ if (input === 'q' || input === 'quit' || input === 'exit') {
196
+ console.log('\n✨ Happy coding!\n');
197
+ break;
198
+ }
199
+ if (input === 'n' || input === 'next') {
200
+ if (currentPage < totalPages) {
201
+ currentPage++;
202
+ const offset = (currentPage - 1) * options.limit;
203
+ result = await client.search(query || '', { ...searchOptions, offset });
204
+ console.clear();
205
+ }
206
+ else {
207
+ console.log('\nāŒ Already on last page');
208
+ await new Promise(resolve => setTimeout(resolve, 1000));
209
+ console.clear();
210
+ }
211
+ continue;
212
+ }
213
+ if (input === 'p' || input === 'prev' || input === 'previous') {
214
+ if (currentPage > 1) {
215
+ currentPage--;
216
+ const offset = (currentPage - 1) * options.limit;
217
+ result = await client.search(query || '', { ...searchOptions, offset });
218
+ console.clear();
219
+ }
220
+ else {
221
+ console.log('\nāŒ Already on first page');
222
+ await new Promise(resolve => setTimeout(resolve, 1000));
223
+ console.clear();
224
+ }
225
+ continue;
226
+ }
227
+ if (input === 'w' || input === 'web' || input === 'browser') {
228
+ const url = buildWebappUrl(query, options, currentPage);
229
+ console.log(`\n🌐 Opening: ${url}`);
230
+ console.log(' (Copy and paste this URL into your browser)\n');
231
+ await new Promise(resolve => setTimeout(resolve, 2000));
232
+ console.clear();
233
+ continue;
234
+ }
235
+ // Check if input is a number for installation
236
+ const num = parseInt(input, 10);
237
+ if (!isNaN(num) && num >= 1 && num <= result.packages.length) {
238
+ const pkg = result.packages[num - 1];
239
+ console.log(`\nšŸ“¦ To install: \x1b[36mprpm install ${pkg.name}\x1b[0m`);
240
+ console.log(` More info: \x1b[36mprpm info ${pkg.name}\x1b[0m\n`);
241
+ await new Promise(resolve => setTimeout(resolve, 2000));
242
+ console.clear();
243
+ continue;
244
+ }
245
+ console.log('\nāŒ Invalid option. Try again.');
246
+ await new Promise(resolve => setTimeout(resolve, 1000));
247
+ console.clear();
248
+ }
249
+ }
63
250
  async function handleSearch(query, options) {
64
251
  const startTime = Date.now();
65
252
  let success = false;
66
253
  let error;
67
254
  let result = null;
255
+ let registryUrl = '';
68
256
  try {
69
- // Allow empty query when filtering by type
257
+ // Allow empty query when filtering by type or author
70
258
  if (query) {
71
259
  console.log(`šŸ” Searching for "${query}"...`);
72
260
  }
73
261
  else if (options.type) {
74
262
  console.log(`šŸ” Listing ${options.type} packages...`);
75
263
  }
264
+ else if (options.author) {
265
+ console.log(`šŸ” Listing packages by @${options.author}...`);
266
+ }
76
267
  else {
77
- console.log('āŒ Please provide a search query or use --type to filter by package type');
268
+ console.log('āŒ Please provide a search query or use --type/--author to filter');
78
269
  console.log('\nšŸ’” Examples:');
79
270
  console.log(' prpm search react');
80
271
  console.log(' prpm search --type skill');
272
+ console.log(' prpm search --author prpm');
81
273
  console.log(' prpm search react --type rule');
82
274
  return;
83
275
  }
84
276
  const config = await (0, user_config_1.getConfig)();
277
+ registryUrl = config.registryUrl || 'https://registry.prpm.dev';
85
278
  const client = (0, registry_client_1.getRegistryClient)(config);
86
279
  // Map CLI type to registry schema
280
+ const limit = options.limit || 20;
281
+ const page = options.page || 1;
282
+ const offset = (page - 1) * limit;
87
283
  const searchOptions = {
88
- limit: options.limit || 20,
284
+ limit,
285
+ offset,
89
286
  };
90
287
  if (options.type) {
91
288
  const mapped = mapTypeToRegistry(options.type);
@@ -96,47 +293,62 @@ async function handleSearch(query, options) {
96
293
  searchOptions.tags = mapped.tags;
97
294
  }
98
295
  }
296
+ if (options.author) {
297
+ searchOptions.author = options.author;
298
+ }
99
299
  result = await client.search(query || '', searchOptions);
100
- if (result.packages.length === 0) {
300
+ if (!result || result.packages.length === 0) {
101
301
  console.log('\nāŒ No packages found');
102
302
  console.log(`\nTry:`);
103
303
  console.log(` - Broadening your search terms`);
104
304
  console.log(` - Checking spelling`);
105
305
  console.log(` - Browsing trending: prpm trending`);
306
+ // Suggest webapp even if no results
307
+ const webappUrl = buildWebappUrl(query, options);
308
+ console.log(`\n🌐 View in browser: ${webappUrl}`);
106
309
  return;
107
310
  }
108
- console.log(`\n✨ Found ${result.total} package(s):\n`);
109
- // Display results
110
- result.packages.forEach((pkg) => {
111
- const badges = [];
112
- if (pkg.featured || pkg.official)
113
- badges.push('Official');
114
- if (pkg.verified && !pkg.featured && !pkg.official)
115
- badges.push('Verified');
116
- const badgeStr = badges.length > 0 ? `[${badges.join(', ')}] ` : '';
117
- const rating = pkg.rating_average ? `⭐ ${pkg.rating_average.toFixed(1)}` : '';
118
- const downloads = pkg.total_downloads >= 1000
119
- ? `${(pkg.total_downloads / 1000).toFixed(1)}k`
120
- : pkg.total_downloads;
121
- const typeIcon = getTypeIcon(pkg.type);
122
- const typeLabel = getTypeLabel(pkg.type);
123
- console.log(`${badgeStr}${pkg.display_name} ${rating}`);
124
- console.log(` ${pkg.description || 'No description'}`);
125
- console.log(` šŸ“¦ ${pkg.id} | ${typeIcon} ${typeLabel} | šŸ“„ ${downloads} | šŸ·ļø ${pkg.tags.slice(0, 3).join(', ')}`);
311
+ // If interactive mode is disabled or only one page, show simple results
312
+ const totalPages = Math.ceil(result.total / limit);
313
+ const shouldPaginate = options.interactive !== false && totalPages > 1;
314
+ if (!shouldPaginate) {
315
+ displayResults(result.packages, result.total, page, limit);
316
+ console.log('\nšŸ’” \x1b[1mQuick Actions:\x1b[0m');
317
+ console.log(' Install: \x1b[36mprpm install <package-id>\x1b[0m');
318
+ console.log(' More info: \x1b[36mprpm info <package-id>\x1b[0m');
319
+ if (totalPages > 1) {
320
+ console.log(`\nšŸ“„ \x1b[1mMore Results:\x1b[0m`);
321
+ console.log(` Page ${page} of ${totalPages}`);
322
+ if (page < totalPages) {
323
+ console.log(` Next page: \x1b[36mprpm search "${query}" --page ${page + 1}\x1b[0m`);
324
+ }
325
+ console.log(` Interactive mode: \x1b[36mprpm search "${query}" --interactive\x1b[0m`);
326
+ }
327
+ // Always show webapp link
328
+ const webappUrl = buildWebappUrl(query, options, page);
329
+ console.log(`\n🌐 \x1b[1mView in Browser:\x1b[0m`);
330
+ console.log(` ${webappUrl}`);
331
+ if (page < totalPages) {
332
+ const nextPageUrl = buildWebappUrl(query, options, page + 1);
333
+ console.log(` Next page: ${nextPageUrl}`);
334
+ }
126
335
  console.log();
127
- });
128
- console.log(`\nšŸ’” Install a package: prpm install <package-id>`);
129
- console.log(` Get more info: prpm info <package-id>`);
130
- if (result.total > result.packages.length) {
131
- console.log(`\n Showing ${result.packages.length} of ${result.total} results`);
336
+ }
337
+ else {
338
+ // Interactive pagination mode
339
+ await handlePagination(query, { ...options, limit }, client, searchOptions, result, registryUrl);
132
340
  }
133
341
  success = true;
134
342
  }
135
343
  catch (err) {
136
344
  error = err instanceof Error ? err.message : String(err);
137
345
  console.error(`\nāŒ Search failed: ${error}`);
138
- console.log(`\nšŸ’” Tip: Make sure you have internet connection`);
139
- console.log(` Registry: ${process.env.PRPM_REGISTRY_URL || 'https://registry.prpm.dev'}`);
346
+ console.log(` Registry: ${registryUrl}`);
347
+ // Provide helpful hint if using localhost
348
+ if (registryUrl.includes('localhost')) {
349
+ console.log(`\nšŸ’” Tip: You're using a local registry. Make sure it's running or update ~/.prpmrc`);
350
+ console.log(` To use the production registry, remove the registryUrl from ~/.prpmrc`);
351
+ }
140
352
  process.exit(1);
141
353
  }
142
354
  finally {
@@ -149,31 +361,44 @@ async function handleSearch(query, options) {
149
361
  query: query.substring(0, 100),
150
362
  type: options.type,
151
363
  resultCount: success && result ? result.packages.length : 0,
364
+ page: options.page,
365
+ interactive: options.interactive,
152
366
  },
153
367
  });
368
+ // Ensure telemetry is flushed before exit
369
+ await telemetry_1.telemetry.shutdown();
154
370
  }
155
371
  }
156
372
  function createSearchCommand() {
157
373
  const command = new commander_1.Command('search');
158
374
  command
159
375
  .description('Search for packages in the registry')
160
- .argument('[query]', 'Search query (optional when using --type)')
161
- .option('--type <type>', 'Filter by package type (skill, agent, rule, plugin, prompt, workflow, tool, template, mcp)')
162
- .option('--limit <number>', 'Number of results to show', '20')
376
+ .argument('[query]', 'Search query (optional when using --type or --author)')
377
+ .option('--type <type>', 'Filter by package type (skill, agent, command, slash-command, rule, plugin, prompt, workflow, tool, template, mcp)')
378
+ .option('--author <username>', 'Filter by author username')
379
+ .option('--limit <number>', 'Number of results per page', '20')
380
+ .option('--page <number>', 'Page number (default: 1)', '1')
381
+ .option('--interactive', 'Enable interactive pagination (default: true for multiple pages)', true)
382
+ .option('--no-interactive', 'Disable interactive pagination')
163
383
  .action(async (query, options) => {
164
384
  const type = options.type;
165
- const limit = parseInt(options.limit, 10);
166
- const validTypes = ['skill', 'agent', 'rule', 'plugin', 'prompt', 'workflow', 'tool', 'template', 'mcp'];
385
+ const author = options.author;
386
+ const limit = options.limit ? parseInt(options.limit, 10) : 20;
387
+ const page = options.page ? parseInt(options.page, 10) : 1;
388
+ const validTypes = ['skill', 'agent', 'command', 'slash-command', 'rule', 'plugin', 'prompt', 'workflow', 'tool', 'template', 'mcp'];
167
389
  if (options.type && !validTypes.includes(type)) {
168
390
  console.error(`āŒ Type must be one of: ${validTypes.join(', ')}`);
169
391
  console.log(`\nšŸ’” Examples:`);
170
392
  console.log(` prpm search postgres --type skill`);
171
393
  console.log(` prpm search debugging --type agent`);
394
+ console.log(` prpm search refactor --type command`);
172
395
  console.log(` prpm search react --type rule`);
396
+ console.log(` prpm search --type command # List all slash commands`);
173
397
  console.log(` prpm search --type skill # List all skills`);
398
+ console.log(` prpm search --author prpm # List packages by @prpm`);
174
399
  process.exit(1);
175
400
  }
176
- await handleSearch(query || '', { type, limit });
401
+ await handleSearch(query || '', { type, author, limit, page, interactive: options.interactive });
177
402
  });
178
403
  return command;
179
404
  }
@@ -29,9 +29,9 @@ async function handleTrending(options) {
29
29
  const downloads = pkg.total_downloads >= 1000
30
30
  ? `${(pkg.total_downloads / 1000).toFixed(1)}k`
31
31
  : pkg.total_downloads;
32
- console.log(`${index + 1}. [${verified}] ${pkg.display_name} ${rating}`);
32
+ console.log(`${index + 1}. [${verified}] ${pkg.name} ${rating}`);
33
33
  console.log(` ${pkg.description || 'No description'}`);
34
- console.log(` šŸ“¦ ${pkg.id} | šŸ“„ ${downloads} downloads`);
34
+ console.log(` šŸ“„ ${downloads} downloads`);
35
35
  console.log();
36
36
  });
37
37
  console.log(`šŸ’” Install a package: prpm install <package-id>`);
@@ -54,6 +54,7 @@ async function handleTrending(options) {
54
54
  limit: options.limit || 10,
55
55
  },
56
56
  });
57
+ await telemetry_1.telemetry.shutdown();
57
58
  }
58
59
  }
59
60
  function createTrendingCommand() {
@@ -64,7 +65,7 @@ function createTrendingCommand() {
64
65
  .option('--limit <number>', 'Number of packages to show', '10')
65
66
  .action(async (options) => {
66
67
  const type = options.type;
67
- const limit = parseInt(options.limit, 10);
68
+ const limit = options.limit ? parseInt(options.limit, 10) : 10;
68
69
  if (options.type && !['cursor', 'claude', 'continue', 'windsurf', 'generic'].includes(type)) {
69
70
  console.error('āŒ Type must be one of: cursor, claude, continue, windsurf, generic');
70
71
  process.exit(1);
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ /**
3
+ * Uninstall command implementation
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.handleUninstall = handleUninstall;
7
+ exports.createUninstallCommand = createUninstallCommand;
8
+ const commander_1 = require("commander");
9
+ const lockfile_1 = require("../core/lockfile");
10
+ const filesystem_1 = require("../core/filesystem");
11
+ const fs_1 = require("fs");
12
+ /**
13
+ * Handle the uninstall command
14
+ */
15
+ async function handleUninstall(name) {
16
+ try {
17
+ console.log(`šŸ—‘ļø Uninstalling package: ${name}`);
18
+ // Remove from lockfile and get package info
19
+ const pkg = await (0, lockfile_1.removePackage)(name);
20
+ if (!pkg) {
21
+ console.error(`āŒ Package "${name}" not found`);
22
+ process.exit(1);
23
+ }
24
+ // Determine file path based on package type and format
25
+ const effectiveType = (pkg.format === 'claude' ? 'claude-skill' :
26
+ pkg.format === 'cursor' ? 'cursor' :
27
+ pkg.format === 'continue' ? 'continue' :
28
+ pkg.format === 'windsurf' ? 'windsurf' :
29
+ pkg.type);
30
+ const destDir = (0, filesystem_1.getDestinationDir)(effectiveType);
31
+ const fileExtension = pkg.format === 'cursor' ? 'mdc' : 'md';
32
+ // Strip author namespace to get just the package name
33
+ const packageName = (0, filesystem_1.stripAuthorNamespace)(name);
34
+ // Try single file first
35
+ const singleFilePath = `${destDir}/${packageName}.${fileExtension}`;
36
+ if (await (0, filesystem_1.fileExists)(singleFilePath)) {
37
+ // Single file package
38
+ await (0, filesystem_1.deleteFile)(singleFilePath);
39
+ console.log(` šŸ—‘ļø Deleted file: ${singleFilePath}`);
40
+ }
41
+ else {
42
+ // Try multi-file package directory
43
+ const packageDir = `${destDir}/${packageName}`;
44
+ try {
45
+ const stats = await fs_1.promises.stat(packageDir);
46
+ if (stats.isDirectory()) {
47
+ await fs_1.promises.rm(packageDir, { recursive: true, force: true });
48
+ console.log(` šŸ—‘ļø Deleted directory: ${packageDir}`);
49
+ }
50
+ }
51
+ catch (error) {
52
+ const err = error;
53
+ if (err.code !== 'ENOENT') {
54
+ console.warn(` āš ļø Could not delete package files: ${err.message}`);
55
+ }
56
+ }
57
+ }
58
+ console.log(`āœ… Successfully uninstalled ${name}`);
59
+ process.exit(0);
60
+ }
61
+ catch (error) {
62
+ console.error(`āŒ Failed to uninstall package: ${error}`);
63
+ process.exit(1);
64
+ }
65
+ }
66
+ /**
67
+ * Create the uninstall command
68
+ */
69
+ function createUninstallCommand() {
70
+ const command = new commander_1.Command('uninstall');
71
+ command
72
+ .description('Uninstall a prompt package')
73
+ .argument('<id>', 'Package ID to uninstall')
74
+ .alias('remove') // Keep 'remove' as an alias for backwards compatibility
75
+ .action(handleUninstall);
76
+ return command;
77
+ }
@@ -8,7 +8,7 @@ exports.createUpdateCommand = createUpdateCommand;
8
8
  const commander_1 = require("commander");
9
9
  const registry_client_1 = require("@prpm/registry-client");
10
10
  const user_config_1 = require("../core/user-config");
11
- const config_1 = require("../core/config");
11
+ const lockfile_1 = require("../core/lockfile");
12
12
  const install_1 = require("./install");
13
13
  const telemetry_1 = require("../core/telemetry");
14
14
  /**
@@ -22,7 +22,7 @@ async function handleUpdate(packageName, options = {}) {
22
22
  try {
23
23
  const config = await (0, user_config_1.getConfig)();
24
24
  const client = (0, registry_client_1.getRegistryClient)(config);
25
- const installedPackages = await (0, config_1.listPackages)();
25
+ const installedPackages = await (0, lockfile_1.listPackages)();
26
26
  if (installedPackages.length === 0) {
27
27
  console.log('No packages installed.');
28
28
  success = true;
@@ -92,6 +92,7 @@ async function handleUpdate(packageName, options = {}) {
92
92
  updatedCount,
93
93
  },
94
94
  });
95
+ await telemetry_1.telemetry.shutdown();
95
96
  }
96
97
  }
97
98
  /**
@@ -8,7 +8,7 @@ exports.createUpgradeCommand = createUpgradeCommand;
8
8
  const commander_1 = require("commander");
9
9
  const registry_client_1 = require("@prpm/registry-client");
10
10
  const user_config_1 = require("../core/user-config");
11
- const config_1 = require("../core/config");
11
+ const lockfile_1 = require("../core/lockfile");
12
12
  const install_1 = require("./install");
13
13
  const telemetry_1 = require("../core/telemetry");
14
14
  /**
@@ -22,7 +22,7 @@ async function handleUpgrade(packageName, options = {}) {
22
22
  try {
23
23
  const config = await (0, user_config_1.getConfig)();
24
24
  const client = (0, registry_client_1.getRegistryClient)(config);
25
- const installedPackages = await (0, config_1.listPackages)();
25
+ const installedPackages = await (0, lockfile_1.listPackages)();
26
26
  if (installedPackages.length === 0) {
27
27
  console.log('No packages installed.');
28
28
  success = true;
@@ -91,6 +91,7 @@ async function handleUpgrade(packageName, options = {}) {
91
91
  upgradedCount,
92
92
  },
93
93
  });
94
+ await telemetry_1.telemetry.shutdown();
94
95
  }
95
96
  }
96
97
  /**
@@ -7,6 +7,7 @@ exports.handleWhoami = handleWhoami;
7
7
  exports.createWhoamiCommand = createWhoamiCommand;
8
8
  const commander_1 = require("commander");
9
9
  const user_config_1 = require("../core/user-config");
10
+ const registry_client_1 = require("@prpm/registry-client");
10
11
  const telemetry_1 = require("../core/telemetry");
11
12
  /**
12
13
  * Show current logged-in user
@@ -23,7 +24,29 @@ async function handleWhoami() {
23
24
  success = true;
24
25
  return;
25
26
  }
26
- console.log(`${config.username}`);
27
+ // Fetch user profile from registry
28
+ try {
29
+ const client = (0, registry_client_1.getRegistryClient)(config);
30
+ const userProfile = await client.getUserProfile(config.username);
31
+ console.log(`\nšŸ‘¤ ${userProfile.username}${userProfile.verified_author ? ' āœ“' : ''}`);
32
+ if (userProfile.stats) {
33
+ console.log(`\nšŸ“Š Stats:`);
34
+ console.log(` šŸ“¦ Packages: ${userProfile.stats.total_packages}`);
35
+ console.log(` ā¬‡ļø Downloads: ${userProfile.stats.total_downloads.toLocaleString()}`);
36
+ }
37
+ // TODO: Add organizations when implemented in the database
38
+ if (userProfile.organizations && userProfile.organizations.length > 0) {
39
+ console.log(`\nšŸ¢ Organizations:`);
40
+ userProfile.organizations.forEach((org) => {
41
+ console.log(` • ${org.name} (${org.role})`);
42
+ });
43
+ }
44
+ console.log('');
45
+ }
46
+ catch (apiError) {
47
+ // Fallback to simple username display if API call fails
48
+ console.log(`${config.username}`);
49
+ }
27
50
  success = true;
28
51
  }
29
52
  catch (err) {
@@ -39,6 +62,7 @@ async function handleWhoami() {
39
62
  error,
40
63
  duration: Date.now() - startTime,
41
64
  });
65
+ await telemetry_1.telemetry.shutdown();
42
66
  }
43
67
  }
44
68
  /**