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,198 +0,0 @@
1
- "use strict";
2
- /**
3
- * List 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.handleList = handleList;
10
- exports.createListCommand = createListCommand;
11
- const commander_1 = require("commander");
12
- const lockfile_1 = require("../core/lockfile");
13
- const telemetry_1 = require("../core/telemetry");
14
- const fs_1 = require("fs");
15
- const path_1 = __importDefault(require("path"));
16
- const errors_1 = require("../core/errors");
17
- /**
18
- * Get destination directory based on package type
19
- */
20
- function getDestinationDir(type) {
21
- switch (type) {
22
- case 'cursor':
23
- return '.cursor/rules';
24
- case 'claude':
25
- return '.claude/agents';
26
- case 'claude-agent':
27
- return '.claude/agents';
28
- case 'claude-skill':
29
- return '.claude/skills';
30
- case 'claude-slash-command':
31
- return '.claude/commands';
32
- case 'continue':
33
- return '.continue/rules';
34
- case 'windsurf':
35
- return '.windsurf/rules';
36
- case 'agents.md':
37
- return '.';
38
- case 'generic':
39
- return '.prompts';
40
- case 'mcp':
41
- return '.mcp';
42
- default:
43
- return '.prompts';
44
- }
45
- }
46
- /**
47
- * Strip author namespace from package ID
48
- */
49
- function stripAuthorNamespace(packageId) {
50
- const parts = packageId.split('/');
51
- return parts[parts.length - 1];
52
- }
53
- /**
54
- * Find the actual file location for a package
55
- */
56
- async function findPackageLocation(id, format, subtype) {
57
- if (!format)
58
- return null;
59
- if (format === 'agents.md') {
60
- try {
61
- await fs_1.promises.access('AGENTS.md');
62
- return 'AGENTS.md';
63
- }
64
- catch {
65
- return null;
66
- }
67
- }
68
- const baseDir = getDestinationDir(format);
69
- // Strip author namespace to get actual package name used in file system
70
- const packageName = stripAuthorNamespace(id);
71
- // Try different file extensions based on format
72
- const extensions = format === 'cursor' ? ['.mdc', '.md'] : ['.md'];
73
- // Try direct file: <dir>/<packageName>.ext
74
- for (const ext of extensions) {
75
- const directPath = path_1.default.join(baseDir, `${packageName}${ext}`);
76
- try {
77
- await fs_1.promises.access(directPath);
78
- return directPath;
79
- }
80
- catch {
81
- // File doesn't exist, continue
82
- }
83
- }
84
- // Try subdirectory: <dir>/<packageName>/SKILL.md or <dir>/<packageName>/AGENT.md
85
- if (subtype === 'skill') {
86
- const skillPath = path_1.default.join(baseDir, packageName, 'SKILL.md');
87
- try {
88
- await fs_1.promises.access(skillPath);
89
- return skillPath;
90
- }
91
- catch {
92
- // Not found
93
- }
94
- }
95
- if (subtype === 'agent' || format === 'claude') {
96
- const agentPath = path_1.default.join(baseDir, packageName, 'AGENT.md');
97
- try {
98
- await fs_1.promises.access(agentPath);
99
- return agentPath;
100
- }
101
- catch {
102
- // Not found
103
- }
104
- }
105
- return null;
106
- }
107
- /**
108
- * Display packages in a formatted table
109
- */
110
- async function displayPackages(packages) {
111
- if (packages.length === 0) {
112
- console.log('šŸ“¦ No packages installed');
113
- return;
114
- }
115
- console.log('šŸ“¦ Installed packages:');
116
- console.log('');
117
- // Find file locations
118
- const packagesWithLocations = await Promise.all(packages.map(async (pkg) => ({
119
- ...pkg,
120
- location: await findPackageLocation(pkg.id, pkg.format, pkg.subtype)
121
- })));
122
- // Helper to format type display
123
- const formatType = (format, subtype) => {
124
- if (!format)
125
- return '';
126
- return subtype ? `${format}/${subtype}` : format;
127
- };
128
- // Calculate column widths
129
- const idWidth = Math.max(8, ...packagesWithLocations.map(p => p.id.length));
130
- const versionWidth = Math.max(7, ...packagesWithLocations.map(p => p.version.length));
131
- const typeWidth = Math.max(6, ...packagesWithLocations.map(p => formatType(p.format, p.subtype).length));
132
- const locationWidth = Math.max(8, ...packagesWithLocations.map(p => (p.installedPath || 'N/A').length));
133
- // Header
134
- const header = [
135
- 'ID'.padEnd(idWidth),
136
- 'VERSION'.padEnd(versionWidth),
137
- 'TYPE'.padEnd(typeWidth),
138
- 'LOCATION'.padEnd(locationWidth)
139
- ].join(' | ');
140
- console.log(header);
141
- console.log('-'.repeat(header.length));
142
- // Rows
143
- packagesWithLocations.forEach(pkg => {
144
- const row = [
145
- pkg.id.padEnd(idWidth),
146
- pkg.version.padEnd(versionWidth),
147
- formatType(pkg.format, pkg.subtype).padEnd(typeWidth),
148
- (pkg.installedPath || 'N/A').padEnd(locationWidth)
149
- ].join(' | ');
150
- console.log(row);
151
- });
152
- console.log('');
153
- console.log(`Total: ${packages.length} package${packages.length === 1 ? '' : 's'}`);
154
- }
155
- /**
156
- * Handle the list command
157
- */
158
- async function handleList() {
159
- const startTime = Date.now();
160
- let success = false;
161
- let error;
162
- let packageCount = 0;
163
- try {
164
- const packages = await (0, lockfile_1.listPackages)();
165
- packageCount = packages.length;
166
- await displayPackages(packages);
167
- success = true;
168
- }
169
- catch (err) {
170
- error = err instanceof Error ? err.message : String(err);
171
- throw new errors_1.CLIError(`āŒ Failed to list packages: ${error}`, 1);
172
- }
173
- finally {
174
- // Track telemetry
175
- await telemetry_1.telemetry.track({
176
- command: 'list',
177
- success,
178
- error,
179
- duration: Date.now() - startTime,
180
- data: {
181
- packageCount,
182
- },
183
- });
184
- await telemetry_1.telemetry.shutdown();
185
- }
186
- }
187
- /**
188
- * Create the list command
189
- */
190
- function createListCommand() {
191
- const command = new commander_1.Command('list');
192
- command
193
- .description('List all installed prompt packages')
194
- .action(async () => {
195
- await handleList();
196
- });
197
- return command;
198
- }
@@ -1,316 +0,0 @@
1
- "use strict";
2
- /**
3
- * Login command implementation
4
- */
5
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- var desc = Object.getOwnPropertyDescriptor(m, k);
8
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
- desc = { enumerable: true, get: function() { return m[k]; } };
10
- }
11
- Object.defineProperty(o, k2, desc);
12
- }) : (function(o, m, k, k2) {
13
- if (k2 === undefined) k2 = k;
14
- o[k2] = m[k];
15
- }));
16
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
- Object.defineProperty(o, "default", { enumerable: true, value: v });
18
- }) : function(o, v) {
19
- o["default"] = v;
20
- });
21
- var __importStar = (this && this.__importStar) || (function () {
22
- var ownKeys = function(o) {
23
- ownKeys = Object.getOwnPropertyNames || function (o) {
24
- var ar = [];
25
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
- return ar;
27
- };
28
- return ownKeys(o);
29
- };
30
- return function (mod) {
31
- if (mod && mod.__esModule) return mod;
32
- var result = {};
33
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
- __setModuleDefault(result, mod);
35
- return result;
36
- };
37
- })();
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.handleLogin = handleLogin;
40
- exports.createLoginCommand = createLoginCommand;
41
- const commander_1 = require("commander");
42
- const http_1 = require("http");
43
- const jwt = __importStar(require("jsonwebtoken"));
44
- const telemetry_1 = require("../core/telemetry");
45
- const user_config_1 = require("../core/user-config");
46
- const errors_1 = require("../core/errors");
47
- /**
48
- * Start OAuth callback server
49
- */
50
- function startCallbackServer() {
51
- return new Promise((resolve, reject) => {
52
- const server = (0, http_1.createServer)((req, res) => {
53
- const url = new URL(req.url || '', 'http://localhost:8765');
54
- if (url.pathname === '/callback') {
55
- const token = url.searchParams.get('token') || undefined;
56
- const username = url.searchParams.get('username') || undefined;
57
- const error = url.searchParams.get('error') || undefined;
58
- if (error) {
59
- res.writeHead(400, { 'Content-Type': 'text/html' });
60
- res.end(`
61
- <html>
62
- <body>
63
- <h1>āŒ Authentication Failed</h1>
64
- <p>Error: ${error}</p>
65
- <p>You can close this window.</p>
66
- </body>
67
- </html>
68
- `);
69
- server.close();
70
- reject(new Error(`OAuth error: ${error}`));
71
- return;
72
- }
73
- if (token) {
74
- res.writeHead(200, { 'Content-Type': 'text/html' });
75
- res.end(`
76
- <html>
77
- <body>
78
- <h1>āœ… Authentication Successful!</h1>
79
- <p>You can close this window and return to your terminal.</p>
80
- </body>
81
- </html>
82
- `);
83
- server.close();
84
- resolve({ token, username });
85
- }
86
- else {
87
- res.writeHead(400, { 'Content-Type': 'text/html' });
88
- res.end(`
89
- <html>
90
- <body>
91
- <h1>āŒ Invalid Request</h1>
92
- <p>No token received from authentication.</p>
93
- </body>
94
- </html>
95
- `);
96
- server.close();
97
- reject(new Error('No token received'));
98
- }
99
- }
100
- });
101
- server.listen(8765, () => {
102
- console.log(' Waiting for authentication...');
103
- });
104
- // Timeout after 5 minutes
105
- setTimeout(() => {
106
- server.close();
107
- reject(new Error('Authentication timeout'));
108
- }, 5 * 60 * 1000);
109
- });
110
- }
111
- /**
112
- * Login with GitHub OAuth via Nango connect link
113
- */
114
- async function loginWithOAuth(registryUrl) {
115
- console.log('\nšŸ” Opening browser for GitHub authentication...\n');
116
- // Generate a unique user ID for this CLI session
117
- const userId = `cli_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
118
- try {
119
- // Get the Nango connect session from the registry
120
- console.log(` Connecting to: ${registryUrl}`);
121
- const response = await fetch(`${registryUrl}/api/v1/auth/nango/cli/connect-session`, {
122
- method: 'POST',
123
- headers: {
124
- 'Content-Type': 'application/json',
125
- },
126
- body: JSON.stringify({
127
- userId,
128
- email: 'cli@example.com',
129
- displayName: 'CLI User',
130
- }),
131
- });
132
- if (!response.ok) {
133
- const errorText = await response.text().catch(() => 'Unable to read error response');
134
- throw new Error(`Failed to get authentication session (${response.status}): ${errorText}`);
135
- }
136
- const responseData = await response.json();
137
- const { connectSessionToken } = responseData;
138
- if (!connectSessionToken) {
139
- console.error('āŒ No session token received from server');
140
- console.error(' Response data:', JSON.stringify(responseData, null, 2));
141
- throw new Error('No session token received from server. Please check your Nango configuration.');
142
- }
143
- // Create the CLI auth URL with session token, callback, and userId
144
- const callbackUrl = 'http://localhost:8765/callback';
145
- // Determine webapp URL based on registry URL
146
- let webappUrl;
147
- if (registryUrl.includes('localhost') || registryUrl.includes('127.0.0.1')) {
148
- // Local development: registry on port 3111, webapp on port 5173
149
- webappUrl = registryUrl.replace(':3111', ':5173');
150
- }
151
- else if (registryUrl.includes('registry.prpm.dev')) {
152
- // Production: always use prpm.dev webapp
153
- webappUrl = 'https://prpm.dev';
154
- }
155
- else {
156
- // Custom registry: assume webapp is on same host without port
157
- const url = new URL(registryUrl);
158
- webappUrl = `${url.protocol}//${url.hostname}`;
159
- }
160
- const authUrl = `${webappUrl}/cli-auth?sessionToken=${encodeURIComponent(connectSessionToken)}&cliCallback=${encodeURIComponent(callbackUrl)}&userId=${encodeURIComponent(userId)}`;
161
- console.log(` Please open this link in your browser to authenticate:`);
162
- console.log(` ${authUrl}\n`);
163
- // Try to open browser
164
- const { exec } = await Promise.resolve().then(() => __importStar(require('child_process')));
165
- const platform = process.platform;
166
- const cmd = platform === 'darwin' ? 'open' : platform === 'win32' ? 'start' : 'xdg-open';
167
- exec(`${cmd} "${authUrl}"`);
168
- // Poll for authentication completion
169
- console.log(' Waiting for authentication...\n');
170
- const result = await pollForAuthentication(registryUrl, userId);
171
- if (!result.token) {
172
- throw new Error('No token received from authentication');
173
- }
174
- return { token: result.token, username: result.username || 'unknown' };
175
- }
176
- catch (error) {
177
- if (error instanceof Error) {
178
- // Check for common network errors
179
- if (error.message.includes('ECONNREFUSED')) {
180
- throw new Error(`Cannot connect to registry at ${registryUrl}. Is the registry running?`);
181
- }
182
- else if (error.message.includes('ENOTFOUND') || error.message.includes('getaddrinfo')) {
183
- throw new Error(`Cannot resolve registry hostname: ${registryUrl}. Check your internet connection.`);
184
- }
185
- }
186
- throw new Error(`Authentication failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
187
- }
188
- }
189
- /**
190
- * Poll for authentication completion
191
- */
192
- async function pollForAuthentication(registryUrl, userId) {
193
- const maxAttempts = 60; // 5 minutes with 5-second intervals
194
- let attempts = 0;
195
- while (attempts < maxAttempts) {
196
- try {
197
- const response = await fetch(`${registryUrl}/api/v1/auth/nango/cli/status/${userId}`);
198
- if (response.ok) {
199
- const { authenticated, connectionId } = await response.json();
200
- if (authenticated && connectionId) {
201
- // Authentication completed, get the JWT token
202
- const statusResponse = await fetch(`${registryUrl}/api/v1/auth/nango/status/${connectionId}`);
203
- if (statusResponse.ok) {
204
- const result = await statusResponse.json();
205
- if (result.ready && result.token) {
206
- return {
207
- token: result.token,
208
- username: result.username,
209
- };
210
- }
211
- }
212
- }
213
- }
214
- }
215
- catch (error) {
216
- // Ignore polling errors and continue
217
- }
218
- // Wait 5 seconds before next attempt
219
- await new Promise(resolve => setTimeout(resolve, 5000));
220
- attempts++;
221
- }
222
- throw new Error('Authentication timeout - please try again');
223
- }
224
- /**
225
- * Login with manual token
226
- */
227
- async function loginWithToken(token, registryUrl) {
228
- // Verify token by making a request to /api/v1/user
229
- const response = await fetch(`${registryUrl}/api/v1/user`, {
230
- headers: {
231
- 'Authorization': `Bearer ${token}`,
232
- },
233
- });
234
- if (!response.ok) {
235
- throw new Error('Invalid token');
236
- }
237
- const user = await response.json();
238
- return { token, username: user.username };
239
- }
240
- /**
241
- * Handle login command
242
- */
243
- async function handleLogin(options) {
244
- const startTime = Date.now();
245
- let success = false;
246
- let error;
247
- try {
248
- const config = await (0, user_config_1.getConfig)();
249
- const registryUrl = config.registryUrl || 'https://registry.prpm.dev';
250
- console.log('šŸ”‘ PRMP Login\n');
251
- let result;
252
- if (options.token) {
253
- // Manual token login
254
- console.log('šŸ” Logging in with provided token...\n');
255
- result = await loginWithToken(options.token, registryUrl);
256
- }
257
- else {
258
- // OAuth login
259
- result = await loginWithOAuth(registryUrl);
260
- }
261
- // Extract user_id and email from JWT token
262
- const decoded = jwt.decode(result.token);
263
- if (!decoded) {
264
- throw new Error('Failed to decode authentication token');
265
- }
266
- // Save token and user info to config
267
- await (0, user_config_1.saveConfig)({
268
- ...config,
269
- token: result.token,
270
- username: result.username,
271
- userId: decoded.user_id,
272
- email: decoded.email,
273
- });
274
- // Identify user in PostHog with user properties
275
- await telemetry_1.telemetry.identifyUser(decoded.user_id, {
276
- username: result.username,
277
- email: decoded.email,
278
- cli_version: process.env.npm_package_version,
279
- platform: process.platform,
280
- first_login: new Date().toISOString(),
281
- });
282
- console.log('āœ… Successfully logged in!\n');
283
- console.log(` Username: ${result.username}`);
284
- console.log(` Registry: ${registryUrl}\n`);
285
- console.log('šŸ’” You can now publish packages with "prpm publish"\n');
286
- success = true;
287
- }
288
- catch (err) {
289
- error = err instanceof Error ? err.message : String(err);
290
- throw new errors_1.CLIError(`\nāŒ Login failed: ${error}\n\nšŸ’” Try again or use "prpm login --token YOUR_TOKEN"\n`, 1);
291
- }
292
- finally {
293
- // Track telemetry
294
- await telemetry_1.telemetry.track({
295
- command: 'login',
296
- success,
297
- error,
298
- duration: Date.now() - startTime,
299
- data: {
300
- method: options.token ? 'token' : 'oauth',
301
- },
302
- });
303
- await telemetry_1.telemetry.shutdown();
304
- }
305
- }
306
- /**
307
- * Create the login command
308
- */
309
- function createLoginCommand() {
310
- return new commander_1.Command('login')
311
- .description('Login to the PRMP registry')
312
- .option('--token <token>', 'Login with a personal access token')
313
- .action(async (options) => {
314
- await handleLogin(options);
315
- });
316
- }
@@ -1,130 +0,0 @@
1
- "use strict";
2
- /**
3
- * Outdated command - Check for package updates
4
- */
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.handleOutdated = handleOutdated;
7
- exports.createOutdatedCommand = createOutdatedCommand;
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 lockfile_1 = require("../core/lockfile");
12
- const telemetry_1 = require("../core/telemetry");
13
- const errors_1 = require("../core/errors");
14
- /**
15
- * Check for outdated packages
16
- */
17
- async function handleOutdated() {
18
- const startTime = Date.now();
19
- let success = false;
20
- let error;
21
- try {
22
- console.log('šŸ” Checking for package updates...\n');
23
- const config = await (0, user_config_1.getConfig)();
24
- const client = (0, registry_client_1.getRegistryClient)(config);
25
- const installedPackages = await (0, lockfile_1.listPackages)();
26
- if (installedPackages.length === 0) {
27
- console.log('No packages installed.');
28
- success = true;
29
- return;
30
- }
31
- const outdated = [];
32
- for (const pkg of installedPackages) {
33
- try {
34
- // Get package info from registry
35
- const registryPkg = await client.getPackage(pkg.id);
36
- if (!registryPkg.latest_version || !pkg.version) {
37
- continue;
38
- }
39
- const currentVersion = pkg.version;
40
- const latestVersion = registryPkg.latest_version.version;
41
- // Check if update available
42
- if (currentVersion !== latestVersion) {
43
- const updateType = getUpdateType(currentVersion, latestVersion);
44
- outdated.push({
45
- id: pkg.id,
46
- current: currentVersion,
47
- latest: latestVersion,
48
- type: updateType,
49
- });
50
- }
51
- }
52
- catch (err) {
53
- // Skip packages that can't be found in registry
54
- continue;
55
- }
56
- }
57
- if (outdated.length === 0) {
58
- console.log('āœ… All packages are up to date!\n');
59
- success = true;
60
- return;
61
- }
62
- // Display outdated packages
63
- console.log(`šŸ“¦ ${outdated.length} package(s) have updates available:\n`);
64
- // Group by update type
65
- const major = outdated.filter(p => p.type === 'major');
66
- const minor = outdated.filter(p => p.type === 'minor');
67
- const patch = outdated.filter(p => p.type === 'patch');
68
- if (major.length > 0) {
69
- console.log('šŸ”“ Major Updates (breaking changes possible):');
70
- major.forEach(pkg => {
71
- console.log(` ${pkg.id.padEnd(30)} ${pkg.current} → ${pkg.latest}`);
72
- });
73
- console.log('');
74
- }
75
- if (minor.length > 0) {
76
- console.log('🟔 Minor Updates (new features):');
77
- minor.forEach(pkg => {
78
- console.log(` ${pkg.id.padEnd(30)} ${pkg.current} → ${pkg.latest}`);
79
- });
80
- console.log('');
81
- }
82
- if (patch.length > 0) {
83
- console.log('🟢 Patch Updates (bug fixes):');
84
- patch.forEach(pkg => {
85
- console.log(` ${pkg.id.padEnd(30)} ${pkg.current} → ${pkg.latest}`);
86
- });
87
- console.log('');
88
- }
89
- console.log('šŸ’” Run "prpm update" to update to latest minor/patch versions');
90
- console.log('šŸ’” Run "prpm upgrade" to upgrade to latest major versions\n');
91
- success = true;
92
- }
93
- catch (err) {
94
- error = err instanceof Error ? err.message : String(err);
95
- throw new errors_1.CLIError(`\nāŒ Failed to check for updates: ${error}`, 1);
96
- }
97
- finally {
98
- await telemetry_1.telemetry.track({
99
- command: 'outdated',
100
- success,
101
- error,
102
- duration: Date.now() - startTime,
103
- });
104
- await telemetry_1.telemetry.shutdown();
105
- }
106
- }
107
- /**
108
- * Determine update type based on semver
109
- */
110
- function getUpdateType(current, latest) {
111
- const currentParts = current.split('.').map(Number);
112
- const latestParts = latest.split('.').map(Number);
113
- const [currMajor = 0, currMinor = 0, currPatch = 0] = currentParts;
114
- const [latestMajor = 0, latestMinor = 0, latestPatch = 0] = latestParts;
115
- if (latestMajor > currMajor)
116
- return 'major';
117
- if (latestMinor > currMinor)
118
- return 'minor';
119
- return 'patch';
120
- }
121
- /**
122
- * Create the outdated command
123
- */
124
- function createOutdatedCommand() {
125
- return new commander_1.Command('outdated')
126
- .description('Check for package updates')
127
- .action(async () => {
128
- await handleOutdated();
129
- });
130
- }