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,161 +0,0 @@
1
- "use strict";
2
- /**
3
- * Config command implementation
4
- */
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.createConfigCommand = createConfigCommand;
7
- const commander_1 = require("commander");
8
- const user_config_1 = require("../core/user-config");
9
- const errors_1 = require("../core/errors");
10
- /**
11
- * Get a config value
12
- */
13
- async function handleConfigGet(key) {
14
- try {
15
- const config = await (0, user_config_1.getConfig)();
16
- const value = config[key];
17
- if (value === undefined) {
18
- throw new errors_1.CLIError(`❌ Config key "${key}" not found\n\nAvailable keys: registryUrl, telemetryEnabled, token, username`, 1);
19
- }
20
- console.log(value);
21
- }
22
- catch (error) {
23
- if (error instanceof errors_1.CLIError) {
24
- throw error;
25
- }
26
- throw new errors_1.CLIError(`❌ Failed to get config: ${error instanceof Error ? error.message : String(error)}`, 1);
27
- }
28
- }
29
- /**
30
- * Set a config value
31
- */
32
- async function handleConfigSet(key, value) {
33
- try {
34
- const config = await (0, user_config_1.getConfig)();
35
- // Validate key
36
- const validKeys = ['registryUrl', 'telemetryEnabled'];
37
- if (!validKeys.includes(key)) {
38
- throw new errors_1.CLIError(`❌ Cannot set config key "${key}"\n\nSettable keys: registryUrl, telemetryEnabled\nNote: token and username are set via "prpm login"`, 1);
39
- }
40
- // Parse boolean values
41
- let parsedValue = value;
42
- if (key === 'telemetryEnabled') {
43
- if (value === 'true' || value === '1' || value === 'yes') {
44
- parsedValue = true;
45
- }
46
- else if (value === 'false' || value === '0' || value === 'no') {
47
- parsedValue = false;
48
- }
49
- else {
50
- throw new errors_1.CLIError(`❌ Invalid boolean value "${value}". Use: true, false, yes, no, 1, or 0`, 1);
51
- }
52
- }
53
- // Update config
54
- config[key] = parsedValue;
55
- await (0, user_config_1.saveConfig)(config);
56
- console.log(`✅ Set ${key} = ${parsedValue}`);
57
- }
58
- catch (error) {
59
- if (error instanceof errors_1.CLIError) {
60
- throw error;
61
- }
62
- throw new errors_1.CLIError(`❌ Failed to set config: ${error instanceof Error ? error.message : String(error)}`, 1);
63
- }
64
- }
65
- /**
66
- * List all config values
67
- */
68
- async function handleConfigList() {
69
- try {
70
- const config = await (0, user_config_1.getConfig)();
71
- console.log('📋 Current configuration:\n');
72
- console.log(` Registry URL: ${config.registryUrl}`);
73
- console.log(` Telemetry: ${config.telemetryEnabled ? 'enabled' : 'disabled'}`);
74
- console.log(` Username: ${config.username || '(not logged in)'}`);
75
- console.log(` Token: ${config.token ? '(set)' : '(not set)'}`);
76
- console.log('');
77
- const configPath = process.platform === 'win32'
78
- ? `${process.env.USERPROFILE}\\.prpmrc`
79
- : `${process.env.HOME}/.prpmrc`;
80
- console.log(`Config file: ${configPath}`);
81
- }
82
- catch (error) {
83
- throw new errors_1.CLIError(`❌ Failed to list config: ${error instanceof Error ? error.message : String(error)}`, 1);
84
- }
85
- }
86
- /**
87
- * Delete a config value (reset to default)
88
- */
89
- async function handleConfigDelete(key) {
90
- try {
91
- const config = await (0, user_config_1.getConfig)();
92
- // Validate key
93
- const deletableKeys = ['registryUrl', 'telemetryEnabled', 'token', 'username'];
94
- if (!deletableKeys.includes(key)) {
95
- throw new errors_1.CLIError(`❌ Cannot delete config key "${key}"`, 1);
96
- }
97
- // Reset to defaults
98
- if (key === 'registryUrl') {
99
- config.registryUrl = 'https://registry.prpm.dev';
100
- }
101
- else if (key === 'telemetryEnabled') {
102
- config.telemetryEnabled = true;
103
- }
104
- else if (key === 'token') {
105
- config.token = undefined;
106
- }
107
- else if (key === 'username') {
108
- config.username = undefined;
109
- }
110
- await (0, user_config_1.saveConfig)(config);
111
- console.log(`✅ Reset ${key} to default value`);
112
- }
113
- catch (error) {
114
- if (error instanceof errors_1.CLIError) {
115
- throw error;
116
- }
117
- throw new errors_1.CLIError(`❌ Failed to delete config: ${error instanceof Error ? error.message : String(error)}`, 1);
118
- }
119
- }
120
- /**
121
- * Create the config command
122
- */
123
- function createConfigCommand() {
124
- const command = new commander_1.Command('config')
125
- .description('Manage CLI configuration');
126
- // config list
127
- command
128
- .command('list')
129
- .alias('ls')
130
- .description('List all configuration values')
131
- .action(async () => {
132
- await handleConfigList();
133
- });
134
- // config get <key>
135
- command
136
- .command('get <key>')
137
- .description('Get a configuration value')
138
- .action(async (key) => {
139
- await handleConfigGet(key);
140
- });
141
- // config set <key> <value>
142
- command
143
- .command('set <key> <value>')
144
- .description('Set a configuration value')
145
- .action(async (key, value) => {
146
- await handleConfigSet(key, value);
147
- });
148
- // config delete <key>
149
- command
150
- .command('delete <key>')
151
- .alias('rm')
152
- .description('Reset a configuration value to default')
153
- .action(async (key) => {
154
- await handleConfigDelete(key);
155
- });
156
- // Default action (show list if no subcommand)
157
- command.action(async () => {
158
- await handleConfigList();
159
- });
160
- return command;
161
- }
@@ -1,186 +0,0 @@
1
- "use strict";
2
- /**
3
- * Credits command - Check and manage playground credits
4
- */
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.handleCredits = handleCredits;
7
- exports.createCreditsCommand = createCreditsCommand;
8
- const commander_1 = require("commander");
9
- const user_config_1 = require("../core/user-config");
10
- const telemetry_1 = require("../core/telemetry");
11
- const errors_1 = require("../core/errors");
12
- /**
13
- * Make authenticated API call
14
- */
15
- async function apiCall(endpoint) {
16
- const config = await (0, user_config_1.getConfig)();
17
- const baseUrl = (config.registryUrl || "https://registry.prpm.dev").replace(/\/$/, '');
18
- if (!config.token) {
19
- throw new Error('Authentication required. Please run `prpm login` first.');
20
- }
21
- const response = await fetch(`${baseUrl}${endpoint}`, {
22
- headers: {
23
- Authorization: `Bearer ${config.token}`,
24
- },
25
- });
26
- if (!response.ok) {
27
- const errorData = await response.json().catch(() => ({}));
28
- throw new Error(errorData.message || `API request failed: ${response.statusText}`);
29
- }
30
- return response;
31
- }
32
- /**
33
- * Display credits balance
34
- */
35
- async function showBalance() {
36
- console.log('💳 Fetching playground credits balance...\n');
37
- const response = await apiCall('/api/v1/playground/credits');
38
- const balance = await response.json();
39
- console.log('═'.repeat(5));
40
- console.log(' PLAYGROUND CREDITS BALANCE');
41
- console.log('═'.repeat(5));
42
- // Total balance
43
- console.log(`\n💰 Total Balance: ${balance.balance} credits`);
44
- // Breakdown
45
- console.log('\n📊 Breakdown:');
46
- if (balance.monthly_credits > 0) {
47
- const monthlyRemaining = balance.monthly_credits - balance.monthly_credits_used;
48
- console.log(` Monthly (PRPM+): ${monthlyRemaining}/${balance.monthly_credits} credits`);
49
- if (balance.monthly_reset_at) {
50
- const resetDate = new Date(balance.monthly_reset_at).toLocaleDateString();
51
- console.log(` (Resets: ${resetDate})`);
52
- }
53
- }
54
- if (balance.rollover_credits > 0) {
55
- console.log(` Rollover: ${balance.rollover_credits} credits`);
56
- if (balance.rollover_expires_at) {
57
- const expiresDate = new Date(balance.rollover_expires_at).toLocaleDateString();
58
- console.log(` (Expires: ${expiresDate})`);
59
- }
60
- }
61
- if (balance.purchased_credits > 0) {
62
- console.log(` Purchased: ${balance.purchased_credits} credits`);
63
- console.log(` (Never expire)`);
64
- }
65
- // PRPM+ Status
66
- if (balance.prpm_plus_status === 'active') {
67
- console.log('\n✨ PRPM+ Active - You get 100 monthly credits!');
68
- }
69
- else {
70
- console.log('\n💡 Upgrade to PRPM+ for 100 monthly credits');
71
- console.log(' Visit: https://prpm.dev/pricing');
72
- }
73
- console.log('\n═'.repeat(5));
74
- }
75
- /**
76
- * Display recent credit transactions
77
- */
78
- async function showHistory(limit = 10) {
79
- console.log(`💳 Fetching recent credit transactions...\n`);
80
- const response = await apiCall(`/api/v1/playground/credits/history?limit=${limit}`);
81
- const data = await response.json();
82
- if (data.transactions.length === 0) {
83
- console.log('No transaction history yet.');
84
- return;
85
- }
86
- console.log('═'.repeat(5));
87
- console.log(' CREDIT TRANSACTION HISTORY');
88
- console.log('═'.repeat(5));
89
- console.log();
90
- for (const tx of data.transactions) {
91
- const date = new Date(tx.created_at).toLocaleString();
92
- const amount = tx.amount >= 0 ? `+${tx.amount}` : `${tx.amount}`;
93
- const emoji = tx.amount >= 0 ? '💰' : '💸';
94
- console.log(`${emoji} ${date}`);
95
- console.log(` Type: ${tx.transaction_type}`);
96
- console.log(` Amount: ${amount} credits`);
97
- console.log(` Balance: ${tx.balance_after} credits`);
98
- console.log(` Details: ${tx.description}`);
99
- console.log();
100
- }
101
- console.log('═'.repeat(5));
102
- }
103
- /**
104
- * Handle the credits command
105
- */
106
- async function handleCredits(options) {
107
- const startTime = Date.now();
108
- let success = false;
109
- let error;
110
- try {
111
- const config = await (0, user_config_1.getConfig)();
112
- if (!config.token) {
113
- console.error('❌ Authentication required');
114
- console.log('\n💡 Please login first:');
115
- console.log(' prpm login');
116
- throw new errors_1.CLIError('❌ Authentication required', 1);
117
- }
118
- if (options.history) {
119
- await showHistory(options.limit || 10);
120
- }
121
- else {
122
- await showBalance();
123
- }
124
- console.log('\n💡 Tips:');
125
- console.log(' - Test packages: prpm playground <package> "<input>"');
126
- console.log(' - View history: prpm credits --history');
127
- console.log(' - Purchase credits: prpm buy-credits');
128
- console.log(' - Subscribe to PRPM+: prpm subscribe');
129
- success = true;
130
- }
131
- catch (err) {
132
- error = err instanceof Error ? err.message : String(err);
133
- console.error(`\n❌ Failed to fetch credits: ${error}`);
134
- throw new errors_1.CLIError(`\n❌ Failed to fetch credits: ${error}`, 1);
135
- }
136
- finally {
137
- await telemetry_1.telemetry.track({
138
- command: 'credits',
139
- success,
140
- error,
141
- duration: Date.now() - startTime,
142
- data: {
143
- showHistory: options.history || false,
144
- },
145
- });
146
- await telemetry_1.telemetry.shutdown();
147
- }
148
- }
149
- /**
150
- * Create the credits command
151
- */
152
- function createCreditsCommand() {
153
- const command = new commander_1.Command('credits');
154
- command
155
- .description('Check playground credits balance and transaction history')
156
- .option('-h, --history', 'Show transaction history instead of balance', false)
157
- .option('-l, --limit <number>', 'Number of transactions to show in history', '10')
158
- .addHelpText('after', `
159
- Examples:
160
- # Check current balance
161
- $ prpm credits
162
-
163
- # View transaction history
164
- $ prpm credits --history
165
-
166
- # View last 20 transactions
167
- $ prpm credits --history --limit 20
168
-
169
- Credits are used for:
170
- - Testing packages in the playground
171
- - Running prompts with AI models
172
- - Comparing packages against baselines
173
-
174
- Get more credits:
175
- - PRPM+ subscribers get 100 monthly credits
176
- - Purchase additional credits at https://prpm.dev/playground/credits/buy
177
- - Free tier gets 5 trial credits
178
- `)
179
- .action(async (options) => {
180
- await handleCredits({
181
- history: options.history,
182
- limit: options.limit ? parseInt(options.limit, 10) : undefined,
183
- });
184
- });
185
- return command;
186
- }
@@ -1,184 +0,0 @@
1
- "use strict";
2
- /**
3
- * Index command implementation
4
- */
5
- var __importDefault = (this && this.__importDefault) || function (mod) {
6
- return (mod && mod.__esModule) ? mod : { "default": mod };
7
- };
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.handleIndex = handleIndex;
10
- exports.createIndexCommand = createIndexCommand;
11
- const commander_1 = require("commander");
12
- const fs_1 = require("fs");
13
- const path_1 = __importDefault(require("path"));
14
- const lockfile_1 = require("../core/lockfile");
15
- const filesystem_1 = require("../core/filesystem");
16
- const errors_1 = require("../core/errors");
17
- /**
18
- * Scan directory for files and return file information
19
- * Recursively scans subdirectories for Claude skills/agents
20
- */
21
- async function scanDirectory(dirPath, format, subtype) {
22
- try {
23
- const files = await fs_1.promises.readdir(dirPath, { withFileTypes: true });
24
- const results = [];
25
- for (const file of files) {
26
- const fullPath = path_1.default.join(dirPath, file.name);
27
- if (file.isFile()) {
28
- // Direct file in the directory
29
- const id = (0, filesystem_1.generateId)(file.name);
30
- results.push({
31
- filePath: fullPath,
32
- filename: file.name,
33
- id
34
- });
35
- }
36
- else if (file.isDirectory()) {
37
- // For Claude/Cursor skills/agents, scan subdirectories for structured packages
38
- const isClaudeType = format === 'claude';
39
- const isCursorAgent = format === 'cursor' && subtype === 'agent';
40
- if (isClaudeType || isCursorAgent) {
41
- try {
42
- const subFiles = await fs_1.promises.readdir(fullPath, { withFileTypes: true });
43
- for (const subFile of subFiles) {
44
- const isValidFile = subFile.isFile() && (subFile.name === 'SKILL.md' ||
45
- subFile.name === 'AGENT.md' ||
46
- subFile.name === 'skill.md' ||
47
- subFile.name === 'agent.md');
48
- if (isValidFile) {
49
- const subFilePath = path_1.default.join(fullPath, subFile.name);
50
- const id = file.name; // Use directory name as package ID
51
- results.push({
52
- filePath: subFilePath,
53
- filename: `${file.name}/${subFile.name}`,
54
- id
55
- });
56
- }
57
- }
58
- }
59
- catch {
60
- // Subdirectory can't be read, skip it
61
- }
62
- }
63
- }
64
- }
65
- return results;
66
- }
67
- catch (error) {
68
- // Directory doesn't exist or can't be read
69
- return [];
70
- }
71
- }
72
- /**
73
- * Check if a package is already registered
74
- */
75
- function isPackageRegistered(packages, id) {
76
- return packages.some(pkg => pkg.id === id);
77
- }
78
- /**
79
- * Handle the index command
80
- */
81
- async function handleIndex(options = {}) {
82
- try {
83
- console.log('🔍 Scanning AI editor directories for prompt files...\n');
84
- // Get currently registered packages
85
- const existingPackages = await (0, lockfile_1.listPackages)();
86
- if (options.verbose) {
87
- console.log(`📋 Currently registered: ${existingPackages.length} packages\n`);
88
- }
89
- let totalFound = 0;
90
- let totalAdded = 0;
91
- const summary = [];
92
- // Define directories to scan with their format and subtype
93
- const dirsToScan = [
94
- { path: '.cursor/rules', format: 'cursor', subtype: 'rule', label: 'Cursor Rules' },
95
- { path: '.cursor/agents', format: 'cursor', subtype: 'agent', label: 'Cursor Agents' },
96
- { path: '.cursor/commands', format: 'cursor', subtype: 'slash-command', label: 'Cursor Slash Commands' },
97
- { path: '.claude/agents', format: 'claude', subtype: 'agent', label: 'Claude Agents' },
98
- { path: '.claude/skills', format: 'claude', subtype: 'skill', label: 'Claude Skills' },
99
- { path: '.claude/commands', format: 'claude', subtype: 'slash-command', label: 'Claude Slash Commands' },
100
- { path: '.continue/rules', format: 'continue', subtype: 'rule', label: 'Continue Rules' },
101
- { path: '.windsurf/rules', format: 'windsurf', subtype: 'rule', label: 'Windsurf Rules' },
102
- { path: '.prompts', format: 'generic', subtype: 'prompt', label: 'Generic Prompts' },
103
- { path: '.mcp', format: 'mcp', subtype: 'tool', label: 'MCP Servers' },
104
- ];
105
- // Scan each directory
106
- for (const dir of dirsToScan) {
107
- const files = await scanDirectory(dir.path, dir.format, dir.subtype);
108
- if (files.length === 0) {
109
- if (options.verbose) {
110
- console.log(`📁 ${dir.path}/ - No files found`);
111
- }
112
- continue;
113
- }
114
- console.log(`📁 ${dir.path}/ (${dir.label}) - Found ${files.length} file(s)`);
115
- let dirAdded = 0;
116
- totalFound += files.length;
117
- for (const file of files) {
118
- if (!isPackageRegistered(existingPackages, file.id)) {
119
- await (0, lockfile_1.addPackage)({
120
- id: file.id,
121
- version: '0.0.0', // Local files don't have versions
122
- tarballUrl: `file://${path_1.default.resolve(file.filePath)}`,
123
- format: dir.format,
124
- subtype: dir.subtype,
125
- });
126
- if (options.verbose) {
127
- console.log(` ✅ Added: ${file.filename} (${file.id})`);
128
- }
129
- totalAdded++;
130
- dirAdded++;
131
- }
132
- else if (options.verbose) {
133
- console.log(` ⏭️ Skipped: ${file.filename} (already registered)`);
134
- }
135
- }
136
- if (dirAdded > 0) {
137
- console.log(` ➕ Added ${dirAdded} new package(s)\n`);
138
- }
139
- else if (!options.verbose) {
140
- console.log(` ✓ All files already registered\n`);
141
- }
142
- summary.push({ dir: dir.path, found: files.length, added: dirAdded });
143
- }
144
- // Summary
145
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
146
- console.log('📊 Index Summary\n');
147
- console.log(` 📁 Total files found: ${totalFound}`);
148
- console.log(` ➕ New packages added: ${totalAdded}`);
149
- console.log(` ⏭️ Already registered: ${totalFound - totalAdded}`);
150
- if (options.verbose && summary.length > 0) {
151
- console.log('\n Breakdown by directory:');
152
- summary.filter(s => s.found > 0).forEach(s => {
153
- console.log(` ${s.dir}: ${s.found} found, ${s.added} added`);
154
- });
155
- }
156
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
157
- if (totalAdded > 0) {
158
- console.log(`\n✅ Successfully indexed ${totalAdded} new package(s)`);
159
- console.log(' Run `prpm list` to see all registered packages');
160
- }
161
- else if (totalFound > 0) {
162
- console.log('\n✨ All existing files are already registered');
163
- }
164
- else {
165
- console.log('\n💡 No prompt files found in standard directories');
166
- console.log(' Install packages with: prpm install <package-name>');
167
- }
168
- }
169
- catch (error) {
170
- console.error(`❌ Failed to index packages: ${error}`);
171
- throw new errors_1.CLIError(`❌ Failed to index packages: ${error}`, 1);
172
- }
173
- }
174
- /**
175
- * Create the index command
176
- */
177
- function createIndexCommand() {
178
- const command = new commander_1.Command('index');
179
- command
180
- .description('Scan AI editor directories and register untracked prompt files in prpm-lock.json')
181
- .option('-v, --verbose', 'Show detailed output for each file scanned')
182
- .action(handleIndex);
183
- return command;
184
- }
@@ -1,78 +0,0 @@
1
- "use strict";
2
- /**
3
- * Info command - Display detailed package information
4
- */
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.handleInfo = handleInfo;
7
- exports.createInfoCommand = createInfoCommand;
8
- const commander_1 = require("commander");
9
- const registry_client_1 = require("@pr-pm/registry-client");
10
- const user_config_1 = require("../core/user-config");
11
- const telemetry_1 = require("../core/telemetry");
12
- const errors_1 = require("../core/errors");
13
- async function handleInfo(packageName) {
14
- const startTime = Date.now();
15
- let success = false;
16
- let error;
17
- try {
18
- console.log(`📦 Fetching package info for "${packageName}"...`);
19
- const config = await (0, user_config_1.getConfig)();
20
- const client = (0, registry_client_1.getRegistryClient)(config);
21
- const pkg = await client.getPackage(packageName);
22
- console.log('\n' + '='.repeat(60));
23
- console.log(` ${pkg.name} ${pkg.verified ? '✓ Verified' : ''}`);
24
- console.log('='.repeat(60));
25
- // Description
26
- if (pkg.description) {
27
- console.log(`\n📝 ${pkg.description}`);
28
- }
29
- // Stats
30
- console.log('\n📊 Stats:');
31
- console.log(` Downloads: ${pkg.total_downloads.toLocaleString()}`);
32
- if (pkg.rating_average) {
33
- console.log(` Rating: ${'⭐'.repeat(Math.round(pkg.rating_average))} (${pkg.rating_average.toFixed(1)}/5)`);
34
- }
35
- // Latest version
36
- if (pkg.latest_version) {
37
- console.log(`\n🏷️ Latest Version: ${pkg.latest_version.version}`);
38
- }
39
- // Tags
40
- if (pkg.tags && pkg.tags.length > 0) {
41
- console.log(`\n🏷️ Tags: ${pkg.tags.join(', ')}`);
42
- }
43
- // Type
44
- console.log(`\n📂 Type: ${`${pkg.format || 'unknown'} ${pkg.subtype || 'unknown'}`}`);
45
- // Installation
46
- console.log('\n💻 Installation:');
47
- console.log(` prpm install ${pkg.name}`);
48
- console.log(` prpm install ${pkg.name}@${pkg.latest_version?.version || 'latest'}`);
49
- console.log('\n' + '='.repeat(60));
50
- success = true;
51
- }
52
- catch (err) {
53
- error = err instanceof Error ? err.message : String(err);
54
- throw new errors_1.CLIError(`\n❌ Failed to fetch package info: ${error}\n\n💡 Tips:\n - Check the package ID spelling\n - Search for packages: prpm search <query>\n - View trending: prpm trending`, 1);
55
- }
56
- finally {
57
- await telemetry_1.telemetry.track({
58
- command: 'info',
59
- success,
60
- error,
61
- duration: Date.now() - startTime,
62
- data: {
63
- packageName,
64
- },
65
- });
66
- await telemetry_1.telemetry.shutdown();
67
- }
68
- }
69
- function createInfoCommand() {
70
- const command = new commander_1.Command('info');
71
- command
72
- .description('Display detailed package information')
73
- .argument('<package>', 'Package ID to get information about')
74
- .action(async (packageId) => {
75
- await handleInfo(packageId);
76
- });
77
- return command;
78
- }