prpm 0.1.10 → 0.1.12

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.
@@ -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
- process.exit(1);
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
- process.exit(1);
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
- process.exit(1);
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
  }
@@ -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
- process.exit(1);
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
  */
@@ -86,7 +87,9 @@ async function handleCollectionsSearch(query, options) {
86
87
  if (c.description) {
87
88
  console.log(` ${c.description.substring(0, 70)}${c.description.length > 70 ? '...' : ''}`);
88
89
  }
89
- console.log(` šŸ‘¤ by @${c.author}${c.verified ? ' āœ“' : ''}`);
90
+ if (c.author) {
91
+ console.log(` šŸ‘¤ by @${c.author}${c.verified ? ' āœ“' : ''}`);
92
+ }
90
93
  console.log(` ā¬‡ļø ${c.downloads.toLocaleString()} installs Ā· ⭐ ${c.stars.toLocaleString()} stars`);
91
94
  console.log('');
92
95
  });
@@ -100,7 +103,9 @@ async function handleCollectionsSearch(query, options) {
100
103
  if (c.description) {
101
104
  console.log(` ${c.description.substring(0, 70)}${c.description.length > 70 ? '...' : ''}`);
102
105
  }
103
- console.log(` šŸ‘¤ by @${c.author}${c.verified ? ' āœ“' : ''}`);
106
+ if (c.author) {
107
+ console.log(` šŸ‘¤ by @${c.author}${c.verified ? ' āœ“' : ''}`);
108
+ }
104
109
  console.log(` ā¬‡ļø ${c.downloads.toLocaleString()} installs Ā· ⭐ ${c.stars.toLocaleString()} stars`);
105
110
  console.log('');
106
111
  });
@@ -130,7 +135,7 @@ async function handleCollectionsSearch(query, options) {
130
135
  error: errorMessage,
131
136
  duration: Date.now() - startTime,
132
137
  });
133
- process.exit(1);
138
+ throw new errors_1.CLIError(`\nāŒ Failed to search collections: ${errorMessage}`, 1);
134
139
  }
135
140
  finally {
136
141
  await telemetry_1.telemetry.shutdown();
@@ -168,7 +173,9 @@ async function handleCollectionsList(options) {
168
173
  if (c.description) {
169
174
  console.log(` ${c.description.substring(0, 70)}${c.description.length > 70 ? '...' : ''}`);
170
175
  }
171
- console.log(` šŸ‘¤ by @${c.author}${c.verified ? ' āœ“' : ''}`);
176
+ if (c.author) {
177
+ console.log(` šŸ‘¤ by @${c.author}${c.verified ? ' āœ“' : ''}`);
178
+ }
172
179
  console.log(` ā¬‡ļø ${c.downloads.toLocaleString()} installs Ā· ⭐ ${c.stars.toLocaleString()} stars`);
173
180
  console.log('');
174
181
  });
@@ -182,7 +189,9 @@ async function handleCollectionsList(options) {
182
189
  if (c.description) {
183
190
  console.log(` ${c.description.substring(0, 70)}${c.description.length > 70 ? '...' : ''}`);
184
191
  }
185
- console.log(` šŸ‘¤ by @${c.author}${c.verified ? ' āœ“' : ''}`);
192
+ if (c.author) {
193
+ console.log(` šŸ‘¤ by @${c.author}${c.verified ? ' āœ“' : ''}`);
194
+ }
186
195
  console.log(` ā¬‡ļø ${c.downloads.toLocaleString()} installs Ā· ⭐ ${c.stars.toLocaleString()} stars`);
187
196
  console.log('');
188
197
  });
@@ -218,7 +227,7 @@ async function handleCollectionsList(options) {
218
227
  error: errorMessage,
219
228
  duration: Date.now() - startTime,
220
229
  });
221
- process.exit(1);
230
+ throw new errors_1.CLIError(`\nāŒ Failed to list collections: ${errorMessage}`, 1);
222
231
  }
