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.
- package/dist/index.js +14257 -109
- package/package.json +11 -9
- package/dist/__tests__/e2e/test-helpers.js +0 -153
- package/dist/commands/buy-credits.js +0 -224
- package/dist/commands/catalog.js +0 -365
- package/dist/commands/collections.js +0 -655
- package/dist/commands/config.js +0 -161
- package/dist/commands/credits.js +0 -186
- package/dist/commands/index.js +0 -184
- package/dist/commands/info.js +0 -78
- package/dist/commands/init.js +0 -684
- package/dist/commands/install.js +0 -829
- package/dist/commands/list.js +0 -198
- package/dist/commands/login.js +0 -316
- package/dist/commands/outdated.js +0 -130
- package/dist/commands/playground.js +0 -637
- package/dist/commands/popular.js +0 -33
- package/dist/commands/publish.js +0 -803
- package/dist/commands/schema.js +0 -41
- package/dist/commands/search.js +0 -446
- package/dist/commands/starred.js +0 -147
- package/dist/commands/subscribe.js +0 -211
- package/dist/commands/telemetry.js +0 -104
- package/dist/commands/trending.js +0 -86
- package/dist/commands/uninstall.js +0 -120
- package/dist/commands/update.js +0 -121
- package/dist/commands/upgrade.js +0 -121
- package/dist/commands/whoami.js +0 -83
- package/dist/core/claude-config.js +0 -91
- package/dist/core/cursor-config.js +0 -130
- package/dist/core/downloader.js +0 -64
- package/dist/core/errors.js +0 -29
- package/dist/core/filesystem.js +0 -246
- package/dist/core/lockfile.js +0 -292
- package/dist/core/marketplace-converter.js +0 -224
- package/dist/core/prompts.js +0 -62
- package/dist/core/registry-client.js +0 -305
- package/dist/core/schema-validator.js +0 -74
- package/dist/core/telemetry.js +0 -253
- package/dist/core/user-config.js +0 -147
- package/dist/types/registry.js +0 -12
- package/dist/types.js +0 -9
- package/dist/utils/license-extractor.js +0 -122
- package/dist/utils/multi-package.js +0 -117
- package/dist/utils/parallel-publisher.js +0 -144
- package/dist/utils/script-executor.js +0 -72
- package/dist/utils/snippet-extractor.js +0 -77
- package/dist/utils/webapp-url.js +0 -44
package/package.json
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prpm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Prompt Package Manager CLI - Install and manage prompt-based files",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"prpm": "dist/index.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
-
"build": "
|
|
11
|
-
"build:watch": "
|
|
10
|
+
"build": "tsup",
|
|
11
|
+
"build:watch": "tsup --watch",
|
|
12
12
|
"dev": "tsx watch --clear-screen=false src/index.ts",
|
|
13
13
|
"dev:with-build": "concurrently --kill-others --names \"BUILD,CLI\" \"tsc --watch --preserveWatchOutput\" \"nodemon --delay 1 --watch dist dist/index.js\"",
|
|
14
14
|
"dev:build-only": "tsc --watch --preserveWatchOutput",
|
|
15
15
|
"start": "node dist/index.js",
|
|
16
|
-
"test": "jest",
|
|
17
|
-
"test:watch": "jest --watch",
|
|
18
|
-
"test:coverage": "jest --coverage",
|
|
19
|
-
"test:ci": "jest --ci --coverage --watchAll=false",
|
|
16
|
+
"test": "jest --runInBand",
|
|
17
|
+
"test:watch": "jest --watch --runInBand",
|
|
18
|
+
"test:coverage": "jest --coverage --runInBand",
|
|
19
|
+
"test:ci": "jest --ci --coverage --watchAll=false --runInBand",
|
|
20
20
|
"build:binary": "echo 'Binary builds deprecated - use npm install -g prpm or Homebrew instead'",
|
|
21
21
|
"typecheck": "tsc --noEmit",
|
|
22
22
|
"version:bump": "node scripts/bump-version.js",
|
|
@@ -45,8 +45,9 @@
|
|
|
45
45
|
"license": "MIT",
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@octokit/rest": "^22.0.0",
|
|
48
|
-
"@pr-pm/
|
|
49
|
-
"@pr-pm/
|
|
48
|
+
"@pr-pm/converters": "^0.1.0",
|
|
49
|
+
"@pr-pm/registry-client": "^1.4.0",
|
|
50
|
+
"@pr-pm/types": "^0.3.0",
|
|
50
51
|
"ajv": "^8.17.1",
|
|
51
52
|
"ajv-formats": "^3.0.1",
|
|
52
53
|
"commander": "^11.1.0",
|
|
@@ -63,6 +64,7 @@
|
|
|
63
64
|
"nodemon": "^3.0.2",
|
|
64
65
|
"ts-jest": "^29.1.1",
|
|
65
66
|
"ts-node": "^10.9.1",
|
|
67
|
+
"tsup": "^8.5.1",
|
|
66
68
|
"tsx": "^4.20.6",
|
|
67
69
|
"typescript": "^5.3.2"
|
|
68
70
|
},
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* E2E Test Helpers
|
|
4
|
-
* Shared utilities for end-to-end CLI testing
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.createTestDir = createTestDir;
|
|
8
|
-
exports.cleanupTestDir = cleanupTestDir;
|
|
9
|
-
exports.createMockPackage = createMockPackage;
|
|
10
|
-
exports.createMockCollection = createMockCollection;
|
|
11
|
-
exports.createMockConfig = createMockConfig;
|
|
12
|
-
exports.createMockFetch = createMockFetch;
|
|
13
|
-
exports.delay = delay;
|
|
14
|
-
exports.setupGlobalMocks = setupGlobalMocks;
|
|
15
|
-
exports.mockProcessExit = mockProcessExit;
|
|
16
|
-
const promises_1 = require("fs/promises");
|
|
17
|
-
const path_1 = require("path");
|
|
18
|
-
const os_1 = require("os");
|
|
19
|
-
/**
|
|
20
|
-
* Create a temporary test directory
|
|
21
|
-
*/
|
|
22
|
-
async function createTestDir() {
|
|
23
|
-
const testDir = (0, path_1.join)((0, os_1.tmpdir)(), `prpm-e2e-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
24
|
-
await (0, promises_1.mkdir)(testDir, { recursive: true });
|
|
25
|
-
return testDir;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Clean up test directory
|
|
29
|
-
*/
|
|
30
|
-
async function cleanupTestDir(testDir) {
|
|
31
|
-
try {
|
|
32
|
-
await (0, promises_1.rm)(testDir, { recursive: true, force: true });
|
|
33
|
-
}
|
|
34
|
-
catch {
|
|
35
|
-
// Ignore cleanup errors
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Create a mock package manifest
|
|
40
|
-
*/
|
|
41
|
-
async function createMockPackage(testDir, name, type = 'cursor', version = '1.0.0') {
|
|
42
|
-
const manifest = {
|
|
43
|
-
name,
|
|
44
|
-
version,
|
|
45
|
-
description: `Test package ${name}`,
|
|
46
|
-
format: type,
|
|
47
|
-
subtype: 'rule',
|
|
48
|
-
author: 'test-author',
|
|
49
|
-
tags: ['test', type],
|
|
50
|
-
files: ['prpm.json', '.cursorrules'],
|
|
51
|
-
};
|
|
52
|
-
const manifestPath = (0, path_1.join)(testDir, 'prpm.json');
|
|
53
|
-
await (0, promises_1.writeFile)(manifestPath, JSON.stringify(manifest, null, 2));
|
|
54
|
-
// Create a sample .cursorrules file
|
|
55
|
-
const rulesPath = (0, path_1.join)(testDir, '.cursorrules');
|
|
56
|
-
await (0, promises_1.writeFile)(rulesPath, '# Test cursor rules\n\nAlways write tests.\n');
|
|
57
|
-
return manifestPath;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Create a mock collection manifest
|
|
61
|
-
*/
|
|
62
|
-
async function createMockCollection(testDir, id, packages) {
|
|
63
|
-
const manifest = {
|
|
64
|
-
id,
|
|
65
|
-
name: `Test Collection ${id}`,
|
|
66
|
-
description: 'A test collection for E2E testing',
|
|
67
|
-
category: 'development',
|
|
68
|
-
tags: ['test', 'automation'],
|
|
69
|
-
packages,
|
|
70
|
-
icon: 'š¦',
|
|
71
|
-
};
|
|
72
|
-
const manifestPath = (0, path_1.join)(testDir, 'collection.json');
|
|
73
|
-
await (0, promises_1.writeFile)(manifestPath, JSON.stringify(manifest, null, 2));
|
|
74
|
-
return manifestPath;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Create a mock user config
|
|
78
|
-
*/
|
|
79
|
-
async function createMockConfig(configPath, options) {
|
|
80
|
-
const config = {
|
|
81
|
-
token: options.token || 'test-token-123',
|
|
82
|
-
registryUrl: options.registryUrl || 'http://localhost:3111',
|
|
83
|
-
};
|
|
84
|
-
await (0, promises_1.mkdir)((0, path_1.join)(configPath, '..'), { recursive: true });
|
|
85
|
-
await (0, promises_1.writeFile)(configPath, JSON.stringify(config, null, 2));
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Mock fetch response for registry API
|
|
89
|
-
*/
|
|
90
|
-
function createMockFetch() {
|
|
91
|
-
const responses = new Map();
|
|
92
|
-
const mockFetch = jest.fn(async (url, options) => {
|
|
93
|
-
const key = `${options?.method || 'GET'} ${url}`;
|
|
94
|
-
const response = responses.get(key) || responses.get(url);
|
|
95
|
-
if (!response) {
|
|
96
|
-
return {
|
|
97
|
-
ok: false,
|
|
98
|
-
status: 404,
|
|
99
|
-
statusText: 'Not Found',
|
|
100
|
-
json: async () => ({ error: 'Not found' }),
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
if (typeof response === 'function') {
|
|
104
|
-
return response(url, options);
|
|
105
|
-
}
|
|
106
|
-
return {
|
|
107
|
-
ok: true,
|
|
108
|
-
status: 200,
|
|
109
|
-
json: async () => response,
|
|
110
|
-
arrayBuffer: async () => Buffer.from('mock-data').buffer,
|
|
111
|
-
};
|
|
112
|
-
});
|
|
113
|
-
return {
|
|
114
|
-
fetch: mockFetch,
|
|
115
|
-
addResponse: (key, response) => {
|
|
116
|
-
responses.set(key, response);
|
|
117
|
-
},
|
|
118
|
-
clear: () => {
|
|
119
|
-
responses.clear();
|
|
120
|
-
mockFetch.mockClear();
|
|
121
|
-
},
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Wait for async operations
|
|
126
|
-
*/
|
|
127
|
-
function delay(ms) {
|
|
128
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Setup global mocks for E2E tests
|
|
132
|
-
*/
|
|
133
|
-
function setupGlobalMocks() {
|
|
134
|
-
// Mock console to reduce noise
|
|
135
|
-
beforeAll(() => {
|
|
136
|
-
jest.spyOn(console, 'log').mockImplementation();
|
|
137
|
-
jest.spyOn(console, 'error').mockImplementation();
|
|
138
|
-
jest.spyOn(console, 'warn').mockImplementation();
|
|
139
|
-
});
|
|
140
|
-
afterAll(() => {
|
|
141
|
-
jest.restoreAllMocks();
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
/**
|
|
145
|
-
* Mock process.exit to throw instead of exiting
|
|
146
|
-
* @deprecated No longer needed - commands now throw CLIError instead of calling process.exit
|
|
147
|
-
*/
|
|
148
|
-
function mockProcessExit() {
|
|
149
|
-
const mockExit = jest.spyOn(process, 'exit').mockImplementation((code) => {
|
|
150
|
-
throw new Error(`Process exited with code ${code}`);
|
|
151
|
-
});
|
|
152
|
-
return mockExit;
|
|
153
|
-
}
|
|
@@ -1,224 +0,0 @@
|
|
|
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 errors_1 = require("../core/errors");
|
|
15
|
-
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
16
|
-
/**
|
|
17
|
-
* Make authenticated API call
|
|
18
|
-
*/
|
|
19
|
-
async function apiCall(endpoint) {
|
|
20
|
-
const config = await (0, user_config_1.getConfig)();
|
|
21
|
-
const baseUrl = (config.registryUrl || 'https://registry.prpm.dev').replace(/\/$/, '');
|
|
22
|
-
if (!config.token) {
|
|
23
|
-
throw new Error('Authentication required. Please run `prpm login` first.');
|
|
24
|
-
}
|
|
25
|
-
const response = await fetch(`${baseUrl}${endpoint}`, {
|
|
26
|
-
headers: {
|
|
27
|
-
Authorization: `Bearer ${config.token}`,
|
|
28
|
-
},
|
|
29
|
-
});
|
|
30
|
-
if (!response.ok) {
|
|
31
|
-
const errorData = await response.json().catch(() => ({}));
|
|
32
|
-
throw new Error(errorData.message || `API request failed: ${response.statusText}`);
|
|
33
|
-
}
|
|
34
|
-
return response;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Get current credits balance
|
|
38
|
-
*/
|
|
39
|
-
async function getBalance() {
|
|
40
|
-
const response = await apiCall('/api/v1/playground/credits');
|
|
41
|
-
return response.json();
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Open URL in default browser
|
|
45
|
-
*/
|
|
46
|
-
async function openBrowser(url) {
|
|
47
|
-
const platform = process.platform;
|
|
48
|
-
let command;
|
|
49
|
-
if (platform === 'darwin') {
|
|
50
|
-
command = `open "${url}"`;
|
|
51
|
-
}
|
|
52
|
-
else if (platform === 'win32') {
|
|
53
|
-
command = `start "" "${url}"`;
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
// Linux and other Unix-like systems
|
|
57
|
-
command = `xdg-open "${url}"`;
|
|
58
|
-
}
|
|
59
|
-
try {
|
|
60
|
-
await execAsync(command);
|
|
61
|
-
}
|
|
62
|
-
catch (error) {
|
|
63
|
-
// If automatic opening fails, just show the URL
|
|
64
|
-
console.log(`\nš Please open this URL in your browser:`);
|
|
65
|
-
console.log(` ${url}`);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Poll for credits balance increase
|
|
70
|
-
*/
|
|
71
|
-
async function pollForPurchase(initialBalance, maxAttempts = 60, intervalMs = 2000) {
|
|
72
|
-
console.log('\nā³ Waiting for purchase confirmation...');
|
|
73
|
-
console.log(' (This may take a minute. Press Ctrl+C to cancel)');
|
|
74
|
-
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
75
|
-
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
76
|
-
try {
|
|
77
|
-
const status = await getBalance();
|
|
78
|
-
if (status.balance > initialBalance) {
|
|
79
|
-
return status.balance - initialBalance;
|
|
80
|
-
}
|
|
81
|
-
// Show progress indicator
|
|
82
|
-
if (attempt % 5 === 0 && attempt > 0) {
|
|
83
|
-
process.stdout.write('.');
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
catch (error) {
|
|
87
|
-
// Continue polling even if there's an error
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Handle the buy-credits command
|
|
95
|
-
*/
|
|
96
|
-
async function handleBuyCredits(options) {
|
|
97
|
-
const startTime = Date.now();
|
|
98
|
-
let success = false;
|
|
99
|
-
let error;
|
|
100
|
-
try {
|
|
101
|
-
const config = await (0, user_config_1.getConfig)();
|
|
102
|
-
if (!config.token) {
|
|
103
|
-
console.error('ā Authentication required');
|
|
104
|
-
console.log('\nš” Please login first:');
|
|
105
|
-
console.log(' prpm login');
|
|
106
|
-
throw new errors_1.CLIError('ā Authentication required', 1);
|
|
107
|
-
}
|
|
108
|
-
// Get current balance
|
|
109
|
-
console.log('š Checking current credits balance...');
|
|
110
|
-
const initialStatus = await getBalance();
|
|
111
|
-
console.log(` Current balance: ${initialStatus.balance} credits`);
|
|
112
|
-
console.log('\nš° Available credit packages:');
|
|
113
|
-
console.log(' Small: 100 credits - $5.00 ($0.05 per credit)');
|
|
114
|
-
console.log(' Medium: 250 credits - $11.25 ($0.045 per credit) - 10% savings');
|
|
115
|
-
console.log(' Large: 600 credits - $24.00 ($0.04 per credit) - 20% savings');
|
|
116
|
-
console.log('\n⨠These credits never expire!');
|
|
117
|
-
console.log('š” Tip: Subscribe to PRPM+ for 100 monthly credits at just $6/month');
|
|
118
|
-
// Build URL with package parameter if specified
|
|
119
|
-
const webappUrl = (0, webapp_url_1.getWebappUrl)(config.registryUrl || 'https://registry.prpm.dev');
|
|
120
|
-
let purchaseUrl = `${webappUrl}/playground/credits/buy`;
|
|
121
|
-
if (options.package) {
|
|
122
|
-
const validPackages = ['small', 'medium', 'large'];
|
|
123
|
-
if (!validPackages.includes(options.package)) {
|
|
124
|
-
console.error(`\nā Invalid package: ${options.package}`);
|
|
125
|
-
console.log(' Valid options: small, medium, large');
|
|
126
|
-
throw new errors_1.CLIError(`\nā Invalid package: ${options.package}`, 1);
|
|
127
|
-
}
|
|
128
|
-
purchaseUrl += `?package=${options.package}`;
|
|
129
|
-
}
|
|
130
|
-
// Open purchase page
|
|
131
|
-
console.log(`\nš Opening purchase page in your browser...`);
|
|
132
|
-
await openBrowser(purchaseUrl);
|
|
133
|
-
// Poll for purchase confirmation
|
|
134
|
-
const creditsAdded = await pollForPurchase(initialStatus.balance);
|
|
135
|
-
if (creditsAdded !== null) {
|
|
136
|
-
const updatedStatus = await getBalance();
|
|
137
|
-
console.log('\n\nš Successfully purchased credits!');
|
|
138
|
-
console.log('\nš Credits added:');
|
|
139
|
-
console.log(` + ${creditsAdded} credits`);
|
|
140
|
-
console.log(` š³ New balance: ${updatedStatus.balance} credits`);
|
|
141
|
-
console.log('\nā
You can now:');
|
|
142
|
-
console.log(' - Test packages: prpm playground <package> "<input>"');
|
|
143
|
-
console.log(' - Check balance: prpm credits');
|
|
144
|
-
console.log(' - View history: prpm credits --history');
|
|
145
|
-
success = true;
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
console.log('\n\nā±ļø Purchase process timed out or was canceled.');
|
|
149
|
-
console.log('\nš” If you completed the purchase, run this to verify:');
|
|
150
|
-
console.log(' prpm credits');
|
|
151
|
-
console.log('\nš” Or check your transaction history:');
|
|
152
|
-
console.log(' prpm credits --history');
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
catch (err) {
|
|
156
|
-
error = err instanceof Error ? err.message : String(err);
|
|
157
|
-
console.error(`\nā Purchase failed: ${error}`);
|
|
158
|
-
throw new errors_1.CLIError(`\nā Purchase failed: ${error}`, 1);
|
|
159
|
-
}
|
|
160
|
-
finally {
|
|
161
|
-
await telemetry_1.telemetry.track({
|
|
162
|
-
command: 'buy-credits',
|
|
163
|
-
success,
|
|
164
|
-
error,
|
|
165
|
-
duration: Date.now() - startTime,
|
|
166
|
-
data: {
|
|
167
|
-
package: options.package,
|
|
168
|
-
},
|
|
169
|
-
});
|
|
170
|
-
await telemetry_1.telemetry.shutdown();
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Create the buy-credits command
|
|
175
|
-
*/
|
|
176
|
-
function createBuyCreditsCommand() {
|
|
177
|
-
const command = new commander_1.Command('buy-credits');
|
|
178
|
-
command
|
|
179
|
-
.description('Purchase one-time playground credits (never expire)')
|
|
180
|
-
.option('-p, --package <package>', 'Credit package to purchase (small, medium, large)')
|
|
181
|
-
.addHelpText('after', `
|
|
182
|
-
Credit Packages:
|
|
183
|
-
Small: 100 credits - $5.00 ($0.05 per credit)
|
|
184
|
-
Medium: 250 credits - $11.25 ($0.045 per credit) - 10% savings
|
|
185
|
-
Large: 600 credits - $24.00 ($0.04 per credit) - 20% savings
|
|
186
|
-
|
|
187
|
-
Credits Usage:
|
|
188
|
-
- Testing packages in playground uses 1-5 credits per request
|
|
189
|
-
- Token-based pricing: 1 credit = 5,000 tokens
|
|
190
|
-
- Model multipliers apply (Opus 5x, GPT-4o 2x, etc.)
|
|
191
|
-
- Credits never expire
|
|
192
|
-
|
|
193
|
-
How it works:
|
|
194
|
-
1. Opens purchase page in your browser
|
|
195
|
-
2. Select package and complete payment with Stripe
|
|
196
|
-
3. Credits are added to your account immediately
|
|
197
|
-
4. Start testing packages right away
|
|
198
|
-
|
|
199
|
-
Examples:
|
|
200
|
-
# Browse all packages
|
|
201
|
-
$ prpm buy-credits
|
|
202
|
-
|
|
203
|
-
# Pre-select a specific package
|
|
204
|
-
$ prpm buy-credits --package small
|
|
205
|
-
$ prpm buy-credits --package medium
|
|
206
|
-
$ prpm buy-credits --package large
|
|
207
|
-
|
|
208
|
-
# After purchase, check balance
|
|
209
|
-
$ prpm credits
|
|
210
|
-
|
|
211
|
-
# Test packages in playground
|
|
212
|
-
$ prpm playground @user/prompt "test input"
|
|
213
|
-
|
|
214
|
-
š” Better Value:
|
|
215
|
-
Subscribe to PRPM+ for 100 monthly credits at just $6/month
|
|
216
|
-
Run: prpm subscribe
|
|
217
|
-
|
|
218
|
-
Note: Purchased credits are one-time and never expire, unlike monthly credits.
|
|
219
|
-
`)
|
|
220
|
-
.action(async (options) => {
|
|
221
|
-
await handleBuyCredits(options);
|
|
222
|
-
});
|
|
223
|
-
return command;
|
|
224
|
-
}
|