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,637 +0,0 @@
1
- "use strict";
2
- /**
3
- * Playground command - Test packages with AI models
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.handlePlayground = handlePlayground;
40
- exports.createPlaygroundCommand = createPlaygroundCommand;
41
- const commander_1 = require("commander");
42
- const user_config_1 = require("../core/user-config");
43
- const telemetry_1 = require("../core/telemetry");
44
- const readline = __importStar(require("readline"));
45
- const fs = __importStar(require("fs"));
46
- const path = __importStar(require("path"));
47
- const errors_1 = require("../core/errors");
48
- /**
49
- * Create a readline interface for user input
50
- */
51
- function createReadline() {
52
- return readline.createInterface({
53
- input: process.stdin,
54
- output: process.stdout,
55
- });
56
- }
57
- /**
58
- * Prompt user for input
59
- */
60
- function prompt(rl, question) {
61
- return new Promise((resolve) => {
62
- rl.question(question, (answer) => {
63
- resolve(answer);
64
- });
65
- });
66
- }
67
- /**
68
- * Ask user for feedback on the result (subtle, non-intrusive)
69
- */
70
- async function promptFeedback(sessionId) {
71
- const rl = createReadline();
72
- try {
73
- console.log('\n💭 Was this result effective? (y/n, or press Enter to skip)');
74
- const answer = await prompt(rl, ' ');
75
- const normalized = answer.toLowerCase().trim();
76
- if (normalized === 'y' || normalized === 'yes') {
77
- // Optional comment
78
- console.log('\n Any comments? (optional, press Enter to skip)');
79
- const comment = await prompt(rl, ' ');
80
- await submitFeedback(sessionId, true, comment.trim() || undefined);
81
- if (comment.trim()) {
82
- console.log(' ✓ Feedback submitted with comment\n');
83
- }
84
- else {
85
- console.log(' ✓ Feedback submitted\n');
86
- }
87
- }
88
- else if (normalized === 'n' || normalized === 'no') {
89
- // Optional comment
90
- console.log('\n Any comments? (optional, press Enter to skip)');
91
- const comment = await prompt(rl, ' ');
92
- await submitFeedback(sessionId, false, comment.trim() || undefined);
93
- if (comment.trim()) {
94
- console.log(' ✓ Feedback submitted with comment\n');
95
- }
96
- else {
97
- console.log(' ✓ Feedback submitted\n');
98
- }
99
- }
100
- // If empty or anything else, silently skip
101
- }
102
- catch (error) {
103
- // Silently fail - feedback is optional
104
- }
105
- finally {
106
- rl.close();
107
- }
108
- }
109
- /**
110
- * Submit feedback to the API
111
- */
112
- async function submitFeedback(sessionId, isEffective, comment) {
113
- try {
114
- const response = await apiCall('/api/v1/playground/feedback', 'POST', {
115
- session_id: sessionId,
116
- is_effective: isEffective,
117
- comment: comment || undefined,
118
- });
119
- if (!response.ok) {
120
- // Silently fail - don't interrupt user flow
121
- return;
122
- }
123
- }
124
- catch (error) {
125
- // Silently fail - feedback is optional
126
- }
127
- }
128
- /**
129
- * Make authenticated API call to registry
130
- */
131
- async function apiCall(endpoint, method = 'GET', body) {
132
- const config = await (0, user_config_1.getConfig)();
133
- const baseUrl = (config.registryUrl || "https://registry.prpm.dev").replace(/\/$/, '');
134
- if (!config.token) {
135
- throw new Error('Authentication required. Please run `prpm login` first.');
136
- }
137
- const response = await fetch(`${baseUrl}${endpoint}`, {
138
- method,
139
- headers: {
140
- 'Content-Type': 'application/json',
141
- Authorization: `Bearer ${config.token}`,
142
- },
143
- body: body ? JSON.stringify(body) : undefined,
144
- });
145
- if (!response.ok) {
146
- const errorData = await response.json().catch(() => ({}));
147
- throw new Error(errorData.message || `API request failed: ${response.statusText}`);
148
- }
149
- return response;
150
- }
151
- /**
152
- * Resolve package name to UUID
153
- */
154
- async function resolvePackageId(packageName) {
155
- // If it's already a UUID, return it
156
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
157
- if (uuidRegex.test(packageName)) {
158
- return packageName;
159
- }
160
- // Look up package by name directly
161
- const config = await (0, user_config_1.getConfig)();
162
- const baseUrl = (config.registryUrl || "https://registry.prpm.dev").replace(/\/$/, '');
163
- // URL encode the package name to handle scoped packages like @user/package
164
- const encodedName = encodeURIComponent(packageName);
165
- const response = await fetch(`${baseUrl}/api/v1/packages/${encodedName}`);
166
- if (!response.ok) {
167
- if (response.status === 404) {
168
- throw new Error(`Package not found: ${packageName}`);
169
- }
170
- throw new Error(`Failed to fetch package: ${response.statusText}`);
171
- }
172
- const data = await response.json();
173
- return data.id;
174
- }
175
- /**
176
- * Execute a playground run
177
- */
178
- async function runPlayground(packageName, input, options, sessionId) {
179
- // Resolve package name to UUID
180
- const packageId = await resolvePackageId(packageName);
181
- const response = await apiCall('/api/v1/playground/run', 'POST', {
182
- package_id: packageId,
183
- package_version: options.version,
184
- input,
185
- model: options.model || 'sonnet',
186
- use_no_prompt: options.compare || false,
187
- session_id: sessionId,
188
- });
189
- return response.json();
190
- }
191
- /**
192
- * Execute a custom prompt playground run
193
- */
194
- async function runCustomPrompt(customPrompt, input, options, sessionId) {
195
- const response = await apiCall('/api/v1/custom-prompt/run', 'POST', {
196
- custom_prompt: customPrompt,
197
- input,
198
- model: options.model || 'sonnet',
199
- session_id: sessionId,
200
- });
201
- return response.json();
202
- }
203
- /**
204
- * Read custom prompt from file
205
- */
206
- function readPromptFile(filePath) {
207
- const absolutePath = path.resolve(filePath);
208
- if (!fs.existsSync(absolutePath)) {
209
- throw new Error(`Prompt file not found: ${filePath}`);
210
- }
211
- return fs.readFileSync(absolutePath, 'utf-8');
212
- }
213
- /**
214
- * Format and display playground response
215
- */
216
- function displayResponse(result, showStats = true) {
217
- // Get the latest assistant response
218
- const lastMessage = result.conversation[result.conversation.length - 1];
219
- if (lastMessage?.role === 'assistant') {
220
- console.log('\n' + '─'.repeat(60));
221
- console.log('🤖 Assistant:');
222
- console.log('─'.repeat(60));
223
- console.log(lastMessage.content);
224
- console.log('─'.repeat(60));
225
- }
226
- if (showStats) {
227
- console.log(`\n📊 Stats:`);
228
- console.log(` Model: ${result.model}`);
229
- console.log(` Tokens: ${result.tokens_used.toLocaleString()}`);
230
- console.log(` Credits spent: ${result.credits_spent}`);
231
- console.log(` Credits remaining: ${result.credits_remaining}`);
232
- console.log(` Duration: ${result.duration_ms}ms`);
233
- }
234
- }
235
- /**
236
- * Run interactive playground session
237
- */
238
- async function runInteractive(packageName, options) {
239
- console.log('\n🎮 Interactive Playground Mode');
240
- console.log(` Package: ${packageName}`);
241
- console.log(` Model: ${options.model || 'sonnet'}`);
242
- if (options.compare) {
243
- console.log(` Mode: Comparing against no prompt (raw model baseline)`);
244
- }
245
- console.log(` Type 'exit' or 'quit' to end session\n`);
246
- const rl = createReadline();
247
- let sessionId;
248
- let turnCount = 0;
249
- try {
250
- while (true) {
251
- const input = await prompt(rl, `\n💬 You: `);
252
- if (input.trim().toLowerCase() === 'exit' || input.trim().toLowerCase() === 'quit') {
253
- console.log('\n👋 Ending playground session. Goodbye!');
254
- break;
255
- }
256
- if (!input.trim()) {
257
- console.log('❌ Please enter a message');
258
- continue;
259
- }
260
- try {
261
- console.log('\n⏳ Processing...');
262
- const result = await runPlayground(packageName, input, options, sessionId);
263
- // Store session ID for conversation continuity
264
- sessionId = result.session_id;
265
- turnCount++;
266
- displayResponse(result, true);
267
- // Prompt for feedback in interactive mode (subtle, can skip)
268
- await promptFeedback(result.session_id);
269
- }
270
- catch (error) {
271
- console.error(`\n❌ Error: ${error instanceof Error ? error.message : String(error)}`);
272
- if (error instanceof Error && error.message.includes('Insufficient credits')) {
273
- console.log('\n💡 Get more credits:');
274
- console.log(' - Purchase credits: prpm buy-credits');
275
- console.log(' - Subscribe to PRPM+: prpm subscribe');
276
- console.log(' - Check balance: prpm credits');
277
- break;
278
- }
279
- }
280
- }
281
- if (turnCount > 0) {
282
- console.log(`\n📝 Session summary: ${turnCount} turn(s)`);
283
- }
284
- }
285
- finally {
286
- rl.close();
287
- }
288
- }
289
- /**
290
- * Run interactive custom prompt session
291
- */
292
- async function runCustomInteractive(customPrompt, options) {
293
- console.log('\n🎮 Interactive Custom Prompt Mode');
294
- console.log(` Model: ${options.model || 'sonnet'}`);
295
- console.log(` Type 'exit' or 'quit' to end session\n`);
296
- const rl = createReadline();
297
- let sessionId;
298
- let turnCount = 0;
299
- try {
300
- while (true) {
301
- const input = await prompt(rl, `\n💬 You: `);
302
- if (input.trim().toLowerCase() === 'exit' || input.trim().toLowerCase() === 'quit') {
303
- console.log('\n👋 Ending playground session. Goodbye!');
304
- break;
305
- }
306
- if (!input.trim()) {
307
- console.log('❌ Please enter a message');
308
- continue;
309
- }
310
- try {
311
- console.log('\n⏳ Processing...');
312
- const result = await runCustomPrompt(customPrompt, input, options, sessionId);
313
- // Store session ID for conversation continuity
314
- sessionId = result.session_id;
315
- turnCount++;
316
- displayResponse(result, true);
317
- }
318
- catch (error) {
319
- console.error(`\n❌ Error: ${error instanceof Error ? error.message : String(error)}`);
320
- if (error instanceof Error && error.message.includes('Insufficient credits')) {
321
- console.log('\n💡 Get more credits:');
322
- console.log(' - Purchase credits: prpm buy-credits');
323
- console.log(' - Subscribe to PRPM+: prpm subscribe');
324
- console.log(' - Check balance: prpm credits');
325
- break;
326
- }
327
- }
328
- }
329
- if (turnCount > 0) {
330
- console.log(`\n📝 Session summary: ${turnCount} turn(s)`);
331
- }
332
- }
333
- finally {
334
- rl.close();
335
- }
336
- }
337
- /**
338
- * Run baseline (no prompt) comparison
339
- */
340
- async function runBaseline(input, options) {
341
- // Use a minimal package but with use_no_prompt flag to get raw model baseline
342
- // We need any valid package ID because the API requires it, but the prompt will be ignored
343
- // Let's use a well-known minimal package (we'll search for any package)
344
- const config = await (0, user_config_1.getConfig)();
345
- const baseUrl = (config.registryUrl || "https://registry.prpm.dev").replace(/\/$/, '');
346
- // Get any package to use for baseline comparison (the prompt will be ignored anyway)
347
- const searchResponse = await fetch(`${baseUrl}/api/v1/search?q=coding&limit=1`);
348
- if (!searchResponse.ok) {
349
- throw new Error('Failed to find a package for baseline comparison');
350
- }
351
- const searchData = await searchResponse.json();
352
- if (!searchData.packages || searchData.packages.length === 0) {
353
- throw new Error('No packages found for baseline comparison');
354
- }
355
- const dummyPackageId = searchData.packages[0].id;
356
- // Call playground with use_no_prompt flag (this ignores the package prompt)
357
- const response = await apiCall('/api/v1/playground/run', 'POST', {
358
- package_id: dummyPackageId,
359
- input,
360
- model: options.model || 'sonnet',
361
- use_no_prompt: true, // This makes it a raw baseline with no system prompt
362
- });
363
- return response.json();
364
- }
365
- /**
366
- * Run single custom prompt query
367
- */
368
- async function runCustomSingle(customPrompt, input, options) {
369
- console.log(`\n🎮 Testing custom prompt`);
370
- console.log(` Model: ${options.model || 'sonnet'}`);
371
- console.log(` Credits: 2x normal cost (custom prompts)`);
372
- if (options.compare) {
373
- console.log(` Mode: Comparing custom prompt vs. no prompt (baseline)`);
374
- }
375
- try {
376
- if (options.compare) {
377
- // Comparison mode: run with custom prompt and without any prompt
378
- console.log('\n⏳ Processing comparison (2 requests)...');
379
- // Run with custom prompt
380
- const resultWithPrompt = await runCustomPrompt(customPrompt, input, options);
381
- // Run baseline (no prompt at all)
382
- const resultBaseline = await runBaseline(input, options);
383
- // Display both results
384
- console.log('\n' + '═'.repeat(60));
385
- console.log('✨ WITH CUSTOM PROMPT');
386
- console.log('═'.repeat(60));
387
- displayResponse(resultWithPrompt, false);
388
- console.log('\n' + '═'.repeat(60));
389
- console.log('🔵 WITHOUT PROMPT (BASELINE)');
390
- console.log('═'.repeat(60));
391
- displayResponse(resultBaseline, false);
392
- // Combined stats
393
- console.log(`\n📊 Combined Stats:`);
394
- console.log(` Total tokens: ${resultWithPrompt.tokens_used + resultBaseline.tokens_used}`);
395
- console.log(` Total credits: ${resultWithPrompt.credits_spent + resultBaseline.credits_spent}`);
396
- console.log(` Credits remaining: ${resultBaseline.credits_remaining}`);
397
- console.log(`\n💡 Compare the responses to evaluate your custom prompt's effectiveness!`);
398
- }
399
- else {
400
- // Single mode: run with custom prompt only
401
- console.log('\n⏳ Processing...');
402
- const result = await runCustomPrompt(customPrompt, input, options);
403
- displayResponse(result, true);
404
- console.log(`\n💡 Tips:`);
405
- console.log(` - Use --interactive for multi-turn conversation`);
406
- console.log(` - Use --compare to test against baseline (no prompt)`);
407
- console.log(` - Use --prompt-file to iterate on a prompt file`);
408
- console.log(` - Custom prompts cost 2x credits (no caching)`);
409
- }
410
- }
411
- catch (error) {
412
- console.error(`\n❌ Error: ${error instanceof Error ? error.message : String(error)}`);
413
- if (error instanceof Error && error.message.includes('Insufficient credits')) {
414
- console.log('\n💡 Get more credits:');
415
- console.log(' - Purchase credits: prpm buy-credits');
416
- console.log(' - Subscribe to PRPM+: prpm subscribe');
417
- console.log(' - Check balance: prpm credits');
418
- }
419
- throw new errors_1.CLIError(`\n❌ Error: ${error instanceof Error ? error.message : String(error)}`, 1);
420
- }
421
- }
422
- /**
423
- * Run single playground query
424
- */
425
- async function runSingle(packageName, input, options) {
426
- console.log(`\n🎮 Testing package: ${packageName}`);
427
- console.log(` Model: ${options.model || 'sonnet'}`);
428
- if (options.compare) {
429
- console.log(` Mode: Comparing with package vs. without (baseline)`);
430
- }
431
- try {
432
- if (options.compare) {
433
- // Comparison mode: run both with package and without
434
- console.log('\n⏳ Processing comparison (2 requests)...');
435
- // Run with package (without use_no_prompt flag)
436
- const withPackageOptions = { ...options, compare: false };
437
- const resultWithPackage = await runPlayground(packageName, input, withPackageOptions);
438
- // Run without package (with use_no_prompt flag)
439
- const withoutPackageOptions = { ...options, compare: true };
440
- const resultWithoutPackage = await runPlayground(packageName, input, withoutPackageOptions);
441
- // Display both results
442
- console.log('\n' + '═'.repeat(60));
443
- console.log('📦 WITH PACKAGE PROMPT');
444
- console.log('═'.repeat(60));
445
- displayResponse(resultWithPackage, false);
446
- console.log('\n' + '═'.repeat(60));
447
- console.log('🔵 WITHOUT PACKAGE (BASELINE)');
448
- console.log('═'.repeat(60));
449
- displayResponse(resultWithoutPackage, false);
450
- // Combined stats
451
- console.log(`\n📊 Combined Stats:`);
452
- console.log(` Total tokens: ${resultWithPackage.tokens_used + resultWithoutPackage.tokens_used}`);
453
- console.log(` Total credits: ${resultWithPackage.credits_spent + resultWithoutPackage.credits_spent}`);
454
- console.log(` Credits remaining: ${resultWithoutPackage.credits_remaining}`);
455
- // Prompt for feedback on the with-package result
456
- await promptFeedback(resultWithPackage.session_id);
457
- }
458
- else {
459
- // Single mode: run with package only
460
- console.log('\n⏳ Processing...');
461
- const result = await runPlayground(packageName, input, options);
462
- displayResponse(result, true);
463
- // Prompt for feedback
464
- await promptFeedback(result.session_id);
465
- }
466
- console.log(`\n💡 Tips:`);
467
- console.log(` - Use --interactive for multi-turn conversation`);
468
- console.log(` - Use --compare to test with and without the package prompt`);
469
- console.log(` - Use --model to choose different models (sonnet, opus, gpt-4o, etc.)`);
470
- }
471
- catch (error) {
472
- console.error(`\n❌ Error: ${error instanceof Error ? error.message : String(error)}`);
473
- if (error instanceof Error && error.message.includes('Insufficient credits')) {
474
- console.log('\n💡 Get more credits:');
475
- console.log(' - Purchase credits: prpm buy-credits');
476
- console.log(' - Subscribe to PRPM+: prpm subscribe');
477
- console.log(' - Check balance: prpm credits');
478
- }
479
- throw new errors_1.CLIError(`\n❌ Error: ${error instanceof Error ? error.message : String(error)}`, 1);
480
- }
481
- }
482
- /**
483
- * Handle the playground command
484
- */
485
- async function handlePlayground(options) {
486
- const startTime = Date.now();
487
- let success = false;
488
- let error;
489
- let customPromptMode = false;
490
- try {
491
- // Validate authentication
492
- const config = await (0, user_config_1.getConfig)();
493
- if (!config.token) {
494
- console.error('❌ Authentication required');
495
- console.log('\n💡 Please login first:');
496
- console.log(' prpm login');
497
- throw new errors_1.CLIError('❌ Authentication required', 1);
498
- }
499
- // Check for custom prompt mode
500
- if (options.custom || options.promptFile) {
501
- customPromptMode = true;
502
- // Get custom prompt from option or file
503
- let customPrompt;
504
- if (options.promptFile) {
505
- console.log(`📄 Loading prompt from: ${options.promptFile}`);
506
- customPrompt = readPromptFile(options.promptFile);
507
- console.log(`✅ Loaded ${customPrompt.length} characters\n`);
508
- }
509
- else {
510
- customPrompt = options.custom;
511
- }
512
- // Validate custom prompt length
513
- if (customPrompt.length < 10) {
514
- throw new Error('Custom prompt too short (minimum 10 characters)');
515
- }
516
- if (customPrompt.length > 50000) {
517
- throw new Error('Custom prompt too long (maximum 50000 characters)');
518
- }
519
- // Interactive mode or single query
520
- if (options.interactive || !options.input) {
521
- // Interactive mode with custom prompt
522
- await runCustomInteractive(customPrompt, options);
523
- }
524
- else {
525
- // Single query mode with custom prompt
526
- await runCustomSingle(customPrompt, options.input, options);
527
- }
528
- }
529
- else {
530
- // Regular package-based playground
531
- if (!options.package) {
532
- throw new Error('Either --package or --custom/--prompt-file is required');
533
- }
534
- // Interactive mode or single query
535
- if (options.interactive || !options.input) {
536
- // Interactive mode
537
- await runInteractive(options.package, options);
538
- }
539
- else {
540
- // Single query mode
541
- await runSingle(options.package, options.input, options);
542
- }
543
- }
544
- success = true;
545
- }
546
- catch (err) {
547
- error = err instanceof Error ? err.message : String(err);
548
- console.error(`\n❌ Playground execution failed: ${error}`);
549
- throw new errors_1.CLIError(`\n❌ Playground execution failed: ${error}`, 1);
550
- }
551
- finally {
552
- await telemetry_1.telemetry.track({
553
- command: 'playground',
554
- success,
555
- error,
556
- duration: Date.now() - startTime,
557
- data: {
558
- packageName: customPromptMode ? 'custom-prompt' : (options.package || 'unknown'),
559
- model: options.model || 'sonnet',
560
- compare: options.compare || false,
561
- interactive: options.interactive || false,
562
- customPrompt: customPromptMode,
563
- },
564
- });
565
- await telemetry_1.telemetry.shutdown();
566
- }
567
- }
568
- /**
569
- * Create the playground command
570
- */
571
- function createPlaygroundCommand() {
572
- const command = new commander_1.Command('playground');
573
- command
574
- .description('Test a package or custom prompt with AI models in the playground')
575
- .option('-p, --package <name>', 'Package name to test')
576
- .option('--input <text>', 'Input text to send to the model (omit for interactive mode)')
577
- .option('-m, --model <model>', 'AI model to use (sonnet, opus, gpt-4o, gpt-4o-mini, gpt-4-turbo)', 'sonnet')
578
- .option('-c, --compare', 'Compare against no prompt (test raw model baseline)', false)
579
- .option('-i, --interactive', 'Start interactive multi-turn conversation mode', false)
580
- .option('-v, --version <version>', 'Specific package version to test')
581
- .option('--custom <prompt>', 'Use a custom prompt string (verified authors only)')
582
- .option('--prompt-file <file>', 'Load custom prompt from a file (verified authors only)')
583
- .addHelpText('after', `
584
- Examples:
585
- # Test a package (single query)
586
- $ prpm playground --package @anthropic/code-reviewer --input "Review this code: console.log('hello')"
587
-
588
- # Interactive mode for multi-turn conversation
589
- $ prpm playground --package @anthropic/brainstorm-assistant --interactive
590
-
591
- # Compare with and without the package prompt
592
- $ prpm playground --package @user/custom-prompt --input "Test input" --compare
593
-
594
- # Use a different model
595
- $ prpm playground --package @user/prompt --model opus --input "Complex task requiring Opus"
596
- $ prpm playground --package @user/prompt --model gpt-4o --input "Test with GPT-4o"
597
-
598
- # Test specific version
599
- $ prpm playground --package @user/prompt --version 1.2.0 --input "Test input"
600
-
601
- # Use a custom prompt string (verified authors only)
602
- $ prpm playground --custom "You are a helpful coding assistant" --input "Explain async/await"
603
-
604
- # Load custom prompt from a file (verified authors only)
605
- $ prpm playground --prompt-file ./my-prompt.txt --input "Test input"
606
-
607
- # Compare custom prompt against baseline (no prompt)
608
- $ prpm playground --custom "You are concise" --input "Explain recursion" --compare
609
- $ prpm playground --prompt-file ./my-prompt.txt --input "Test" --compare
610
-
611
- # Interactive mode with custom prompt from file
612
- $ prpm playground --prompt-file ./my-prompt.txt --interactive
613
-
614
- # Short flags for common usage
615
- $ prpm playground -p @user/prompt --input "Test this"
616
- $ prpm playground -p @user/prompt -i
617
-
618
- Available Models:
619
- sonnet - Claude 3.5 Sonnet (default, balanced performance)
620
- opus - Claude 3 Opus (most capable, higher cost)
621
- gpt-4o - GPT-4o (OpenAI's latest)
622
- gpt-4o-mini - GPT-4o Mini (faster, cheaper)
623
- gpt-4-turbo - GPT-4 Turbo
624
-
625
- Custom Prompts:
626
- - Available to verified authors (link your GitHub account)
627
- - Cost 2x normal credits (no prompt caching)
628
- - Min 10 characters, max 50,000 characters
629
- - Perfect for iterating on prompt files locally
630
-
631
- Note: Playground usage requires credits. Run 'prpm credits' to check balance.
632
- `)
633
- .action(async (options) => {
634
- await handlePlayground(options);
635
- });
636
- return command;
637
- }
@@ -1,33 +0,0 @@
1
- "use strict";
2
- /**
3
- * Popular packages command implementation
4
- * Shows all-time popular packages (delegates to trending)
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.handlePopular = handlePopular;
8
- exports.createPopularCommand = createPopularCommand;
9
- const commander_1 = require("commander");
10
- const trending_1 = require("./trending");
11
- /**
12
- * Show popular packages (wrapper around trending)
13
- */
14
- async function handlePopular(options) {
15
- // Delegate to trending command
16
- console.log('📊 Popular Packages (All Time)\n');
17
- await (0, trending_1.handleTrending)({
18
- format: options.format,
19
- subtype: options.subtype
20
- });
21
- }
22
- /**
23
- * Create the popular command
24
- */
25
- function createPopularCommand() {
26
- return new commander_1.Command('popular')
27
- .description('Show popular packages (all time)')
28
- .option('--format <format>', 'Filter by format (cursor, claude, continue, windsurf, copilot, kiro, agents.md, generic)')
29
- .option('--subtype <subtype>', 'Filter by subtype (rule, agent, skill, slash-command, prompt, workflow, tool, template, collection)')
30
- .action(async (options) => {
31
- await handlePopular(options);
32
- });
33
- }