prpm 0.1.9 ā 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/e2e/test-helpers.js +1 -0
- package/dist/commands/buy-credits.js +4 -4
- package/dist/commands/catalog.js +2 -2
- package/dist/commands/collections.js +17 -9
- package/dist/commands/config.js +18 -24
- package/dist/commands/credits.js +3 -3
- package/dist/commands/index.js +2 -4
- package/dist/commands/info.js +2 -7
- package/dist/commands/init.js +5 -3
- package/dist/commands/install.js +79 -27
- package/dist/commands/list.js +2 -3
- package/dist/commands/login.js +2 -4
- package/dist/commands/outdated.js +2 -3
- package/dist/commands/playground.js +4 -4
- package/dist/commands/popular.js +0 -1
- package/dist/commands/publish.js +66 -35
- package/dist/commands/schema.js +6 -5
- package/dist/commands/search.js +4 -4
- package/dist/commands/subscribe.js +4 -4
- package/dist/commands/telemetry.js +3 -8
- package/dist/commands/trending.js +4 -4
- package/dist/commands/uninstall.js +6 -5
- package/dist/commands/update.js +2 -3
- package/dist/commands/upgrade.js +2 -3
- package/dist/commands/whoami.js +2 -3
- package/dist/core/errors.js +29 -0
- package/dist/core/telemetry.js +36 -4
- package/dist/index.js +23 -2
- package/package.json +3 -3
|
@@ -141,6 +141,7 @@ function setupGlobalMocks() {
|
|
|
141
141
|
}
|
|
142
142
|
/**
|
|
143
143
|
* Mock process.exit to throw instead of exiting
|
|
144
|
+
* @deprecated No longer needed - commands now throw CLIError instead of calling process.exit
|
|
144
145
|
*/
|
|
145
146
|
function mockProcessExit() {
|
|
146
147
|
const mockExit = jest.spyOn(process, 'exit').mockImplementation((code) => {
|
|
@@ -11,6 +11,7 @@ const telemetry_1 = require("../core/telemetry");
|
|
|
11
11
|
const child_process_1 = require("child_process");
|
|
12
12
|
const util_1 = require("util");
|
|
13
13
|
const webapp_url_1 = require("../utils/webapp-url");
|
|
14
|
+
const errors_1 = require("../core/errors");
|
|
14
15
|
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
15
16
|
/**
|
|
16
17
|
* Make authenticated API call
|
|
@@ -102,7 +103,7 @@ async function handleBuyCredits(options) {
|
|
|
102
103
|
console.error('ā Authentication required');
|
|
103
104
|
console.log('\nš” Please login first:');
|
|
104
105
|
console.log(' prpm login');
|
|
105
|
-
|
|
106
|
+
throw new errors_1.CLIError('ā Authentication required', 1);
|
|
106
107
|
}
|
|
107
108
|
// Get current balance
|
|
108
109
|
console.log('š Checking current credits balance...');
|
|
@@ -122,7 +123,7 @@ async function handleBuyCredits(options) {
|
|
|
122
123
|
if (!validPackages.includes(options.package)) {
|
|
123
124
|
console.error(`\nā Invalid package: ${options.package}`);
|
|
124
125
|
console.log(' Valid options: small, medium, large');
|
|
125
|
-
|
|
126
|
+
throw new errors_1.CLIError(`\nā Invalid package: ${options.package}`, 1);
|
|
126
127
|
}
|
|
127
128
|
purchaseUrl += `?package=${options.package}`;
|
|
128
129
|
}
|
|
@@ -154,7 +155,7 @@ async function handleBuyCredits(options) {
|
|
|
154
155
|
catch (err) {
|
|
155
156
|
error = err instanceof Error ? err.message : String(err);
|
|
156
157
|
console.error(`\nā Purchase failed: ${error}`);
|
|
157
|
-
|
|
158
|
+
throw new errors_1.CLIError(`\nā Purchase failed: ${error}`, 1);
|
|
158
159
|
}
|
|
159
160
|
finally {
|
|
160
161
|
await telemetry_1.telemetry.track({
|
|
@@ -218,7 +219,6 @@ Note: Purchased credits are one-time and never expire, unlike monthly credits.
|
|
|
218
219
|
`)
|
|
219
220
|
.action(async (options) => {
|
|
220
221
|
await handleBuyCredits(options);
|
|
221
|
-
process.exit(0);
|
|
222
222
|
});
|
|
223
223
|
return command;
|
|
224
224
|
}
|
package/dist/commands/catalog.js
CHANGED
|
@@ -10,6 +10,7 @@ const promises_1 = require("fs/promises");
|
|
|
10
10
|
const path_1 = require("path");
|
|
11
11
|
const telemetry_1 = require("../core/telemetry");
|
|
12
12
|
const lockfile_1 = require("../core/lockfile");
|
|
13
|
+
const errors_1 = require("../core/errors");
|
|
13
14
|
/**
|
|
14
15
|
* Detect format and subtype from file path and content
|
|
15
16
|
*/
|
|
@@ -333,7 +334,7 @@ async function handleCatalog(directories, options) {
|
|
|
333
334
|
catch (err) {
|
|
334
335
|
error = err instanceof Error ? err.message : String(err);
|
|
335
336
|
console.error(`\nā Failed to catalog packages: ${error}\n`);
|
|
336
|
-
|
|
337
|
+
throw new errors_1.CLIError(`\nā Failed to catalog packages: ${error}`, 1);
|
|
337
338
|
}
|
|
338
339
|
finally {
|
|
339
340
|
await telemetry_1.telemetry.track({
|
|
@@ -360,6 +361,5 @@ function createCatalogCommand() {
|
|
|
360
361
|
.option('--dry-run', 'Show what would be cataloged without making changes')
|
|
361
362
|
.action(async (directories, options) => {
|
|
362
363
|
await handleCatalog(directories, options);
|
|
363
|
-
process.exit(0);
|
|
364
364
|
});
|
|
365
365
|
}
|
|
@@ -48,6 +48,7 @@ const user_config_1 = require("../core/user-config");
|
|
|
48
48
|
const install_1 = require("./install");
|
|
49
49
|
const telemetry_1 = require("../core/telemetry");
|
|
50
50
|
const lockfile_1 = require("../core/lockfile");
|
|
51
|
+
const errors_1 = require("../core/errors");
|
|
51
52
|
/**
|
|
52
53
|
* Search collections by query
|
|
53
54
|
*/
|
|
@@ -130,7 +131,7 @@ async function handleCollectionsSearch(query, options) {
|
|
|
130
131
|
error: errorMessage,
|
|
131
132
|
duration: Date.now() - startTime,
|
|
132
133
|
});
|
|
133
|
-
|
|
134
|
+
throw new errors_1.CLIError(`\nā Failed to search collections: ${errorMessage}`, 1);
|
|
134
135
|
}
|
|
135
136
|
finally {
|
|
136
137
|
await telemetry_1.telemetry.shutdown();
|
|
@@ -218,7 +219,7 @@ async function handleCollectionsList(options) {
|
|
|
218
219
|
error: errorMessage,
|
|
219
220
|
duration: Date.now() - startTime,
|
|
220
221
|
});
|
|
221
|
-
|
|
222
|
+
throw new errors_1.CLIError(`\nā Failed to list collections: ${errorMessage}`, 1);
|
|
222
223
|
}
|
|
223
224
|
finally {
|
|
224
225
|
await telemetry_1.telemetry.shutdown();
|
|
@@ -338,7 +339,7 @@ async function handleCollectionInfo(collectionSpec) {
|
|
|
338
339
|
error: errorMessage,
|
|
339
340
|
duration: Date.now() - startTime,
|
|
340
341
|
});
|
|
341
|
-
|
|
342
|
+
throw new errors_1.CLIError(`\nā Failed to get collection info: ${errorMessage}`, 1);
|
|
342
343
|
}
|
|
343
344
|
finally {
|
|
344
345
|
await telemetry_1.telemetry.shutdown();
|
|
@@ -355,7 +356,7 @@ async function handleCollectionPublish(manifestPath = './collection.json') {
|
|
|
355
356
|
// Check authentication
|
|
356
357
|
if (!config.token) {
|
|
357
358
|
console.error('\nā Authentication required. Run `prpm login` first.\n');
|
|
358
|
-
|
|
359
|
+
throw new errors_1.CLIError('\nā Authentication required. Run `prpm login` first.', 1);
|
|
359
360
|
}
|
|
360
361
|
console.log('š¦ Publishing collection...\n');
|
|
361
362
|
// Read collection manifest
|
|
@@ -438,7 +439,7 @@ async function handleCollectionPublish(manifestPath = './collection.json') {
|
|
|
438
439
|
error: errorMessage,
|
|
439
440
|
duration: Date.now() - startTime,
|
|
440
441
|
});
|
|
441
|
-
|
|
442
|
+
throw new errors_1.CLIError(`\nā Failed to publish collection: ${errorMessage}`, 1);
|
|
442
443
|
}
|
|
443
444
|
finally {
|
|
444
445
|
await telemetry_1.telemetry.shutdown();
|
|
@@ -501,14 +502,21 @@ async function handleCollectionInstall(collectionSpec, options) {
|
|
|
501
502
|
const progress = `${i + 1}/${packages.length}`;
|
|
502
503
|
try {
|
|
503
504
|
console.log(`\n ${progress} Installing ${pkg.packageId}@${pkg.version}...`);
|
|
504
|
-
|
|
505
|
-
|
|
505
|
+
// Only pass 'as' format if user explicitly requested it via --as flag
|
|
506
|
+
// Otherwise, let handleInstall auto-detect the format based on existing directories
|
|
507
|
+
// This ensures collections respect existing .claude or .cursor directories
|
|
508
|
+
const installOptions = {
|
|
506
509
|
fromCollection: {
|
|
507
510
|
scope,
|
|
508
511
|
name_slug,
|
|
509
512
|
version: collection.version || version || '1.0.0',
|
|
510
513
|
},
|
|
511
|
-
}
|
|
514
|
+
};
|
|
515
|
+
// Only set 'as' if user explicitly provided a format
|
|
516
|
+
if (options.format) {
|
|
517
|
+
installOptions.as = options.format;
|
|
518
|
+
}
|
|
519
|
+
await (0, install_1.handleInstall)(`${pkg.packageId}@${pkg.version}`, installOptions);
|
|
512
520
|
console.log(` ${progress} ā ${pkg.packageId}`);
|
|
513
521
|
installedPackageIds.push(pkg.packageId);
|
|
514
522
|
packagesInstalled++;
|
|
@@ -566,7 +574,7 @@ async function handleCollectionInstall(collectionSpec, options) {
|
|
|
566
574
|
failed: packagesFailed,
|
|
567
575
|
},
|
|
568
576
|
});
|
|
569
|
-
|
|
577
|
+
throw new errors_1.CLIError(`\nā Failed to install collection: ${errorMessage}`, 1);
|
|
570
578
|
}
|
|
571
579
|
finally {
|
|
572
580
|
await telemetry_1.telemetry.shutdown();
|
package/dist/commands/config.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.createConfigCommand = createConfigCommand;
|
|
7
7
|
const commander_1 = require("commander");
|
|
8
8
|
const user_config_1 = require("../core/user-config");
|
|
9
|
+
const errors_1 = require("../core/errors");
|
|
9
10
|
/**
|
|
10
11
|
* Get a config value
|
|
11
12
|
*/
|
|
@@ -14,15 +15,15 @@ async function handleConfigGet(key) {
|
|
|
14
15
|
const config = await (0, user_config_1.getConfig)();
|
|
15
16
|
const value = config[key];
|
|
16
17
|
if (value === undefined) {
|
|
17
|
-
|
|
18
|
-
console.log('\nAvailable keys: registryUrl, telemetryEnabled, token, username');
|
|
19
|
-
process.exit(1);
|
|
18
|
+
throw new errors_1.CLIError(`ā Config key "${key}" not found\n\nAvailable keys: registryUrl, telemetryEnabled, token, username`, 1);
|
|
20
19
|
}
|
|
21
20
|
console.log(value);
|
|
22
21
|
}
|
|
23
22
|
catch (error) {
|
|
24
|
-
|
|
25
|
-
|
|
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);
|
|
26
27
|
}
|
|
27
28
|
}
|
|
28
29
|
/**
|
|
@@ -34,10 +35,7 @@ async function handleConfigSet(key, value) {
|
|
|
34
35
|
// Validate key
|
|
35
36
|
const validKeys = ['registryUrl', 'telemetryEnabled'];
|
|
36
37
|
if (!validKeys.includes(key)) {
|
|
37
|
-
|
|
38
|
-
console.log('\nSettable keys: registryUrl, telemetryEnabled');
|
|
39
|
-
console.log('Note: token and username are set via "prpm login"');
|
|
40
|
-
process.exit(1);
|
|
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);
|
|
41
39
|
}
|
|
42
40
|
// Parse boolean values
|
|
43
41
|
let parsedValue = value;
|
|
@@ -49,8 +47,7 @@ async function handleConfigSet(key, value) {
|
|
|
49
47
|
parsedValue = false;
|
|
50
48
|
}
|
|
51
49
|
else {
|
|
52
|
-
|
|
53
|
-
process.exit(1);
|
|
50
|
+
throw new errors_1.CLIError(`ā Invalid boolean value "${value}". Use: true, false, yes, no, 1, or 0`, 1);
|
|
54
51
|
}
|
|
55
52
|
}
|
|
56
53
|
// Update config
|
|
@@ -59,8 +56,10 @@ async function handleConfigSet(key, value) {
|
|
|
59
56
|
console.log(`ā
Set ${key} = ${parsedValue}`);
|
|
60
57
|
}
|
|
61
58
|
catch (error) {
|
|
62
|
-
|
|
63
|
-
|
|
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);
|
|
64
63
|
}
|
|
65
64
|
}
|
|
66
65
|
/**
|
|
@@ -81,8 +80,7 @@ async function handleConfigList() {
|
|
|
81
80
|
console.log(`Config file: ${configPath}`);
|
|
82
81
|
}
|
|
83
82
|
catch (error) {
|
|
84
|
-
|
|
85
|
-
process.exit(1);
|
|
83
|
+
throw new errors_1.CLIError(`ā Failed to list config: ${error instanceof Error ? error.message : String(error)}`, 1);
|
|
86
84
|
}
|
|
87
85
|
}
|
|
88
86
|
/**
|
|
@@ -94,8 +92,7 @@ async function handleConfigDelete(key) {
|
|
|
94
92
|
// Validate key
|
|
95
93
|
const deletableKeys = ['registryUrl', 'telemetryEnabled', 'token', 'username'];
|
|
96
94
|
if (!deletableKeys.includes(key)) {
|
|
97
|
-
|
|
98
|
-
process.exit(1);
|
|
95
|
+
throw new errors_1.CLIError(`ā Cannot delete config key "${key}"`, 1);
|
|
99
96
|
}
|
|
100
97
|
// Reset to defaults
|
|
101
98
|
if (key === 'registryUrl') {
|
|
@@ -114,8 +111,10 @@ async function handleConfigDelete(key) {
|
|
|
114
111
|
console.log(`ā
Reset ${key} to default value`);
|
|
115
112
|
}
|
|
116
113
|
catch (error) {
|
|
117
|
-
|
|
118
|
-
|
|
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);
|
|
119
118
|
}
|
|
120
119
|
}
|
|
121
120
|
/**
|
|
@@ -131,7 +130,6 @@ function createConfigCommand() {
|
|
|
131
130
|
.description('List all configuration values')
|
|
132
131
|
.action(async () => {
|
|
133
132
|
await handleConfigList();
|
|
134
|
-
process.exit(0);
|
|
135
133
|
});
|
|
136
134
|
// config get <key>
|
|
137
135
|
command
|
|
@@ -139,7 +137,6 @@ function createConfigCommand() {
|
|
|
139
137
|
.description('Get a configuration value')
|
|
140
138
|
.action(async (key) => {
|
|
141
139
|
await handleConfigGet(key);
|
|
142
|
-
process.exit(0);
|
|
143
140
|
});
|
|
144
141
|
// config set <key> <value>
|
|
145
142
|
command
|
|
@@ -147,7 +144,6 @@ function createConfigCommand() {
|
|
|
147
144
|
.description('Set a configuration value')
|
|
148
145
|
.action(async (key, value) => {
|
|
149
146
|
await handleConfigSet(key, value);
|
|
150
|
-
process.exit(0);
|
|
151
147
|
});
|
|
152
148
|
// config delete <key>
|
|
153
149
|
command
|
|
@@ -156,12 +152,10 @@ function createConfigCommand() {
|
|
|
156
152
|
.description('Reset a configuration value to default')
|
|
157
153
|
.action(async (key) => {
|
|
158
154
|
await handleConfigDelete(key);
|
|
159
|
-
process.exit(0);
|
|
160
155
|
});
|
|
161
156
|
// Default action (show list if no subcommand)
|
|
162
157
|
command.action(async () => {
|
|
163
158
|
await handleConfigList();
|
|
164
|
-
process.exit(0);
|
|
165
159
|
});
|
|
166
160
|
return command;
|
|
167
161
|
}
|
package/dist/commands/credits.js
CHANGED
|
@@ -8,6 +8,7 @@ exports.createCreditsCommand = createCreditsCommand;
|
|
|
8
8
|
const commander_1 = require("commander");
|
|
9
9
|
const user_config_1 = require("../core/user-config");
|
|
10
10
|
const telemetry_1 = require("../core/telemetry");
|
|
11
|
+
const errors_1 = require("../core/errors");
|
|
11
12
|
/**
|
|
12
13
|
* Make authenticated API call
|
|
13
14
|
*/
|
|
@@ -112,7 +113,7 @@ async function handleCredits(options) {
|
|
|
112
113
|
console.error('ā Authentication required');
|
|
113
114
|
console.log('\nš” Please login first:');
|
|
114
115
|
console.log(' prpm login');
|
|
115
|
-
|
|
116
|
+
throw new errors_1.CLIError('ā Authentication required', 1);
|
|
116
117
|
}
|
|
117
118
|
if (options.history) {
|
|
118
119
|
await showHistory(options.limit || 10);
|
|
@@ -130,7 +131,7 @@ async function handleCredits(options) {
|
|
|
130
131
|
catch (err) {
|
|
131
132
|
error = err instanceof Error ? err.message : String(err);
|
|
132
133
|
console.error(`\nā Failed to fetch credits: ${error}`);
|
|
133
|
-
|
|
134
|
+
throw new errors_1.CLIError(`\nā Failed to fetch credits: ${error}`, 1);
|
|
134
135
|
}
|
|
135
136
|
finally {
|
|
136
137
|
await telemetry_1.telemetry.track({
|
|
@@ -180,7 +181,6 @@ Get more credits:
|
|
|
180
181
|
history: options.history,
|
|
181
182
|
limit: options.limit ? parseInt(options.limit, 10) : undefined,
|
|
182
183
|
});
|
|
183
|
-
process.exit(0);
|
|
184
184
|
});
|
|
185
185
|
return command;
|
|
186
186
|
}
|
package/dist/commands/index.js
CHANGED
|
@@ -13,6 +13,7 @@ const fs_1 = require("fs");
|
|
|
13
13
|
const path_1 = __importDefault(require("path"));
|
|
14
14
|
const lockfile_1 = require("../core/lockfile");
|
|
15
15
|
const filesystem_1 = require("../core/filesystem");
|
|
16
|
+
const errors_1 = require("../core/errors");
|
|
16
17
|
/**
|
|
17
18
|
* Scan directory for files and return file information
|
|
18
19
|
* Recursively scans subdirectories for Claude skills/agents
|
|
@@ -167,10 +168,7 @@ async function handleIndex(options = {}) {
|
|
|
167
168
|
}
|
|
168
169
|
catch (error) {
|
|
169
170
|
console.error(`ā Failed to index packages: ${error}`);
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
finally {
|
|
173
|
-
process.exit(0);
|
|
171
|
+
throw new errors_1.CLIError(`ā Failed to index packages: ${error}`, 1);
|
|
174
172
|
}
|
|
175
173
|
}
|
|
176
174
|
/**
|
package/dist/commands/info.js
CHANGED
|
@@ -9,6 +9,7 @@ const commander_1 = require("commander");
|
|
|
9
9
|
const registry_client_1 = require("@pr-pm/registry-client");
|
|
10
10
|
const user_config_1 = require("../core/user-config");
|
|
11
11
|
const telemetry_1 = require("../core/telemetry");
|
|
12
|
+
const errors_1 = require("../core/errors");
|
|
12
13
|
async function handleInfo(packageName) {
|
|
13
14
|
const startTime = Date.now();
|
|
14
15
|
let success = false;
|
|
@@ -50,12 +51,7 @@ async function handleInfo(packageName) {
|
|
|
50
51
|
}
|
|
51
52
|
catch (err) {
|
|
52
53
|
error = err instanceof Error ? err.message : String(err);
|
|
53
|
-
|
|
54
|
-
console.log(`\nš” Tips:`);
|
|
55
|
-
console.log(` - Check the package ID spelling`);
|
|
56
|
-
console.log(` - Search for packages: prpm search <query>`);
|
|
57
|
-
console.log(` - View trending: prpm trending`);
|
|
58
|
-
process.exit(1);
|
|
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);
|
|
59
55
|
}
|
|
60
56
|
finally {
|
|
61
57
|
await telemetry_1.telemetry.track({
|
|
@@ -77,7 +73,6 @@ function createInfoCommand() {
|
|
|
77
73
|
.argument('<package>', 'Package ID to get information about')
|
|
78
74
|
.action(async (packageId) => {
|
|
79
75
|
await handleInfo(packageId);
|
|
80
|
-
process.exit(0);
|
|
81
76
|
});
|
|
82
77
|
return command;
|
|
83
78
|
}
|
package/dist/commands/init.js
CHANGED
|
@@ -45,6 +45,7 @@ const fs_1 = require("fs");
|
|
|
45
45
|
const readline = __importStar(require("readline/promises"));
|
|
46
46
|
const process_1 = require("process");
|
|
47
47
|
const types_1 = require("../types");
|
|
48
|
+
const errors_1 = require("../core/errors");
|
|
48
49
|
const FORMAT_EXAMPLES = {
|
|
49
50
|
cursor: {
|
|
50
51
|
description: 'Cursor AI coding rules',
|
|
@@ -648,7 +649,9 @@ async function initPackage(options) {
|
|
|
648
649
|
// Create example files
|
|
649
650
|
if (config.files && config.format && config.name) {
|
|
650
651
|
console.log('Creating example files...\n');
|
|
651
|
-
|
|
652
|
+
// Filter out README.md since createReadme will handle it with proper content
|
|
653
|
+
const filesToCreate = config.files.filter(f => f !== 'README.md');
|
|
654
|
+
await createExampleFiles(config.format, filesToCreate, config.name);
|
|
652
655
|
// Create README
|
|
653
656
|
await createReadme(config);
|
|
654
657
|
}
|
|
@@ -671,11 +674,10 @@ function createInitCommand() {
|
|
|
671
674
|
.action(async (options) => {
|
|
672
675
|
try {
|
|
673
676
|
await initPackage(options);
|
|
674
|
-
process.exit(0);
|
|
675
677
|
}
|
|
676
678
|
catch (error) {
|
|
677
679
|
console.error('\nā Error:', error instanceof Error ? error.message : error);
|
|
678
|
-
|
|
680
|
+
throw new errors_1.CLIError('\nā Error: ' + (error instanceof Error ? error.message : error), 1);
|
|
679
681
|
}
|
|
680
682
|
});
|
|
681
683
|
return command;
|
package/dist/commands/install.js
CHANGED
|
@@ -45,6 +45,7 @@ const user_config_1 = require("../core/user-config");
|
|
|
45
45
|
const filesystem_1 = require("../core/filesystem");
|
|
46
46
|
const telemetry_1 = require("../core/telemetry");
|
|
47
47
|
const tar = __importStar(require("tar"));
|
|
48
|
+
const errors_1 = require("../core/errors");
|
|
48
49
|
const lockfile_1 = require("../core/lockfile");
|
|
49
50
|
const cursor_config_1 = require("../core/cursor-config");
|
|
50
51
|
const claude_config_1 = require("../core/claude-config");
|
|
@@ -356,10 +357,14 @@ async function handleInstall(packageSpec, options) {
|
|
|
356
357
|
const destDir = (0, filesystem_1.getDestinationDir)(effectiveFormat, effectiveSubtype, pkg.name);
|
|
357
358
|
// Multi-file package - create directory for package
|
|
358
359
|
// For Claude skills, destDir already includes package name, so use it directly
|
|
360
|
+
// For Cursor rules converted from Claude skills, use flat structure
|
|
359
361
|
const packageName = (0, filesystem_1.stripAuthorNamespace)(packageId);
|
|
362
|
+
const isCursorConversion = (effectiveFormat === 'cursor' && pkg.format === 'claude' && pkg.subtype === 'skill');
|
|
360
363
|
const packageDir = (effectiveFormat === 'claude' && effectiveSubtype === 'skill')
|
|
361
364
|
? destDir
|
|
362
|
-
:
|
|
365
|
+
: isCursorConversion
|
|
366
|
+
? destDir // Cursor uses flat structure
|
|
367
|
+
: `${destDir}/${packageName}`;
|
|
363
368
|
destPath = packageDir;
|
|
364
369
|
console.log(` š Multi-file package - creating directory: ${packageDir}`);
|
|
365
370
|
// For Claude skills, verify SKILL.md exists
|
|
@@ -385,6 +390,8 @@ async function handleInstall(packageSpec, options) {
|
|
|
385
390
|
}
|
|
386
391
|
}
|
|
387
392
|
}
|
|
393
|
+
// Track JSON files for @reference insertion in Cursor conversion
|
|
394
|
+
const jsonFiles = [];
|
|
388
395
|
for (const file of extractedFiles) {
|
|
389
396
|
// Strip the tarball's root directory prefix to preserve subdirectories
|
|
390
397
|
// Example: ".claude/skills/agent-builder/docs/examples.md" ā "docs/examples.md"
|
|
@@ -404,10 +411,58 @@ async function handleInstall(packageSpec, options) {
|
|
|
404
411
|
// Fallback: just take the filename (last part)
|
|
405
412
|
relativeFileName = pathParts[pathParts.length - 1];
|
|
406
413
|
}
|
|
407
|
-
|
|
408
|
-
|
|
414
|
+
let fileContent = file.content;
|
|
415
|
+
let fileName = relativeFileName;
|
|
416
|
+
// Handle Cursor conversion from Claude skill
|
|
417
|
+
if (isCursorConversion) {
|
|
418
|
+
// Convert SKILL.md to .mdc
|
|
419
|
+
if (fileName === 'SKILL.md' || fileName.endsWith('/SKILL.md')) {
|
|
420
|
+
fileName = `${packageName}.mdc`;
|
|
421
|
+
// Add MDC header if missing
|
|
422
|
+
if (!(0, cursor_config_1.hasMDCHeader)(fileContent)) {
|
|
423
|
+
console.log(` ā ļø Adding MDC header to converted skill...`);
|
|
424
|
+
fileContent = (0, cursor_config_1.addMDCHeader)(fileContent, pkg.description);
|
|
425
|
+
}
|
|
426
|
+
// Apply cursor config if available
|
|
427
|
+
if (config.cursor) {
|
|
428
|
+
console.log(` āļø Applying cursor config...`);
|
|
429
|
+
fileContent = (0, cursor_config_1.applyCursorConfig)(fileContent, config.cursor);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
// Track JSON files for @reference
|
|
433
|
+
else if (fileName.endsWith('.json')) {
|
|
434
|
+
// Flatten structure - remove subdirectories
|
|
435
|
+
const jsonFileName = fileName.split('/').pop() || fileName;
|
|
436
|
+
fileName = jsonFileName;
|
|
437
|
+
jsonFiles.push(jsonFileName);
|
|
438
|
+
}
|
|
439
|
+
// For other files (docs, etc), flatten the structure
|
|
440
|
+
else {
|
|
441
|
+
fileName = fileName.split('/').pop() || fileName;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
const filePath = `${packageDir}/${fileName}`;
|
|
445
|
+
await (0, filesystem_1.saveFile)(filePath, fileContent);
|
|
409
446
|
fileCount++;
|
|
410
447
|
}
|
|
448
|
+
// Add @references to .mdc file for JSON files
|
|
449
|
+
if (isCursorConversion && jsonFiles.length > 0) {
|
|
450
|
+
const mdcFile = `${packageDir}/${packageName}.mdc`;
|
|
451
|
+
const { readFile } = await Promise.resolve().then(() => __importStar(require('fs/promises')));
|
|
452
|
+
let mdcContent = await readFile(mdcFile, 'utf-8');
|
|
453
|
+
// Find the end of frontmatter (if exists)
|
|
454
|
+
const frontmatterMatch = mdcContent.match(/^---\n[\s\S]*?\n---\n/);
|
|
455
|
+
if (frontmatterMatch) {
|
|
456
|
+
const frontmatterEnd = frontmatterMatch[0].length;
|
|
457
|
+
const beforeFrontmatter = mdcContent.slice(0, frontmatterEnd);
|
|
458
|
+
const afterFrontmatter = mdcContent.slice(frontmatterEnd);
|
|
459
|
+
// Add @references right after frontmatter
|
|
460
|
+
const references = jsonFiles.map(f => `@${f}`).join('\n');
|
|
461
|
+
mdcContent = `${beforeFrontmatter}\n${references}\n${afterFrontmatter}`;
|
|
462
|
+
await (0, filesystem_1.saveFile)(mdcFile, mdcContent);
|
|
463
|
+
console.log(` ā Added ${jsonFiles.length} @reference(s) to ${packageName}.mdc`);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
411
466
|
}
|
|
412
467
|
// Update or create lock file
|
|
413
468
|
const updatedLockfile = lockfile || (0, lockfile_1.createLockfile)();
|
|
@@ -440,11 +495,7 @@ async function handleInstall(packageSpec, options) {
|
|
|
440
495
|
}
|
|
441
496
|
catch (err) {
|
|
442
497
|
error = err instanceof Error ? err.message : String(err);
|
|
443
|
-
|
|
444
|
-
console.log(`\nš” Tips:`);
|
|
445
|
-
console.log(` - Check package name: prpm search <query>`);
|
|
446
|
-
console.log(` - Get package info: prpm info <package>`);
|
|
447
|
-
process.exit(1);
|
|
498
|
+
throw new errors_1.CLIError(`\nā Installation failed: ${error}\n\nš” Tips:\n - Check package name: prpm search <query>\n - Get package info: prpm info <package>`, 1);
|
|
448
499
|
}
|
|
449
500
|
finally {
|
|
450
501
|
await telemetry_1.telemetry.track({
|
|
@@ -557,9 +608,7 @@ async function installFromLockfile(options) {
|
|
|
557
608
|
// Read lockfile
|
|
558
609
|
const lockfile = await (0, lockfile_1.readLockfile)();
|
|
559
610
|
if (!lockfile) {
|
|
560
|
-
|
|
561
|
-
console.log('\nš” Run "prpm install <package>" first to create a lockfile, or initialize a new project with "prpm init"');
|
|
562
|
-
process.exit(1);
|
|
611
|
+
throw new errors_1.CLIError('ā No prpm.lock file found\n\nš” Run "prpm install <package>" first to create a lockfile, or initialize a new project with "prpm init"', 1);
|
|
563
612
|
}
|
|
564
613
|
const packageIds = Object.keys(lockfile.packages);
|
|
565
614
|
if (packageIds.length === 0) {
|
|
@@ -588,19 +637,31 @@ async function installFromLockfile(options) {
|
|
|
588
637
|
successCount++;
|
|
589
638
|
}
|
|
590
639
|
catch (error) {
|
|
591
|
-
|
|
592
|
-
|
|
640
|
+
// Check if this is a success exit (CLIError with exitCode 0)
|
|
641
|
+
if (error instanceof errors_1.CLIError && error.exitCode === 0) {
|
|
642
|
+
successCount++;
|
|
643
|
+
}
|
|
644
|
+
else {
|
|
645
|
+
failCount++;
|
|
646
|
+
console.error(` ā Failed to install ${packageId}:`);
|
|
647
|
+
console.error(` Type: ${error?.constructor?.name}`);
|
|
648
|
+
console.error(` Message: ${error instanceof Error ? error.message : String(error)}`);
|
|
649
|
+
if (error instanceof errors_1.CLIError) {
|
|
650
|
+
console.error(` ExitCode: ${error.exitCode}`);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
593
653
|
}
|
|
594
654
|
}
|
|
595
655
|
console.log(`\nā
Installed ${successCount}/${packageIds.length} packages`);
|
|
596
656
|
if (failCount > 0) {
|
|
597
|
-
|
|
598
|
-
process.exit(1);
|
|
657
|
+
throw new errors_1.CLIError(`ā ${failCount} package${failCount === 1 ? '' : 's'} failed to install`, 1);
|
|
599
658
|
}
|
|
600
659
|
}
|
|
601
660
|
catch (error) {
|
|
602
|
-
|
|
603
|
-
|
|
661
|
+
if (error instanceof errors_1.CLIError) {
|
|
662
|
+
throw error;
|
|
663
|
+
}
|
|
664
|
+
throw new errors_1.CLIError(`ā Failed to install from lockfile: ${error}`, 1);
|
|
604
665
|
}
|
|
605
666
|
}
|
|
606
667
|
function createInstallCommand() {
|
|
@@ -617,14 +678,7 @@ function createInstallCommand() {
|
|
|
617
678
|
// Support both --as and --format (format is alias for as)
|
|
618
679
|
const convertTo = options.format || options.as;
|
|
619
680
|
if (convertTo && !['cursor', 'claude', 'continue', 'windsurf', 'copilot', 'kiro', 'agents.md', 'canonical'].includes(convertTo)) {
|
|
620
|
-
|
|
621
|
-
console.log('\nš” Examples:');
|
|
622
|
-
console.log(' prpm install my-package --as cursor # Convert to Cursor format');
|
|
623
|
-
console.log(' prpm install my-package --format claude # Convert to Claude format');
|
|
624
|
-
console.log(' prpm install my-package --format kiro # Convert to Kiro format');
|
|
625
|
-
console.log(' prpm install my-package --format agents.md # Convert to Agents.md format');
|
|
626
|
-
console.log(' prpm install my-package # Install in native format');
|
|
627
|
-
process.exit(1);
|
|
681
|
+
throw new errors_1.CLIError('ā Format must be one of: cursor, claude, continue, windsurf, copilot, kiro, agents.md, canonical\n\nš” Examples:\n prpm install my-package --as cursor # Convert to Cursor format\n prpm install my-package --format claude # Convert to Claude format\n prpm install my-package --format kiro # Convert to Kiro format\n prpm install my-package --format agents.md # Convert to Agents.md format\n prpm install my-package # Install in native format', 1);
|
|
628
682
|
}
|
|
629
683
|
// If no package specified, install from lockfile
|
|
630
684
|
if (!packageSpec) {
|
|
@@ -633,7 +687,6 @@ function createInstallCommand() {
|
|
|
633
687
|
subtype: options.subtype,
|
|
634
688
|
frozenLockfile: options.frozenLockfile
|
|
635
689
|
});
|
|
636
|
-
process.exit(0);
|
|
637
690
|
return;
|
|
638
691
|
}
|
|
639
692
|
await handleInstall(packageSpec, {
|
|
@@ -642,7 +695,6 @@ function createInstallCommand() {
|
|
|
642
695
|
subtype: options.subtype,
|
|
643
696
|
frozenLockfile: options.frozenLockfile
|
|
644
697
|
});
|
|
645
|
-
process.exit(0);
|
|
646
698
|
});
|
|
647
699
|
return command;
|
|
648
700
|
}
|
package/dist/commands/list.js
CHANGED
|
@@ -13,6 +13,7 @@ const lockfile_1 = require("../core/lockfile");
|
|
|
13
13
|
const telemetry_1 = require("../core/telemetry");
|
|
14
14
|
const fs_1 = require("fs");
|
|
15
15
|
const path_1 = __importDefault(require("path"));
|
|
16
|
+
const errors_1 = require("../core/errors");
|
|
16
17
|
/**
|
|
17
18
|
* Get destination directory based on package type
|
|
18
19
|
*/
|
|
@@ -158,8 +159,7 @@ async function handleList() {
|
|
|
158
159
|
}
|
|
159
160
|
catch (err) {
|
|
160
161
|
error = err instanceof Error ? err.message : String(err);
|
|
161
|
-
|
|
162
|
-
process.exit(1);
|
|
162
|
+
throw new errors_1.CLIError(`ā Failed to list packages: ${error}`, 1);
|
|
163
163
|
}
|
|
164
164
|
finally {
|
|
165
165
|
// Track telemetry
|
|
@@ -184,7 +184,6 @@ function createListCommand() {
|
|
|
184
184
|
.description('List all installed prompt packages')
|
|
185
185
|
.action(async () => {
|
|
186
186
|
await handleList();
|
|
187
|
-
process.exit(0);
|
|
188
187
|
});
|
|
189
188
|
return command;
|
|
190
189
|
}
|
package/dist/commands/login.js
CHANGED
|
@@ -42,6 +42,7 @@ const commander_1 = require("commander");
|
|
|
42
42
|
const http_1 = require("http");
|
|
43
43
|
const telemetry_1 = require("../core/telemetry");
|
|
44
44
|
const user_config_1 = require("../core/user-config");
|
|
45
|
+
const errors_1 = require("../core/errors");
|
|
45
46
|
/**
|
|
46
47
|
* Start OAuth callback server
|
|
47
48
|
*/
|
|
@@ -270,9 +271,7 @@ async function handleLogin(options) {
|
|
|
270
271
|
}
|
|
271
272
|
catch (err) {
|
|
272
273
|
error = err instanceof Error ? err.message : String(err);
|
|
273
|
-
|
|
274
|
-
console.error('š” Try again or use "prpm login --token YOUR_TOKEN"\n');
|
|
275
|
-
process.exit(1);
|
|
274
|
+
throw new errors_1.CLIError(`\nā Login failed: ${error}\n\nš” Try again or use "prpm login --token YOUR_TOKEN"\n`, 1);
|
|
276
275
|
}
|
|
277
276
|
finally {
|
|
278
277
|
// Track telemetry
|
|
@@ -297,6 +296,5 @@ function createLoginCommand() {
|
|
|
297
296
|
.option('--token <token>', 'Login with a personal access token')
|
|
298
297
|
.action(async (options) => {
|
|
299
298
|
await handleLogin(options);
|
|
300
|
-
process.exit(0);
|
|
301
299
|
});
|
|
302
300
|
}
|