prpm 0.1.5 ā 0.1.7
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/commands/buy-credits.js +224 -0
- package/dist/commands/credits.js +186 -0
- package/dist/commands/install.js +14 -2
- package/dist/commands/playground.js +351 -0
- package/dist/commands/subscribe.js +211 -0
- package/dist/core/filesystem.js +35 -0
- package/dist/index.js +9 -0
- package/dist/utils/webapp-url.js +44 -0
- package/package.json +3 -3
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Buy Credits command - Purchase one-time playground credits
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handleBuyCredits = handleBuyCredits;
|
|
7
|
+
exports.createBuyCreditsCommand = createBuyCreditsCommand;
|
|
8
|
+
const commander_1 = require("commander");
|
|
9
|
+
const user_config_1 = require("../core/user-config");
|
|
10
|
+
const telemetry_1 = require("../core/telemetry");
|
|
11
|
+
const child_process_1 = require("child_process");
|
|
12
|
+
const util_1 = require("util");
|
|
13
|
+
const webapp_url_1 = require("../utils/webapp-url");
|
|
14
|
+
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
15
|
+
/**
|
|
16
|
+
* Make authenticated API call
|
|
17
|
+
*/
|
|
18
|
+
async function apiCall(endpoint) {
|
|
19
|
+
const config = await (0, user_config_1.getConfig)();
|
|
20
|
+
const baseUrl = (config.registryUrl || 'https://registry.prpm.dev').replace(/\/$/, '');
|
|
21
|
+
if (!config.token) {
|
|
22
|
+
throw new Error('Authentication required. Please run `prpm login` first.');
|
|
23
|
+
}
|
|
24
|
+
const response = await fetch(`${baseUrl}${endpoint}`, {
|
|
25
|
+
headers: {
|
|
26
|
+
Authorization: `Bearer ${config.token}`,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
if (!response.ok) {
|
|
30
|
+
const errorData = await response.json().catch(() => ({}));
|
|
31
|
+
throw new Error(errorData.message || `API request failed: ${response.statusText}`);
|
|
32
|
+
}
|
|
33
|
+
return response;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get current credits balance
|
|
37
|
+
*/
|
|
38
|
+
async function getBalance() {
|
|
39
|
+
const response = await apiCall('/api/v1/playground/credits');
|
|
40
|
+
return response.json();
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Open URL in default browser
|
|
44
|
+
*/
|
|
45
|
+
async function openBrowser(url) {
|
|
46
|
+
const platform = process.platform;
|
|
47
|
+
let command;
|
|
48
|
+
if (platform === 'darwin') {
|
|
49
|
+
command = `open "${url}"`;
|
|
50
|
+
}
|
|
51
|
+
else if (platform === 'win32') {
|
|
52
|
+
command = `start "" "${url}"`;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
// Linux and other Unix-like systems
|
|
56
|
+
command = `xdg-open "${url}"`;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
await execAsync(command);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
// If automatic opening fails, just show the URL
|
|
63
|
+
console.log(`\nš Please open this URL in your browser:`);
|
|
64
|
+
console.log(` ${url}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Poll for credits balance increase
|
|
69
|
+
*/
|
|
70
|
+
async function pollForPurchase(initialBalance, maxAttempts = 60, intervalMs = 2000) {
|
|
71
|
+
console.log('\nā³ Waiting for purchase confirmation...');
|
|
72
|
+
console.log(' (This may take a minute. Press Ctrl+C to cancel)');
|
|
73
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
74
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
75
|
+
try {
|
|
76
|
+
const status = await getBalance();
|
|
77
|
+
if (status.balance > initialBalance) {
|
|
78
|
+
return status.balance - initialBalance;
|
|
79
|
+
}
|
|
80
|
+
// Show progress indicator
|
|
81
|
+
if (attempt % 5 === 0 && attempt > 0) {
|
|
82
|
+
process.stdout.write('.');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
// Continue polling even if there's an error
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Handle the buy-credits command
|
|
94
|
+
*/
|
|
95
|
+
async function handleBuyCredits(options) {
|
|
96
|
+
const startTime = Date.now();
|
|
97
|
+
let success = false;
|
|
98
|
+
let error;
|
|
99
|
+
try {
|
|
100
|
+
const config = await (0, user_config_1.getConfig)();
|
|
101
|
+
if (!config.token) {
|
|
102
|
+
console.error('ā Authentication required');
|
|
103
|
+
console.log('\nš” Please login first:');
|
|
104
|
+
console.log(' prpm login');
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
// Get current balance
|
|
108
|
+
console.log('š Checking current credits balance...');
|
|
109
|
+
const initialStatus = await getBalance();
|
|
110
|
+
console.log(` Current balance: ${initialStatus.balance} credits`);
|
|
111
|
+
console.log('\nš° Available credit packages:');
|
|
112
|
+
console.log(' Small: 100 credits - $5.00 ($0.05 per credit)');
|
|
113
|
+
console.log(' Medium: 250 credits - $11.25 ($0.045 per credit) - 10% savings');
|
|
114
|
+
console.log(' Large: 600 credits - $24.00 ($0.04 per credit) - 20% savings');
|
|
115
|
+
console.log('\n⨠These credits never expire!');
|
|
116
|
+
console.log('š” Tip: Subscribe to PRPM+ for 100 monthly credits at just $6/month');
|
|
117
|
+
// Build URL with package parameter if specified
|
|
118
|
+
const webappUrl = (0, webapp_url_1.getWebappUrl)(config.registryUrl || 'https://registry.prpm.dev');
|
|
119
|
+
let purchaseUrl = `${webappUrl}/playground/credits/buy`;
|
|
120
|
+
if (options.package) {
|
|
121
|
+
const validPackages = ['small', 'medium', 'large'];
|
|
122
|
+
if (!validPackages.includes(options.package)) {
|
|
123
|
+
console.error(`\nā Invalid package: ${options.package}`);
|
|
124
|
+
console.log(' Valid options: small, medium, large');
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
purchaseUrl += `?package=${options.package}`;
|
|
128
|
+
}
|
|
129
|
+
// Open purchase page
|
|
130
|
+
console.log(`\nš Opening purchase page in your browser...`);
|
|
131
|
+
await openBrowser(purchaseUrl);
|
|
132
|
+
// Poll for purchase confirmation
|
|
133
|
+
const creditsAdded = await pollForPurchase(initialStatus.balance);
|
|
134
|
+
if (creditsAdded !== null) {
|
|
135
|
+
const updatedStatus = await getBalance();
|
|
136
|
+
console.log('\n\nš Successfully purchased credits!');
|
|
137
|
+
console.log('\nš Credits added:');
|
|
138
|
+
console.log(` + ${creditsAdded} credits`);
|
|
139
|
+
console.log(` š³ New balance: ${updatedStatus.balance} credits`);
|
|
140
|
+
console.log('\nā
You can now:');
|
|
141
|
+
console.log(' - Test packages: prpm playground <package> "<input>"');
|
|
142
|
+
console.log(' - Check balance: prpm credits');
|
|
143
|
+
console.log(' - View history: prpm credits --history');
|
|
144
|
+
success = true;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
console.log('\n\nā±ļø Purchase process timed out or was canceled.');
|
|
148
|
+
console.log('\nš” If you completed the purchase, run this to verify:');
|
|
149
|
+
console.log(' prpm credits');
|
|
150
|
+
console.log('\nš” Or check your transaction history:');
|
|
151
|
+
console.log(' prpm credits --history');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
error = err instanceof Error ? err.message : String(err);
|
|
156
|
+
console.error(`\nā Purchase failed: ${error}`);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
finally {
|
|
160
|
+
await telemetry_1.telemetry.track({
|
|
161
|
+
command: 'buy-credits',
|
|
162
|
+
success,
|
|
163
|
+
error,
|
|
164
|
+
duration: Date.now() - startTime,
|
|
165
|
+
data: {
|
|
166
|
+
package: options.package,
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
await telemetry_1.telemetry.shutdown();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Create the buy-credits command
|
|
174
|
+
*/
|
|
175
|
+
function createBuyCreditsCommand() {
|
|
176
|
+
const command = new commander_1.Command('buy-credits');
|
|
177
|
+
command
|
|
178
|
+
.description('Purchase one-time playground credits (never expire)')
|
|
179
|
+
.option('-p, --package <package>', 'Credit package to purchase (small, medium, large)')
|
|
180
|
+
.addHelpText('after', `
|
|
181
|
+
Credit Packages:
|
|
182
|
+
Small: 100 credits - $5.00 ($0.05 per credit)
|
|
183
|
+
Medium: 250 credits - $11.25 ($0.045 per credit) - 10% savings
|
|
184
|
+
Large: 600 credits - $24.00 ($0.04 per credit) - 20% savings
|
|
185
|
+
|
|
186
|
+
Credits Usage:
|
|
187
|
+
- Testing packages in playground uses 1-5 credits per request
|
|
188
|
+
- Token-based pricing: 1 credit = 5,000 tokens
|
|
189
|
+
- Model multipliers apply (Opus 5x, GPT-4o 2x, etc.)
|
|
190
|
+
- Credits never expire
|
|
191
|
+
|
|
192
|
+
How it works:
|
|
193
|
+
1. Opens purchase page in your browser
|
|
194
|
+
2. Select package and complete payment with Stripe
|
|
195
|
+
3. Credits are added to your account immediately
|
|
196
|
+
4. Start testing packages right away
|
|
197
|
+
|
|
198
|
+
Examples:
|
|
199
|
+
# Browse all packages
|
|
200
|
+
$ prpm buy-credits
|
|
201
|
+
|
|
202
|
+
# Pre-select a specific package
|
|
203
|
+
$ prpm buy-credits --package small
|
|
204
|
+
$ prpm buy-credits --package medium
|
|
205
|
+
$ prpm buy-credits --package large
|
|
206
|
+
|
|
207
|
+
# After purchase, check balance
|
|
208
|
+
$ prpm credits
|
|
209
|
+
|
|
210
|
+
# Test packages in playground
|
|
211
|
+
$ prpm playground @user/prompt "test input"
|
|
212
|
+
|
|
213
|
+
š” Better Value:
|
|
214
|
+
Subscribe to PRPM+ for 100 monthly credits at just $6/month
|
|
215
|
+
Run: prpm subscribe
|
|
216
|
+
|
|
217
|
+
Note: Purchased credits are one-time and never expire, unlike monthly credits.
|
|
218
|
+
`)
|
|
219
|
+
.action(async (options) => {
|
|
220
|
+
await handleBuyCredits(options);
|
|
221
|
+
process.exit(0);
|
|
222
|
+
});
|
|
223
|
+
return command;
|
|
224
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Credits command - Check and manage playground credits
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handleCredits = handleCredits;
|
|
7
|
+
exports.createCreditsCommand = createCreditsCommand;
|
|
8
|
+
const commander_1 = require("commander");
|
|
9
|
+
const user_config_1 = require("../core/user-config");
|
|
10
|
+
const telemetry_1 = require("../core/telemetry");
|
|
11
|
+
/**
|
|
12
|
+
* Make authenticated API call
|
|
13
|
+
*/
|
|
14
|
+
async function apiCall(endpoint) {
|
|
15
|
+
const config = await (0, user_config_1.getConfig)();
|
|
16
|
+
const baseUrl = (config.registryUrl || "https://registry.prpm.dev").replace(/\/$/, '');
|
|
17
|
+
if (!config.token) {
|
|
18
|
+
throw new Error('Authentication required. Please run `prpm login` first.');
|
|
19
|
+
}
|
|
20
|
+
const response = await fetch(`${baseUrl}${endpoint}`, {
|
|
21
|
+
headers: {
|
|
22
|
+
Authorization: `Bearer ${config.token}`,
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
const errorData = await response.json().catch(() => ({}));
|
|
27
|
+
throw new Error(errorData.message || `API request failed: ${response.statusText}`);
|
|
28
|
+
}
|
|
29
|
+
return response;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Display credits balance
|
|
33
|
+
*/
|
|
34
|
+
async function showBalance() {
|
|
35
|
+
console.log('š³ Fetching playground credits balance...\n');
|
|
36
|
+
const response = await apiCall('/api/v1/playground/credits');
|
|
37
|
+
const balance = await response.json();
|
|
38
|
+
console.log('ā'.repeat(5));
|
|
39
|
+
console.log(' PLAYGROUND CREDITS BALANCE');
|
|
40
|
+
console.log('ā'.repeat(5));
|
|
41
|
+
// Total balance
|
|
42
|
+
console.log(`\nš° Total Balance: ${balance.balance} credits`);
|
|
43
|
+
// Breakdown
|
|
44
|
+
console.log('\nš Breakdown:');
|
|
45
|
+
if (balance.monthly_credits > 0) {
|
|
46
|
+
const monthlyRemaining = balance.monthly_credits - balance.monthly_credits_used;
|
|
47
|
+
console.log(` Monthly (PRPM+): ${monthlyRemaining}/${balance.monthly_credits} credits`);
|
|
48
|
+
if (balance.monthly_reset_at) {
|
|
49
|
+
const resetDate = new Date(balance.monthly_reset_at).toLocaleDateString();
|
|
50
|
+
console.log(` (Resets: ${resetDate})`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (balance.rollover_credits > 0) {
|
|
54
|
+
console.log(` Rollover: ${balance.rollover_credits} credits`);
|
|
55
|
+
if (balance.rollover_expires_at) {
|
|
56
|
+
const expiresDate = new Date(balance.rollover_expires_at).toLocaleDateString();
|
|
57
|
+
console.log(` (Expires: ${expiresDate})`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (balance.purchased_credits > 0) {
|
|
61
|
+
console.log(` Purchased: ${balance.purchased_credits} credits`);
|
|
62
|
+
console.log(` (Never expire)`);
|
|
63
|
+
}
|
|
64
|
+
// PRPM+ Status
|
|
65
|
+
if (balance.prpm_plus_status === 'active') {
|
|
66
|
+
console.log('\n⨠PRPM+ Active - You get 100 monthly credits!');
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
console.log('\nš” Upgrade to PRPM+ for 100 monthly credits');
|
|
70
|
+
console.log(' Visit: https://prpm.dev/pricing');
|
|
71
|
+
}
|
|
72
|
+
console.log('\nā'.repeat(5));
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Display recent credit transactions
|
|
76
|
+
*/
|
|
77
|
+
async function showHistory(limit = 10) {
|
|
78
|
+
console.log(`š³ Fetching recent credit transactions...\n`);
|
|
79
|
+
const response = await apiCall(`/api/v1/playground/credits/history?limit=${limit}`);
|
|
80
|
+
const data = await response.json();
|
|
81
|
+
if (data.transactions.length === 0) {
|
|
82
|
+
console.log('No transaction history yet.');
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
console.log('ā'.repeat(5));
|
|
86
|
+
console.log(' CREDIT TRANSACTION HISTORY');
|
|
87
|
+
console.log('ā'.repeat(5));
|
|
88
|
+
console.log();
|
|
89
|
+
for (const tx of data.transactions) {
|
|
90
|
+
const date = new Date(tx.created_at).toLocaleString();
|
|
91
|
+
const amount = tx.amount >= 0 ? `+${tx.amount}` : `${tx.amount}`;
|
|
92
|
+
const emoji = tx.amount >= 0 ? 'š°' : 'šø';
|
|
93
|
+
console.log(`${emoji} ${date}`);
|
|
94
|
+
console.log(` Type: ${tx.transaction_type}`);
|
|
95
|
+
console.log(` Amount: ${amount} credits`);
|
|
96
|
+
console.log(` Balance: ${tx.balance_after} credits`);
|
|
97
|
+
console.log(` Details: ${tx.description}`);
|
|
98
|
+
console.log();
|
|
99
|
+
}
|
|
100
|
+
console.log('ā'.repeat(5));
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Handle the credits command
|
|
104
|
+
*/
|
|
105
|
+
async function handleCredits(options) {
|
|
106
|
+
const startTime = Date.now();
|
|
107
|
+
let success = false;
|
|
108
|
+
let error;
|
|
109
|
+
try {
|
|
110
|
+
const config = await (0, user_config_1.getConfig)();
|
|
111
|
+
if (!config.token) {
|
|
112
|
+
console.error('ā Authentication required');
|
|
113
|
+
console.log('\nš” Please login first:');
|
|
114
|
+
console.log(' prpm login');
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
if (options.history) {
|
|
118
|
+
await showHistory(options.limit || 10);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
await showBalance();
|
|
122
|
+
}
|
|
123
|
+
console.log('\nš” Tips:');
|
|
124
|
+
console.log(' - Test packages: prpm playground <package> "<input>"');
|
|
125
|
+
console.log(' - View history: prpm credits --history');
|
|
126
|
+
console.log(' - Purchase credits: prpm buy-credits');
|
|
127
|
+
console.log(' - Subscribe to PRPM+: prpm subscribe');
|
|
128
|
+
success = true;
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
error = err instanceof Error ? err.message : String(err);
|
|
132
|
+
console.error(`\nā Failed to fetch credits: ${error}`);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
finally {
|
|
136
|
+
await telemetry_1.telemetry.track({
|
|
137
|
+
command: 'credits',
|
|
138
|
+
success,
|
|
139
|
+
error,
|
|
140
|
+
duration: Date.now() - startTime,
|
|
141
|
+
data: {
|
|
142
|
+
showHistory: options.history || false,
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
await telemetry_1.telemetry.shutdown();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Create the credits command
|
|
150
|
+
*/
|
|
151
|
+
function createCreditsCommand() {
|
|
152
|
+
const command = new commander_1.Command('credits');
|
|
153
|
+
command
|
|
154
|
+
.description('Check playground credits balance and transaction history')
|
|
155
|
+
.option('-h, --history', 'Show transaction history instead of balance', false)
|
|
156
|
+
.option('-l, --limit <number>', 'Number of transactions to show in history', '10')
|
|
157
|
+
.addHelpText('after', `
|
|
158
|
+
Examples:
|
|
159
|
+
# Check current balance
|
|
160
|
+
$ prpm credits
|
|
161
|
+
|
|
162
|
+
# View transaction history
|
|
163
|
+
$ prpm credits --history
|
|
164
|
+
|
|
165
|
+
# View last 20 transactions
|
|
166
|
+
$ prpm credits --history --limit 20
|
|
167
|
+
|
|
168
|
+
Credits are used for:
|
|
169
|
+
- Testing packages in the playground
|
|
170
|
+
- Running prompts with AI models
|
|
171
|
+
- Comparing packages against baselines
|
|
172
|
+
|
|
173
|
+
Get more credits:
|
|
174
|
+
- PRPM+ subscribers get 100 monthly credits
|
|
175
|
+
- Purchase additional credits at https://prpm.dev/playground/credits/buy
|
|
176
|
+
- Free tier gets 5 trial credits
|
|
177
|
+
`)
|
|
178
|
+
.action(async (options) => {
|
|
179
|
+
await handleCredits({
|
|
180
|
+
history: options.history,
|
|
181
|
+
limit: options.limit ? parseInt(options.limit, 10) : undefined,
|
|
182
|
+
});
|
|
183
|
+
process.exit(0);
|
|
184
|
+
});
|
|
185
|
+
return command;
|
|
186
|
+
}
|
package/dist/commands/install.js
CHANGED
|
@@ -220,8 +220,20 @@ async function handleInstall(packageSpec, options) {
|
|
|
220
220
|
console.log(` ${pkg.name} ${pkg.official ? 'š
' : ''}`);
|
|
221
221
|
console.log(` ${pkg.description || 'No description'}`);
|
|
222
222
|
console.log(` ${typeIcon} Type: ${typeLabel}`);
|
|
223
|
-
// Determine format preference
|
|
224
|
-
let format = options.as
|
|
223
|
+
// Determine format preference with auto-detection
|
|
224
|
+
let format = options.as;
|
|
225
|
+
// Auto-detect format if not explicitly specified
|
|
226
|
+
if (!format) {
|
|
227
|
+
const detectedFormat = await (0, filesystem_1.autoDetectFormat)();
|
|
228
|
+
if (detectedFormat) {
|
|
229
|
+
format = detectedFormat;
|
|
230
|
+
console.log(` š Auto-detected ${format} format (found .${format}/ directory)`);
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
// No existing directories found, use package's native format
|
|
234
|
+
format = pkg.format;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
225
237
|
// Special handling for Claude packages: default to CLAUDE.md if it doesn't exist
|
|
226
238
|
// BUT only for packages that are generic rules (not skills, agents, or commands)
|
|
227
239
|
if (!options.as && pkg.format === 'claude' && pkg.subtype === 'rule') {
|
|
@@ -0,0 +1,351 @@
|
|
|
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
|
+
/**
|
|
46
|
+
* Create a readline interface for user input
|
|
47
|
+
*/
|
|
48
|
+
function createReadline() {
|
|
49
|
+
return readline.createInterface({
|
|
50
|
+
input: process.stdin,
|
|
51
|
+
output: process.stdout,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Prompt user for input
|
|
56
|
+
*/
|
|
57
|
+
function prompt(rl, question) {
|
|
58
|
+
return new Promise((resolve) => {
|
|
59
|
+
rl.question(question, (answer) => {
|
|
60
|
+
resolve(answer);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Make authenticated API call to registry
|
|
66
|
+
*/
|
|
67
|
+
async function apiCall(endpoint, method = 'GET', body) {
|
|
68
|
+
const config = await (0, user_config_1.getConfig)();
|
|
69
|
+
const baseUrl = (config.registryUrl || "https://registry.prpm.dev").replace(/\/$/, '');
|
|
70
|
+
if (!config.token) {
|
|
71
|
+
throw new Error('Authentication required. Please run `prpm login` first.');
|
|
72
|
+
}
|
|
73
|
+
const response = await fetch(`${baseUrl}${endpoint}`, {
|
|
74
|
+
method,
|
|
75
|
+
headers: {
|
|
76
|
+
'Content-Type': 'application/json',
|
|
77
|
+
Authorization: `Bearer ${config.token}`,
|
|
78
|
+
},
|
|
79
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
80
|
+
});
|
|
81
|
+
if (!response.ok) {
|
|
82
|
+
const errorData = await response.json().catch(() => ({}));
|
|
83
|
+
throw new Error(errorData.message || `API request failed: ${response.statusText}`);
|
|
84
|
+
}
|
|
85
|
+
return response;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Resolve package name to UUID
|
|
89
|
+
*/
|
|
90
|
+
async function resolvePackageId(packageName) {
|
|
91
|
+
// If it's already a UUID, return it
|
|
92
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
93
|
+
if (uuidRegex.test(packageName)) {
|
|
94
|
+
return packageName;
|
|
95
|
+
}
|
|
96
|
+
// Search for the package by name
|
|
97
|
+
const config = await (0, user_config_1.getConfig)();
|
|
98
|
+
const baseUrl = (config.registryUrl || "https://registry.prpm.dev").replace(/\/$/, '');
|
|
99
|
+
const response = await fetch(`${baseUrl}/api/v1/search?q=${encodeURIComponent(packageName)}&limit=10`);
|
|
100
|
+
if (!response.ok) {
|
|
101
|
+
throw new Error(`Failed to search for package: ${response.statusText}`);
|
|
102
|
+
}
|
|
103
|
+
const data = await response.json();
|
|
104
|
+
// Find exact match
|
|
105
|
+
const exactMatch = data.packages.find(pkg => pkg.name === packageName);
|
|
106
|
+
if (exactMatch) {
|
|
107
|
+
return exactMatch.id;
|
|
108
|
+
}
|
|
109
|
+
// If no exact match, throw error
|
|
110
|
+
throw new Error(`Package not found: ${packageName}`);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Execute a playground run
|
|
114
|
+
*/
|
|
115
|
+
async function runPlayground(packageName, input, options, sessionId) {
|
|
116
|
+
// Resolve package name to UUID
|
|
117
|
+
const packageId = await resolvePackageId(packageName);
|
|
118
|
+
const response = await apiCall('/api/v1/playground/run', 'POST', {
|
|
119
|
+
package_id: packageId,
|
|
120
|
+
package_version: options.version,
|
|
121
|
+
input,
|
|
122
|
+
model: options.model || 'sonnet',
|
|
123
|
+
use_no_prompt: options.compare || false,
|
|
124
|
+
session_id: sessionId,
|
|
125
|
+
});
|
|
126
|
+
return response.json();
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Format and display playground response
|
|
130
|
+
*/
|
|
131
|
+
function displayResponse(result, showStats = true) {
|
|
132
|
+
// Get the latest assistant response
|
|
133
|
+
const lastMessage = result.conversation[result.conversation.length - 1];
|
|
134
|
+
if (lastMessage?.role === 'assistant') {
|
|
135
|
+
console.log('\n' + 'ā'.repeat(60));
|
|
136
|
+
console.log('š¤ Assistant:');
|
|
137
|
+
console.log('ā'.repeat(60));
|
|
138
|
+
console.log(lastMessage.content);
|
|
139
|
+
console.log('ā'.repeat(60));
|
|
140
|
+
}
|
|
141
|
+
if (showStats) {
|
|
142
|
+
console.log(`\nš Stats:`);
|
|
143
|
+
console.log(` Model: ${result.model}`);
|
|
144
|
+
console.log(` Tokens: ${result.tokens_used.toLocaleString()}`);
|
|
145
|
+
console.log(` Credits spent: ${result.credits_spent}`);
|
|
146
|
+
console.log(` Credits remaining: ${result.credits_remaining}`);
|
|
147
|
+
console.log(` Duration: ${result.duration_ms}ms`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Run interactive playground session
|
|
152
|
+
*/
|
|
153
|
+
async function runInteractive(packageName, options) {
|
|
154
|
+
console.log('\nš® Interactive Playground Mode');
|
|
155
|
+
console.log(` Package: ${packageName}`);
|
|
156
|
+
console.log(` Model: ${options.model || 'sonnet'}`);
|
|
157
|
+
if (options.compare) {
|
|
158
|
+
console.log(` Mode: Comparing against no prompt (raw model baseline)`);
|
|
159
|
+
}
|
|
160
|
+
console.log(` Type 'exit' or 'quit' to end session\n`);
|
|
161
|
+
const rl = createReadline();
|
|
162
|
+
let sessionId;
|
|
163
|
+
let turnCount = 0;
|
|
164
|
+
try {
|
|
165
|
+
while (true) {
|
|
166
|
+
const input = await prompt(rl, `\nš¬ You: `);
|
|
167
|
+
if (input.trim().toLowerCase() === 'exit' || input.trim().toLowerCase() === 'quit') {
|
|
168
|
+
console.log('\nš Ending playground session. Goodbye!');
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
if (!input.trim()) {
|
|
172
|
+
console.log('ā Please enter a message');
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
console.log('\nā³ Processing...');
|
|
177
|
+
const result = await runPlayground(packageName, input, options, sessionId);
|
|
178
|
+
// Store session ID for conversation continuity
|
|
179
|
+
sessionId = result.session_id;
|
|
180
|
+
turnCount++;
|
|
181
|
+
displayResponse(result, true);
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
console.error(`\nā Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
185
|
+
if (error instanceof Error && error.message.includes('Insufficient credits')) {
|
|
186
|
+
console.log('\nš” Get more credits:');
|
|
187
|
+
console.log(' - Purchase credits: prpm buy-credits');
|
|
188
|
+
console.log(' - Subscribe to PRPM+: prpm subscribe');
|
|
189
|
+
console.log(' - Check balance: prpm credits');
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (turnCount > 0) {
|
|
195
|
+
console.log(`\nš Session summary: ${turnCount} turn(s)`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
finally {
|
|
199
|
+
rl.close();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Run single playground query
|
|
204
|
+
*/
|
|
205
|
+
async function runSingle(packageName, input, options) {
|
|
206
|
+
console.log(`\nš® Testing package: ${packageName}`);
|
|
207
|
+
console.log(` Model: ${options.model || 'sonnet'}`);
|
|
208
|
+
if (options.compare) {
|
|
209
|
+
console.log(` Mode: Comparing with package vs. without (baseline)`);
|
|
210
|
+
}
|
|
211
|
+
try {
|
|
212
|
+
if (options.compare) {
|
|
213
|
+
// Comparison mode: run both with package and without
|
|
214
|
+
console.log('\nā³ Processing comparison (2 requests)...');
|
|
215
|
+
// Run with package (without use_no_prompt flag)
|
|
216
|
+
const withPackageOptions = { ...options, compare: false };
|
|
217
|
+
const resultWithPackage = await runPlayground(packageName, input, withPackageOptions);
|
|
218
|
+
// Run without package (with use_no_prompt flag)
|
|
219
|
+
const withoutPackageOptions = { ...options, compare: true };
|
|
220
|
+
const resultWithoutPackage = await runPlayground(packageName, input, withoutPackageOptions);
|
|
221
|
+
// Display both results
|
|
222
|
+
console.log('\n' + 'ā'.repeat(60));
|
|
223
|
+
console.log('š¦ WITH PACKAGE PROMPT');
|
|
224
|
+
console.log('ā'.repeat(60));
|
|
225
|
+
displayResponse(resultWithPackage, false);
|
|
226
|
+
console.log('\n' + 'ā'.repeat(60));
|
|
227
|
+
console.log('šµ WITHOUT PACKAGE (BASELINE)');
|
|
228
|
+
console.log('ā'.repeat(60));
|
|
229
|
+
displayResponse(resultWithoutPackage, false);
|
|
230
|
+
// Combined stats
|
|
231
|
+
console.log(`\nš Combined Stats:`);
|
|
232
|
+
console.log(` Total tokens: ${resultWithPackage.tokens_used + resultWithoutPackage.tokens_used}`);
|
|
233
|
+
console.log(` Total credits: ${resultWithPackage.credits_spent + resultWithoutPackage.credits_spent}`);
|
|
234
|
+
console.log(` Credits remaining: ${resultWithoutPackage.credits_remaining}`);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
// Single mode: run with package only
|
|
238
|
+
console.log('\nā³ Processing...');
|
|
239
|
+
const result = await runPlayground(packageName, input, options);
|
|
240
|
+
displayResponse(result, true);
|
|
241
|
+
}
|
|
242
|
+
console.log(`\nš” Tips:`);
|
|
243
|
+
console.log(` - Use --interactive for multi-turn conversation`);
|
|
244
|
+
console.log(` - Use --compare to test with and without the package prompt`);
|
|
245
|
+
console.log(` - Use --model to choose different models (sonnet, opus, gpt-4o, etc.)`);
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
console.error(`\nā Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
249
|
+
if (error instanceof Error && error.message.includes('Insufficient credits')) {
|
|
250
|
+
console.log('\nš” Get more credits:');
|
|
251
|
+
console.log(' - Purchase credits: prpm buy-credits');
|
|
252
|
+
console.log(' - Subscribe to PRPM+: prpm subscribe');
|
|
253
|
+
console.log(' - Check balance: prpm credits');
|
|
254
|
+
}
|
|
255
|
+
process.exit(1);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Handle the playground command
|
|
260
|
+
*/
|
|
261
|
+
async function handlePlayground(packageName, input, options) {
|
|
262
|
+
const startTime = Date.now();
|
|
263
|
+
let success = false;
|
|
264
|
+
let error;
|
|
265
|
+
try {
|
|
266
|
+
// Validate authentication
|
|
267
|
+
const config = await (0, user_config_1.getConfig)();
|
|
268
|
+
if (!config.token) {
|
|
269
|
+
console.error('ā Authentication required');
|
|
270
|
+
console.log('\nš” Please login first:');
|
|
271
|
+
console.log(' prpm login');
|
|
272
|
+
process.exit(1);
|
|
273
|
+
}
|
|
274
|
+
// Interactive mode or single query
|
|
275
|
+
if (options.interactive || !input) {
|
|
276
|
+
// Interactive mode
|
|
277
|
+
await runInteractive(packageName, options);
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
// Single query mode
|
|
281
|
+
await runSingle(packageName, input, options);
|
|
282
|
+
}
|
|
283
|
+
success = true;
|
|
284
|
+
}
|
|
285
|
+
catch (err) {
|
|
286
|
+
error = err instanceof Error ? err.message : String(err);
|
|
287
|
+
console.error(`\nā Playground execution failed: ${error}`);
|
|
288
|
+
process.exit(1);
|
|
289
|
+
}
|
|
290
|
+
finally {
|
|
291
|
+
await telemetry_1.telemetry.track({
|
|
292
|
+
command: 'playground',
|
|
293
|
+
success,
|
|
294
|
+
error,
|
|
295
|
+
duration: Date.now() - startTime,
|
|
296
|
+
data: {
|
|
297
|
+
packageName,
|
|
298
|
+
model: options.model || 'sonnet',
|
|
299
|
+
compare: options.compare || false,
|
|
300
|
+
interactive: options.interactive || false,
|
|
301
|
+
},
|
|
302
|
+
});
|
|
303
|
+
await telemetry_1.telemetry.shutdown();
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Create the playground command
|
|
308
|
+
*/
|
|
309
|
+
function createPlaygroundCommand() {
|
|
310
|
+
const command = new commander_1.Command('playground');
|
|
311
|
+
command
|
|
312
|
+
.description('Test a package with AI models in the playground')
|
|
313
|
+
.argument('<package>', 'Package name to test')
|
|
314
|
+
.argument('[input]', 'Input text to send to the model (omit for interactive mode)')
|
|
315
|
+
.option('-m, --model <model>', 'AI model to use (sonnet, opus, gpt-4o, gpt-4o-mini, gpt-4-turbo)', 'sonnet')
|
|
316
|
+
.option('-c, --compare', 'Compare against no prompt (test raw model baseline)', false)
|
|
317
|
+
.option('-i, --interactive', 'Start interactive multi-turn conversation mode', false)
|
|
318
|
+
.option('-v, --version <version>', 'Specific package version to test')
|
|
319
|
+
.addHelpText('after', `
|
|
320
|
+
Examples:
|
|
321
|
+
# Single query with default model (Sonnet)
|
|
322
|
+
$ prpm playground @anthropic/code-reviewer "Review this code: console.log('hello')"
|
|
323
|
+
|
|
324
|
+
# Interactive mode for multi-turn conversation
|
|
325
|
+
$ prpm playground @anthropic/brainstorm-assistant --interactive
|
|
326
|
+
|
|
327
|
+
# Compare with and without the package prompt
|
|
328
|
+
$ prpm playground @user/custom-prompt "Test input" --compare
|
|
329
|
+
|
|
330
|
+
# Use a different model
|
|
331
|
+
$ prpm playground @user/prompt --model opus "Complex task requiring Opus"
|
|
332
|
+
$ prpm playground @user/prompt --model gpt-4o "Test with GPT-4o"
|
|
333
|
+
|
|
334
|
+
# Test specific version
|
|
335
|
+
$ prpm playground @user/prompt@1.2.0 "Test input"
|
|
336
|
+
|
|
337
|
+
Available Models:
|
|
338
|
+
sonnet - Claude 3.5 Sonnet (default, balanced performance)
|
|
339
|
+
opus - Claude 3 Opus (most capable, higher cost)
|
|
340
|
+
gpt-4o - GPT-4o (OpenAI's latest)
|
|
341
|
+
gpt-4o-mini - GPT-4o Mini (faster, cheaper)
|
|
342
|
+
gpt-4-turbo - GPT-4 Turbo
|
|
343
|
+
|
|
344
|
+
Note: Playground usage requires credits. Run 'prpm credits' to check balance.
|
|
345
|
+
`)
|
|
346
|
+
.action(async (packageName, input, options) => {
|
|
347
|
+
await handlePlayground(packageName, input, options);
|
|
348
|
+
process.exit(0);
|
|
349
|
+
});
|
|
350
|
+
return command;
|
|
351
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Subscribe command - Subscribe to PRPM+ for monthly credits
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handleSubscribe = handleSubscribe;
|
|
7
|
+
exports.createSubscribeCommand = createSubscribeCommand;
|
|
8
|
+
const commander_1 = require("commander");
|
|
9
|
+
const user_config_1 = require("../core/user-config");
|
|
10
|
+
const telemetry_1 = require("../core/telemetry");
|
|
11
|
+
const child_process_1 = require("child_process");
|
|
12
|
+
const util_1 = require("util");
|
|
13
|
+
const webapp_url_1 = require("../utils/webapp-url");
|
|
14
|
+
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
15
|
+
/**
|
|
16
|
+
* Make authenticated API call
|
|
17
|
+
*/
|
|
18
|
+
async function apiCall(endpoint) {
|
|
19
|
+
const config = await (0, user_config_1.getConfig)();
|
|
20
|
+
const baseUrl = (config.registryUrl || "https://registry.prpm.dev").replace(/\/$/, '');
|
|
21
|
+
if (!config.token) {
|
|
22
|
+
throw new Error('Authentication required. Please run `prpm login` first.');
|
|
23
|
+
}
|
|
24
|
+
const response = await fetch(`${baseUrl}${endpoint}`, {
|
|
25
|
+
headers: {
|
|
26
|
+
Authorization: `Bearer ${config.token}`,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
if (!response.ok) {
|
|
30
|
+
const errorData = await response.json().catch(() => ({}));
|
|
31
|
+
throw new Error(errorData.message || `API request failed: ${response.statusText}`);
|
|
32
|
+
}
|
|
33
|
+
return response;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get current subscription status
|
|
37
|
+
*/
|
|
38
|
+
async function getSubscriptionStatus() {
|
|
39
|
+
const response = await apiCall('/api/v1/playground/credits');
|
|
40
|
+
return response.json();
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Open URL in default browser
|
|
44
|
+
*/
|
|
45
|
+
async function openBrowser(url) {
|
|
46
|
+
const platform = process.platform;
|
|
47
|
+
let command;
|
|
48
|
+
if (platform === 'darwin') {
|
|
49
|
+
command = `open "${url}"`;
|
|
50
|
+
}
|
|
51
|
+
else if (platform === 'win32') {
|
|
52
|
+
command = `start "" "${url}"`;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
// Linux and other Unix-like systems
|
|
56
|
+
command = `xdg-open "${url}"`;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
await execAsync(command);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
// If automatic opening fails, just show the URL
|
|
63
|
+
console.log(`\nš Please open this URL in your browser:`);
|
|
64
|
+
console.log(` ${url}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Poll for subscription status change
|
|
69
|
+
*/
|
|
70
|
+
async function pollForSubscription(initialStatus, maxAttempts = 60, intervalMs = 2000) {
|
|
71
|
+
console.log('\nā³ Waiting for subscription confirmation...');
|
|
72
|
+
console.log(' (This may take a minute. Press Ctrl+C to cancel)');
|
|
73
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
74
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
75
|
+
try {
|
|
76
|
+
const status = await getSubscriptionStatus();
|
|
77
|
+
if (status.prpm_plus_status === 'active' && initialStatus !== 'active') {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
// Show progress indicator
|
|
81
|
+
if (attempt % 5 === 0 && attempt > 0) {
|
|
82
|
+
process.stdout.write('.');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
// Continue polling even if there's an error
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Handle the subscribe command
|
|
94
|
+
*/
|
|
95
|
+
async function handleSubscribe() {
|
|
96
|
+
const startTime = Date.now();
|
|
97
|
+
let success = false;
|
|
98
|
+
let error;
|
|
99
|
+
try {
|
|
100
|
+
const config = await (0, user_config_1.getConfig)();
|
|
101
|
+
if (!config.token) {
|
|
102
|
+
console.error('ā Authentication required');
|
|
103
|
+
console.log('\nš” Please login first:');
|
|
104
|
+
console.log(' prpm login');
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
// Get current status
|
|
108
|
+
console.log('š Checking current subscription status...');
|
|
109
|
+
const initialStatus = await getSubscriptionStatus();
|
|
110
|
+
if (initialStatus.prpm_plus_status === 'active') {
|
|
111
|
+
console.log('\nā
You are already subscribed to PRPM+!');
|
|
112
|
+
console.log(`\nš Current benefits:`);
|
|
113
|
+
console.log(` š° Monthly credits: ${initialStatus.monthly_credits}`);
|
|
114
|
+
console.log(` š¦ Priority support`);
|
|
115
|
+
console.log(` š Early access to new features`);
|
|
116
|
+
console.log('\nš” Manage your subscription at:');
|
|
117
|
+
console.log(' https://prpm.dev/settings/billing');
|
|
118
|
+
process.exit(0);
|
|
119
|
+
}
|
|
120
|
+
console.log('\n⨠Subscribe to PRPM+ and get:');
|
|
121
|
+
console.log(' š° 100 monthly playground credits');
|
|
122
|
+
console.log(' ā»ļø Rollover unused credits (up to 200)');
|
|
123
|
+
console.log(' š¦ Priority support');
|
|
124
|
+
console.log(' š Early access to new features');
|
|
125
|
+
console.log('\nšµ Pricing:');
|
|
126
|
+
console.log(' $6/month for individuals');
|
|
127
|
+
console.log(' $3/month for verified organization members (50% off)');
|
|
128
|
+
// Open subscription page
|
|
129
|
+
const webappUrl = (0, webapp_url_1.getWebappUrl)(config.registryUrl || 'https://registry.prpm.dev');
|
|
130
|
+
const subscribeUrl = `${webappUrl}/playground/credits/subscribe`;
|
|
131
|
+
console.log(`\nš Opening subscription page in your browser...`);
|
|
132
|
+
await openBrowser(subscribeUrl);
|
|
133
|
+
// Poll for subscription confirmation
|
|
134
|
+
const subscribed = await pollForSubscription(initialStatus.prpm_plus_status);
|
|
135
|
+
if (subscribed) {
|
|
136
|
+
const updatedStatus = await getSubscriptionStatus();
|
|
137
|
+
console.log('\n\nš Successfully subscribed to PRPM+!');
|
|
138
|
+
console.log('\nš Your benefits:');
|
|
139
|
+
console.log(` š° Monthly credits: ${updatedStatus.monthly_credits}`);
|
|
140
|
+
console.log(` š³ Current balance: ${updatedStatus.balance} credits`);
|
|
141
|
+
console.log('\nā
You can now:');
|
|
142
|
+
console.log(' - Test packages in playground: prpm playground <package> "<input>"');
|
|
143
|
+
console.log(' - Check credits anytime: prpm credits');
|
|
144
|
+
success = true;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
console.log('\n\nā±ļø Subscription process timed out or was canceled.');
|
|
148
|
+
console.log('\nš” If you completed the subscription, run this to verify:');
|
|
149
|
+
console.log(' prpm credits');
|
|
150
|
+
console.log('\nš” Or visit your account settings:');
|
|
151
|
+
console.log(' https://prpm.dev/settings/billing');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
error = err instanceof Error ? err.message : String(err);
|
|
156
|
+
console.error(`\nā Subscription failed: ${error}`);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
finally {
|
|
160
|
+
await telemetry_1.telemetry.track({
|
|
161
|
+
command: 'subscribe',
|
|
162
|
+
success,
|
|
163
|
+
error,
|
|
164
|
+
duration: Date.now() - startTime,
|
|
165
|
+
});
|
|
166
|
+
await telemetry_1.telemetry.shutdown();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Create the subscribe command
|
|
171
|
+
*/
|
|
172
|
+
function createSubscribeCommand() {
|
|
173
|
+
const command = new commander_1.Command('subscribe');
|
|
174
|
+
command
|
|
175
|
+
.description('Subscribe to PRPM+ for monthly playground credits and benefits')
|
|
176
|
+
.addHelpText('after', `
|
|
177
|
+
PRPM+ Benefits:
|
|
178
|
+
⨠100 monthly playground credits (worth $6+ in API costs)
|
|
179
|
+
ā»ļø Rollover unused credits up to 200 (1-month expiry)
|
|
180
|
+
š¦ Priority support and bug fixes
|
|
181
|
+
š Early access to new features
|
|
182
|
+
š¬ Access to PRPM+ community
|
|
183
|
+
|
|
184
|
+
Pricing:
|
|
185
|
+
Individual: $6/month
|
|
186
|
+
Organization: $3/month (50% discount for verified org members)
|
|
187
|
+
|
|
188
|
+
How it works:
|
|
189
|
+
1. Opens subscription page in your browser
|
|
190
|
+
2. Complete payment with Stripe
|
|
191
|
+
3. Credits are added automatically
|
|
192
|
+
4. Start testing packages immediately
|
|
193
|
+
|
|
194
|
+
Examples:
|
|
195
|
+
# Subscribe to PRPM+
|
|
196
|
+
$ prpm subscribe
|
|
197
|
+
|
|
198
|
+
# After subscribing, check your credits
|
|
199
|
+
$ prpm credits
|
|
200
|
+
|
|
201
|
+
# Test packages in playground
|
|
202
|
+
$ prpm playground @anthropic/assistant "Help me brainstorm ideas"
|
|
203
|
+
|
|
204
|
+
Note: You can cancel anytime from https://prpm.dev/settings/billing
|
|
205
|
+
`)
|
|
206
|
+
.action(async () => {
|
|
207
|
+
await handleSubscribe();
|
|
208
|
+
process.exit(0);
|
|
209
|
+
});
|
|
210
|
+
return command;
|
|
211
|
+
}
|
package/dist/core/filesystem.js
CHANGED
|
@@ -11,6 +11,8 @@ exports.ensureDirectoryExists = ensureDirectoryExists;
|
|
|
11
11
|
exports.saveFile = saveFile;
|
|
12
12
|
exports.deleteFile = deleteFile;
|
|
13
13
|
exports.fileExists = fileExists;
|
|
14
|
+
exports.directoryExists = directoryExists;
|
|
15
|
+
exports.autoDetectFormat = autoDetectFormat;
|
|
14
16
|
exports.generateId = generateId;
|
|
15
17
|
exports.stripAuthorNamespace = stripAuthorNamespace;
|
|
16
18
|
exports.getInstalledFilePath = getInstalledFilePath;
|
|
@@ -119,6 +121,39 @@ async function fileExists(filePath) {
|
|
|
119
121
|
return false;
|
|
120
122
|
}
|
|
121
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* Check if a directory exists
|
|
126
|
+
*/
|
|
127
|
+
async function directoryExists(dirPath) {
|
|
128
|
+
try {
|
|
129
|
+
const stats = await fs_1.promises.stat(dirPath);
|
|
130
|
+
return stats.isDirectory();
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Auto-detect the format based on existing directories in the current project
|
|
138
|
+
* Returns the format if a matching directory is found, or null if none found
|
|
139
|
+
*/
|
|
140
|
+
async function autoDetectFormat() {
|
|
141
|
+
const formatDirs = [
|
|
142
|
+
{ format: 'cursor', dir: '.cursor' },
|
|
143
|
+
{ format: 'claude', dir: '.claude' },
|
|
144
|
+
{ format: 'continue', dir: '.continue' },
|
|
145
|
+
{ format: 'windsurf', dir: '.windsurf' },
|
|
146
|
+
{ format: 'copilot', dir: '.github/instructions' },
|
|
147
|
+
{ format: 'kiro', dir: '.kiro' },
|
|
148
|
+
{ format: 'agents.md', dir: '.agents' },
|
|
149
|
+
];
|
|
150
|
+
for (const { format, dir } of formatDirs) {
|
|
151
|
+
if (await directoryExists(dir)) {
|
|
152
|
+
return format;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
122
157
|
/**
|
|
123
158
|
* Generate a unique ID from filename
|
|
124
159
|
*/
|
package/dist/index.js
CHANGED
|
@@ -27,6 +27,10 @@ const schema_1 = require("./commands/schema");
|
|
|
27
27
|
const init_1 = require("./commands/init");
|
|
28
28
|
const config_1 = require("./commands/config");
|
|
29
29
|
const catalog_1 = require("./commands/catalog");
|
|
30
|
+
const playground_1 = require("./commands/playground");
|
|
31
|
+
const credits_1 = require("./commands/credits");
|
|
32
|
+
const subscribe_1 = require("./commands/subscribe");
|
|
33
|
+
const buy_credits_1 = require("./commands/buy-credits");
|
|
30
34
|
const telemetry_2 = require("./core/telemetry");
|
|
31
35
|
// Read version from package.json
|
|
32
36
|
function getVersion() {
|
|
@@ -65,6 +69,11 @@ program.addCommand((0, list_1.createListCommand)());
|
|
|
65
69
|
program.addCommand((0, uninstall_1.createUninstallCommand)());
|
|
66
70
|
program.addCommand((0, index_1.createIndexCommand)());
|
|
67
71
|
program.addCommand((0, telemetry_1.createTelemetryCommand)());
|
|
72
|
+
// Playground commands
|
|
73
|
+
program.addCommand((0, playground_1.createPlaygroundCommand)());
|
|
74
|
+
program.addCommand((0, credits_1.createCreditsCommand)());
|
|
75
|
+
program.addCommand((0, subscribe_1.createSubscribeCommand)());
|
|
76
|
+
program.addCommand((0, buy_credits_1.createBuyCreditsCommand)());
|
|
68
77
|
// Utility commands
|
|
69
78
|
program.addCommand((0, schema_1.createSchemaCommand)());
|
|
70
79
|
program.addCommand((0, config_1.createConfigCommand)());
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Utility to convert registry URL to webapp URL
|
|
4
|
+
* Handles localhost, production, and custom registry URLs
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.getWebappUrl = getWebappUrl;
|
|
8
|
+
/**
|
|
9
|
+
* Convert a registry URL to its corresponding webapp URL
|
|
10
|
+
*
|
|
11
|
+
* @param registryUrl - The registry URL (e.g., https://registry.prpm.dev)
|
|
12
|
+
* @returns The webapp URL (e.g., https://prpm.dev)
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* // Production
|
|
16
|
+
* getWebappUrl('https://registry.prpm.dev') // => 'https://prpm.dev'
|
|
17
|
+
*
|
|
18
|
+
* // Local development
|
|
19
|
+
* getWebappUrl('http://localhost:3111') // => 'http://localhost:5173'
|
|
20
|
+
*
|
|
21
|
+
* // Custom registry
|
|
22
|
+
* getWebappUrl('https://registry.custom.com') // => 'https://custom.com'
|
|
23
|
+
*/
|
|
24
|
+
function getWebappUrl(registryUrl) {
|
|
25
|
+
const cleanUrl = registryUrl.replace(/\/$/, '').replace(/\/api\/?$/, '');
|
|
26
|
+
if (cleanUrl.includes('localhost') || cleanUrl.includes('127.0.0.1')) {
|
|
27
|
+
// Local development: registry on port 3111, webapp on port 5173
|
|
28
|
+
return cleanUrl.replace(':3111', ':5173');
|
|
29
|
+
}
|
|
30
|
+
if (cleanUrl.includes('registry.prpm.dev')) {
|
|
31
|
+
// Production: always use prpm.dev webapp
|
|
32
|
+
return 'https://prpm.dev';
|
|
33
|
+
}
|
|
34
|
+
// Custom registry: assume webapp is on same host without 'registry.' subdomain
|
|
35
|
+
try {
|
|
36
|
+
const url = new URL(cleanUrl);
|
|
37
|
+
const hostname = url.hostname.replace(/^registry\./, '');
|
|
38
|
+
return `${url.protocol}//${hostname}`;
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// If URL parsing fails, return as-is
|
|
42
|
+
return cleanUrl;
|
|
43
|
+
}
|
|
44
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prpm",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Prompt Package Manager CLI - Install and manage prompt-based files",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"license": "MIT",
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@octokit/rest": "^22.0.0",
|
|
48
|
-
"@pr-pm/registry-client": "^1.3.
|
|
49
|
-
"@pr-pm/types": "^0.2.
|
|
48
|
+
"@pr-pm/registry-client": "^1.3.5",
|
|
49
|
+
"@pr-pm/types": "^0.2.6",
|
|
50
50
|
"ajv": "^8.17.1",
|
|
51
51
|
"ajv-formats": "^3.0.1",
|
|
52
52
|
"commander": "^11.1.0",
|