223
232
  finally {
224
233
  await telemetry_1.telemetry.shutdown();
@@ -264,7 +273,9 @@ async function handleCollectionInfo(collectionSpec) {
264
273
  console.log(` Stars: ${collection.stars.toLocaleString()}`);
265
274
  console.log(` Version: ${collection.version}`);
266
275
  console.log(` Packages: ${collection.packages.length}`);
267
- console.log(` Author: ${collection.author}${collection.verified ? ' āœ“' : ''}`);
276
+ if (collection.author) {
277
+ console.log(` Author: ${collection.author}${collection.verified ? ' āœ“' : ''}`);
278
+ }
268
279
  if (collection.category) {
269
280
  console.log(` Category: ${collection.category}`);
270
281
  }
@@ -338,7 +349,7 @@ async function handleCollectionInfo(collectionSpec) {
338
349
  error: errorMessage,
339
350
  duration: Date.now() - startTime,
340
351
  });
341
- process.exit(1);
352
+ throw new errors_1.CLIError(`\nāŒ Failed to get collection info: ${errorMessage}`, 1);
342
353
  }
343
354
  finally {
344
355
  await telemetry_1.telemetry.shutdown();
@@ -355,7 +366,7 @@ async function handleCollectionPublish(manifestPath = './collection.json') {
355
366
  // Check authentication
356
367
  if (!config.token) {
357
368
  console.error('\nāŒ Authentication required. Run `prpm login` first.\n');
358
- process.exit(1);
369
+ throw new errors_1.CLIError('\nāŒ Authentication required. Run `prpm login` first.', 1);
359
370
  }
360
371
  console.log('šŸ“¦ Publishing collection...\n');
361
372
  // Read collection manifest
@@ -438,7 +449,7 @@ async function handleCollectionPublish(manifestPath = './collection.json') {
438
449
  error: errorMessage,
439
450
  duration: Date.now() - startTime,
440
451
  });
441
- process.exit(1);
452
+ throw new errors_1.CLIError(`\nāŒ Failed to publish collection: ${errorMessage}`, 1);
442
453
  }
443
454
  finally {
444
455
  await telemetry_1.telemetry.shutdown();
@@ -501,14 +512,23 @@ async function handleCollectionInstall(collectionSpec, options) {
501
512
  const progress = `${i + 1}/${packages.length}`;
502
513
  try {
503
514
  console.log(`\n ${progress} Installing ${pkg.packageId}@${pkg.version}...`);
504
- await (0, install_1.handleInstall)(`${pkg.packageId}@${pkg.version}`, {
505
- as: pkg.format,
515
+ // Only pass 'as' format if user explicitly requested it via --as flag
516
+ // Otherwise, handleInstall will use this priority order:
517
+ // 1. defaultFormat from .prpmrc config
518
+ // 2. Auto-detection based on existing directories
519
+ // 3. Package native format
520
+ const installOptions = {
506
521
  fromCollection: {
507
522
  scope,
508
523
  name_slug,
509
524
  version: collection.version || version || '1.0.0',
510
525
  },
511
- });
526
+ };
527
+ // Only set 'as' if user explicitly provided a format
528
+ if (options.format) {
529
+ installOptions.as = options.format;
530
+ }
531
+ await (0, install_1.handleInstall)(`${pkg.packageId}@${pkg.version}`, installOptions);
512
532
  console.log(` ${progress} āœ“ ${pkg.packageId}`);
513
533
  installedPackageIds.push(pkg.packageId);
514
534
  packagesInstalled++;
@@ -566,7 +586,7 @@ async function handleCollectionInstall(collectionSpec, options) {
566
586
  failed: packagesFailed,
567
587
  },
568
588
  });
569
- process.exit(1);
589
+ throw new errors_1.CLIError(`\nāŒ Failed to install collection: ${errorMessage}`, 1);
570
590
  }
571
591
  finally {
572
592
  await telemetry_1.telemetry.shutdown();
@@ -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
- console.error(`āŒ Config key "${key}" not found`);
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
- console.error(`āŒ Failed to get config: ${error instanceof Error ? error.message : String(error)}`);
25
- process.exit(1);
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
- console.error(`āŒ Cannot set config key "${key}"`);
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
- console.error(`āŒ Invalid boolean value "${value}". Use: true, false, yes, no, 1, or 0`);
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
- console.error(`āŒ Failed to set config: ${error instanceof Error ? error.message : String(error)}`);
63
- process.exit(1);
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
- console.error(`āŒ Failed to list config: ${error instanceof Error ? error.message : String(error)}`);
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
- console.error(`āŒ Cannot delete config key "${key}"`);
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
- console.error(`āŒ Failed to delete config: ${error instanceof Error ? error.message : String(error)}`);
118
- process.exit(1);
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
  }
@@ -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
- process.exit(1);
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
- process.exit(1);
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
  }
@@ -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
- process.exit(1);
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
  /**
@@ -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
- console.error(`\nāŒ Failed to fetch package info: ${error}`);
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
  }
@@ -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
- await createExampleFiles(config.format, config.files, config.name);
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
- process.exit(1);
680
+ throw new errors_1.CLIError('\nāŒ Error: ' + (error instanceof Error ? error.message : error), 1);
679
681
  }
680
682
  });
681
683
  return command;
@@ -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");
@@ -223,18 +224,29 @@ async function handleInstall(packageSpec, options) {
223
224
  console.log(` ${pkg.name} ${pkg.official ? 'šŸ…' : ''}`);
224
225
  console.log(` ${pkg.description || 'No description'}`);
225
226
  console.log(` ${typeIcon} Type: ${typeLabel}`);
226
- // Determine format preference with auto-detection
227
+ // Determine format preference with priority order:
228
+ // 1. CLI --as flag (highest priority)
229
+ // 2. defaultFormat from .prpmrc config
230
+ // 3. Auto-detection based on existing directories
231
+ // 4. Package native format (fallback)
227
232
  let format = options.as;
228
- // Auto-detect format if not explicitly specified
229
233
  if (!format) {
230
- const detectedFormat = await (0, filesystem_1.autoDetectFormat)();
231
- if (detectedFormat) {
232
- format = detectedFormat;
233
- console.log(` šŸ” Auto-detected ${format} format (found .${format}/ directory)`);
234
+ // Check for config default format
235
+ if (config.defaultFormat) {
236
+ format = config.defaultFormat;
237
+ console.log(` āš™ļø Using default format from config: ${format}`);
234
238
  }
235
239
  else {
236
- // No existing directories found, use package's native format
237
- format = pkg.format;
240
+ // Auto-detect format based on existing directories
241
+ const detectedFormat = await (0, filesystem_1.autoDetectFormat)();
242
+ if (detectedFormat) {
243
+ format = detectedFormat;
244
+ console.log(` šŸ” Auto-detected ${format} format (found .${format}/ directory)`);
245
+ }
246
+ else {
247
+ // No config or detection, use package's native format
248
+ format = pkg.format;
249
+ }
238
250
  }
239
251
  }
240
252
  // Special handling for Claude packages: default to CLAUDE.md if it doesn't exist
@@ -494,11 +506,7 @@ async function handleInstall(packageSpec, options) {
494
506
  }
495
507
  catch (err) {
496
508
  error = err instanceof Error ? err.message : String(err);
497
- console.error(`\nāŒ Installation failed: ${error}`);
498
- console.log(`\nšŸ’” Tips:`);
499
- console.log(` - Check package name: prpm search <query>`);
500
- console.log(` - Get package info: prpm info <package>`);
501
- process.exit(1);
509
+ 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);
502
510
  }
503
511
  finally {
504
512
  await telemetry_1.telemetry.track({
@@ -611,9 +619,7 @@ async function installFromLockfile(options) {
611
619
  // Read lockfile
612
620
  const lockfile = await (0, lockfile_1.readLockfile)();
613
621
  if (!lockfile) {
614
- console.error('āŒ No prpm.lock file found');
615
- console.log('\nšŸ’” Run "prpm install <package>" first to create a lockfile, or initialize a new project with "prpm init"');
616
- process.exit(1);
622
+ 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);
617
623
  }
618
624
  const packageIds = Object.keys(lockfile.packages);
619
625
  if (packageIds.length === 0) {
@@ -642,19 +648,31 @@ async function installFromLockfile(options) {
642
648
  successCount++;
643
649
  }
644
650
  catch (error) {
645
- failCount++;
646
- console.error(` āŒ Failed to install ${packageId}: ${error}`);
651
+ // Check if this is a success exit (CLIError with exitCode 0)
652
+ if (error instanceof errors_1.CLIError && error.exitCode === 0) {
653
+ successCount++;
654
+ }
655
+ else {
656
+ failCount++;
657
+ console.error(` āŒ Failed to install ${packageId}:`);
658
+ console.error(` Type: ${error?.constructor?.name}`);
659
+ console.error(` Message: ${error instanceof Error ? error.message : String(error)}`);
660
+ if (error instanceof errors_1.CLIError) {
661
+ console.error(` ExitCode: ${error.exitCode}`);
662
+ }
663
+ }
647
664
  }
648
665
  }
649
666
  console.log(`\nāœ… Installed ${successCount}/${packageIds.length} packages`);
650
667
  if (failCount > 0) {
651
- console.error(`āŒ ${failCount} package${failCount === 1 ? '' : 's'} failed to install`);
652
- process.exit(1);
668
+ throw new errors_1.CLIError(`āŒ ${failCount} package${failCount === 1 ? '' : 's'} failed to install`, 1);
653
669
  }
654
670
  }
655
671
  catch (error) {
656
- console.error(`āŒ Failed to install from lockfile: ${error}`);
657
- process.exit(1);
672
+ if (error instanceof errors_1.CLIError) {
673
+ throw error;
674
+ }
675
+ throw new errors_1.CLIError(`āŒ Failed to install from lockfile: ${error}`, 1);
658
676
  }
659
677
  }
660
678
  function createInstallCommand() {
@@ -671,14 +689,7 @@ function createInstallCommand() {
671
689
  // Support both --as and --format (format is alias for as)
672
690
  const convertTo = options.format || options.as;
673
691
  if (convertTo && !['cursor', 'claude', 'continue', 'windsurf', 'copilot', 'kiro', 'agents.md', 'canonical'].includes(convertTo)) {
674
- console.error('āŒ Format must be one of: cursor, claude, continue, windsurf, copilot, kiro, agents.md, canonical');
675
- console.log('\nšŸ’” Examples:');
676
- console.log(' prpm install my-package --as cursor # Convert to Cursor format');
677
- console.log(' prpm install my-package --format claude # Convert to Claude format');
678
- console.log(' prpm install my-package --format kiro # Convert to Kiro format');
679
- console.log(' prpm install my-package --format agents.md # Convert to Agents.md format');
680
- console.log(' prpm install my-package # Install in native format');
681
- process.exit(1);
692
+ 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);
682
693
  }
683
694
  // If no package specified, install from lockfile
684
695
  if (!packageSpec) {
@@ -687,7 +698,6 @@ function createInstallCommand() {
687
698
  subtype: options.subtype,
688
699
  frozenLockfile: options.frozenLockfile
689
700
  });
690
- process.exit(0);
691
701
  return;
692
702
  }
693
703
  await handleInstall(packageSpec, {
@@ -696,7 +706,6 @@ function createInstallCommand() {
696
706
  subtype: options.subtype,
697
707
  frozenLockfile: options.frozenLockfile
698
708
  });
699
- process.exit(0);
700
709
  });
701
710
  return command;
702
711
  }
@@ -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
- console.error(`āŒ Failed to list packages: ${error}`);
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
  }
@@ -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
- console.error(`\nāŒ Login failed: ${error}\n`);
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
  }