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/dist/commands/list.js
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* List command implementation
|
|
4
|
-
*/
|
|
5
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
6
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
|
-
};
|
|
8
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.handleList = handleList;
|
|
10
|
-
exports.createListCommand = createListCommand;
|
|
11
|
-
const commander_1 = require("commander");
|
|
12
|
-
const lockfile_1 = require("../core/lockfile");
|
|
13
|
-
const telemetry_1 = require("../core/telemetry");
|
|
14
|
-
const fs_1 = require("fs");
|
|
15
|
-
const path_1 = __importDefault(require("path"));
|
|
16
|
-
const errors_1 = require("../core/errors");
|
|
17
|
-
/**
|
|
18
|
-
* Get destination directory based on package type
|
|
19
|
-
*/
|
|
20
|
-
function getDestinationDir(type) {
|
|
21
|
-
switch (type) {
|
|
22
|
-
case 'cursor':
|
|
23
|
-
return '.cursor/rules';
|
|
24
|
-
case 'claude':
|
|
25
|
-
return '.claude/agents';
|
|
26
|
-
case 'claude-agent':
|
|
27
|
-
return '.claude/agents';
|
|
28
|
-
case 'claude-skill':
|
|
29
|
-
return '.claude/skills';
|
|
30
|
-
case 'claude-slash-command':
|
|
31
|
-
return '.claude/commands';
|
|
32
|
-
case 'continue':
|
|
33
|
-
return '.continue/rules';
|
|
34
|
-
case 'windsurf':
|
|
35
|
-
return '.windsurf/rules';
|
|
36
|
-
case 'agents.md':
|
|
37
|
-
return '.';
|
|
38
|
-
case 'generic':
|
|
39
|
-
return '.prompts';
|
|
40
|
-
case 'mcp':
|
|
41
|
-
return '.mcp';
|
|
42
|
-
default:
|
|
43
|
-
return '.prompts';
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Strip author namespace from package ID
|
|
48
|
-
*/
|
|
49
|
-
function stripAuthorNamespace(packageId) {
|
|
50
|
-
const parts = packageId.split('/');
|
|
51
|
-
return parts[parts.length - 1];
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Find the actual file location for a package
|
|
55
|
-
*/
|
|
56
|
-
async function findPackageLocation(id, format, subtype) {
|
|
57
|
-
if (!format)
|
|
58
|
-
return null;
|
|
59
|
-
if (format === 'agents.md') {
|
|
60
|
-
try {
|
|
61
|
-
await fs_1.promises.access('AGENTS.md');
|
|
62
|
-
return 'AGENTS.md';
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
const baseDir = getDestinationDir(format);
|
|
69
|
-
// Strip author namespace to get actual package name used in file system
|
|
70
|
-
const packageName = stripAuthorNamespace(id);
|
|
71
|
-
// Try different file extensions based on format
|
|
72
|
-
const extensions = format === 'cursor' ? ['.mdc', '.md'] : ['.md'];
|
|
73
|
-
// Try direct file: <dir>/<packageName>.ext
|
|
74
|
-
for (const ext of extensions) {
|
|
75
|
-
const directPath = path_1.default.join(baseDir, `${packageName}${ext}`);
|
|
76
|
-
try {
|
|
77
|
-
await fs_1.promises.access(directPath);
|
|
78
|
-
return directPath;
|
|
79
|
-
}
|
|
80
|
-
catch {
|
|
81
|
-
// File doesn't exist, continue
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
// Try subdirectory: <dir>/<packageName>/SKILL.md or <dir>/<packageName>/AGENT.md
|
|
85
|
-
if (subtype === 'skill') {
|
|
86
|
-
const skillPath = path_1.default.join(baseDir, packageName, 'SKILL.md');
|
|
87
|
-
try {
|
|
88
|
-
await fs_1.promises.access(skillPath);
|
|
89
|
-
return skillPath;
|
|
90
|
-
}
|
|
91
|
-
catch {
|
|
92
|
-
// Not found
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
if (subtype === 'agent' || format === 'claude') {
|
|
96
|
-
const agentPath = path_1.default.join(baseDir, packageName, 'AGENT.md');
|
|
97
|
-
try {
|
|
98
|
-
await fs_1.promises.access(agentPath);
|
|
99
|
-
return agentPath;
|
|
100
|
-
}
|
|
101
|
-
catch {
|
|
102
|
-
// Not found
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
return null;
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Display packages in a formatted table
|
|
109
|
-
*/
|
|
110
|
-
async function displayPackages(packages) {
|
|
111
|
-
if (packages.length === 0) {
|
|
112
|
-
console.log('š¦ No packages installed');
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
console.log('š¦ Installed packages:');
|
|
116
|
-
console.log('');
|
|
117
|
-
// Find file locations
|
|
118
|
-
const packagesWithLocations = await Promise.all(packages.map(async (pkg) => ({
|
|
119
|
-
...pkg,
|
|
120
|
-
location: await findPackageLocation(pkg.id, pkg.format, pkg.subtype)
|
|
121
|
-
})));
|
|
122
|
-
// Helper to format type display
|
|
123
|
-
const formatType = (format, subtype) => {
|
|
124
|
-
if (!format)
|
|
125
|
-
return '';
|
|
126
|
-
return subtype ? `${format}/${subtype}` : format;
|
|
127
|
-
};
|
|
128
|
-
// Calculate column widths
|
|
129
|
-
const idWidth = Math.max(8, ...packagesWithLocations.map(p => p.id.length));
|
|
130
|
-
const versionWidth = Math.max(7, ...packagesWithLocations.map(p => p.version.length));
|
|
131
|
-
const typeWidth = Math.max(6, ...packagesWithLocations.map(p => formatType(p.format, p.subtype).length));
|
|
132
|
-
const locationWidth = Math.max(8, ...packagesWithLocations.map(p => (p.installedPath || 'N/A').length));
|
|
133
|
-
// Header
|
|
134
|
-
const header = [
|
|
135
|
-
'ID'.padEnd(idWidth),
|
|
136
|
-
'VERSION'.padEnd(versionWidth),
|
|
137
|
-
'TYPE'.padEnd(typeWidth),
|
|
138
|
-
'LOCATION'.padEnd(locationWidth)
|
|
139
|
-
].join(' | ');
|
|
140
|
-
console.log(header);
|
|
141
|
-
console.log('-'.repeat(header.length));
|
|
142
|
-
// Rows
|
|
143
|
-
packagesWithLocations.forEach(pkg => {
|
|
144
|
-
const row = [
|
|
145
|
-
pkg.id.padEnd(idWidth),
|
|
146
|
-
pkg.version.padEnd(versionWidth),
|
|
147
|
-
formatType(pkg.format, pkg.subtype).padEnd(typeWidth),
|
|
148
|
-
(pkg.installedPath || 'N/A').padEnd(locationWidth)
|
|
149
|
-
].join(' | ');
|
|
150
|
-
console.log(row);
|
|
151
|
-
});
|
|
152
|
-
console.log('');
|
|
153
|
-
console.log(`Total: ${packages.length} package${packages.length === 1 ? '' : 's'}`);
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Handle the list command
|
|
157
|
-
*/
|
|
158
|
-
async function handleList() {
|
|
159
|
-
const startTime = Date.now();
|
|
160
|
-
let success = false;
|
|
161
|
-
let error;
|
|
162
|
-
let packageCount = 0;
|
|
163
|
-
try {
|
|
164
|
-
const packages = await (0, lockfile_1.listPackages)();
|
|
165
|
-
packageCount = packages.length;
|
|
166
|
-
await displayPackages(packages);
|
|
167
|
-
success = true;
|
|
168
|
-
}
|
|
169
|
-
catch (err) {
|
|
170
|
-
error = err instanceof Error ? err.message : String(err);
|
|
171
|
-
throw new errors_1.CLIError(`ā Failed to list packages: ${error}`, 1);
|
|
172
|
-
}
|
|
173
|
-
finally {
|
|
174
|
-
// Track telemetry
|
|
175
|
-
await telemetry_1.telemetry.track({
|
|
176
|
-
command: 'list',
|
|
177
|
-
success,
|
|
178
|
-
error,
|
|
179
|
-
duration: Date.now() - startTime,
|
|
180
|
-
data: {
|
|
181
|
-
packageCount,
|
|
182
|
-
},
|
|
183
|
-
});
|
|
184
|
-
await telemetry_1.telemetry.shutdown();
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* Create the list command
|
|
189
|
-
*/
|
|
190
|
-
function createListCommand() {
|
|
191
|
-
const command = new commander_1.Command('list');
|
|
192
|
-
command
|
|
193
|
-
.description('List all installed prompt packages')
|
|
194
|
-
.action(async () => {
|
|
195
|
-
await handleList();
|
|
196
|
-
});
|
|
197
|
-
return command;
|
|
198
|
-
}
|
package/dist/commands/login.js
DELETED
|
@@ -1,316 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Login command implementation
|
|
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.handleLogin = handleLogin;
|
|
40
|
-
exports.createLoginCommand = createLoginCommand;
|
|
41
|
-
const commander_1 = require("commander");
|
|
42
|
-
const http_1 = require("http");
|
|
43
|
-
const jwt = __importStar(require("jsonwebtoken"));
|
|
44
|
-
const telemetry_1 = require("../core/telemetry");
|
|
45
|
-
const user_config_1 = require("../core/user-config");
|
|
46
|
-
const errors_1 = require("../core/errors");
|
|
47
|
-
/**
|
|
48
|
-
* Start OAuth callback server
|
|
49
|
-
*/
|
|
50
|
-
function startCallbackServer() {
|
|
51
|
-
return new Promise((resolve, reject) => {
|
|
52
|
-
const server = (0, http_1.createServer)((req, res) => {
|
|
53
|
-
const url = new URL(req.url || '', 'http://localhost:8765');
|
|
54
|
-
if (url.pathname === '/callback') {
|
|
55
|
-
const token = url.searchParams.get('token') || undefined;
|
|
56
|
-
const username = url.searchParams.get('username') || undefined;
|
|
57
|
-
const error = url.searchParams.get('error') || undefined;
|
|
58
|
-
if (error) {
|
|
59
|
-
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
60
|
-
res.end(`
|
|
61
|
-
<html>
|
|
62
|
-
<body>
|
|
63
|
-
<h1>ā Authentication Failed</h1>
|
|
64
|
-
<p>Error: ${error}</p>
|
|
65
|
-
<p>You can close this window.</p>
|
|
66
|
-
</body>
|
|
67
|
-
</html>
|
|
68
|
-
`);
|
|
69
|
-
server.close();
|
|
70
|
-
reject(new Error(`OAuth error: ${error}`));
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
if (token) {
|
|
74
|
-
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
75
|
-
res.end(`
|
|
76
|
-
<html>
|
|
77
|
-
<body>
|
|
78
|
-
<h1>ā
Authentication Successful!</h1>
|
|
79
|
-
<p>You can close this window and return to your terminal.</p>
|
|
80
|
-
</body>
|
|
81
|
-
</html>
|
|
82
|
-
`);
|
|
83
|
-
server.close();
|
|
84
|
-
resolve({ token, username });
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
88
|
-
res.end(`
|
|
89
|
-
<html>
|
|
90
|
-
<body>
|
|
91
|
-
<h1>ā Invalid Request</h1>
|
|
92
|
-
<p>No token received from authentication.</p>
|
|
93
|
-
</body>
|
|
94
|
-
</html>
|
|
95
|
-
`);
|
|
96
|
-
server.close();
|
|
97
|
-
reject(new Error('No token received'));
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
server.listen(8765, () => {
|
|
102
|
-
console.log(' Waiting for authentication...');
|
|
103
|
-
});
|
|
104
|
-
// Timeout after 5 minutes
|
|
105
|
-
setTimeout(() => {
|
|
106
|
-
server.close();
|
|
107
|
-
reject(new Error('Authentication timeout'));
|
|
108
|
-
}, 5 * 60 * 1000);
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Login with GitHub OAuth via Nango connect link
|
|
113
|
-
*/
|
|
114
|
-
async function loginWithOAuth(registryUrl) {
|
|
115
|
-
console.log('\nš Opening browser for GitHub authentication...\n');
|
|
116
|
-
// Generate a unique user ID for this CLI session
|
|
117
|
-
const userId = `cli_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
118
|
-
try {
|
|
119
|
-
// Get the Nango connect session from the registry
|
|
120
|
-
console.log(` Connecting to: ${registryUrl}`);
|
|
121
|
-
const response = await fetch(`${registryUrl}/api/v1/auth/nango/cli/connect-session`, {
|
|
122
|
-
method: 'POST',
|
|
123
|
-
headers: {
|
|
124
|
-
'Content-Type': 'application/json',
|
|
125
|
-
},
|
|
126
|
-
body: JSON.stringify({
|
|
127
|
-
userId,
|
|
128
|
-
email: 'cli@example.com',
|
|
129
|
-
displayName: 'CLI User',
|
|
130
|
-
}),
|
|
131
|
-
});
|
|
132
|
-
if (!response.ok) {
|
|
133
|
-
const errorText = await response.text().catch(() => 'Unable to read error response');
|
|
134
|
-
throw new Error(`Failed to get authentication session (${response.status}): ${errorText}`);
|
|
135
|
-
}
|
|
136
|
-
const responseData = await response.json();
|
|
137
|
-
const { connectSessionToken } = responseData;
|
|
138
|
-
if (!connectSessionToken) {
|
|
139
|
-
console.error('ā No session token received from server');
|
|
140
|
-
console.error(' Response data:', JSON.stringify(responseData, null, 2));
|
|
141
|
-
throw new Error('No session token received from server. Please check your Nango configuration.');
|
|
142
|
-
}
|
|
143
|
-
// Create the CLI auth URL with session token, callback, and userId
|
|
144
|
-
const callbackUrl = 'http://localhost:8765/callback';
|
|
145
|
-
// Determine webapp URL based on registry URL
|
|
146
|
-
let webappUrl;
|
|
147
|
-
if (registryUrl.includes('localhost') || registryUrl.includes('127.0.0.1')) {
|
|
148
|
-
// Local development: registry on port 3111, webapp on port 5173
|
|
149
|
-
webappUrl = registryUrl.replace(':3111', ':5173');
|
|
150
|
-
}
|
|
151
|
-
else if (registryUrl.includes('registry.prpm.dev')) {
|
|
152
|
-
// Production: always use prpm.dev webapp
|
|
153
|
-
webappUrl = 'https://prpm.dev';
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
// Custom registry: assume webapp is on same host without port
|
|
157
|
-
const url = new URL(registryUrl);
|
|
158
|
-
webappUrl = `${url.protocol}//${url.hostname}`;
|
|
159
|
-
}
|
|
160
|
-
const authUrl = `${webappUrl}/cli-auth?sessionToken=${encodeURIComponent(connectSessionToken)}&cliCallback=${encodeURIComponent(callbackUrl)}&userId=${encodeURIComponent(userId)}`;
|
|
161
|
-
console.log(` Please open this link in your browser to authenticate:`);
|
|
162
|
-
console.log(` ${authUrl}\n`);
|
|
163
|
-
// Try to open browser
|
|
164
|
-
const { exec } = await Promise.resolve().then(() => __importStar(require('child_process')));
|
|
165
|
-
const platform = process.platform;
|
|
166
|
-
const cmd = platform === 'darwin' ? 'open' : platform === 'win32' ? 'start' : 'xdg-open';
|
|
167
|
-
exec(`${cmd} "${authUrl}"`);
|
|
168
|
-
// Poll for authentication completion
|
|
169
|
-
console.log(' Waiting for authentication...\n');
|
|
170
|
-
const result = await pollForAuthentication(registryUrl, userId);
|
|
171
|
-
if (!result.token) {
|
|
172
|
-
throw new Error('No token received from authentication');
|
|
173
|
-
}
|
|
174
|
-
return { token: result.token, username: result.username || 'unknown' };
|
|
175
|
-
}
|
|
176
|
-
catch (error) {
|
|
177
|
-
if (error instanceof Error) {
|
|
178
|
-
// Check for common network errors
|
|
179
|
-
if (error.message.includes('ECONNREFUSED')) {
|
|
180
|
-
throw new Error(`Cannot connect to registry at ${registryUrl}. Is the registry running?`);
|
|
181
|
-
}
|
|
182
|
-
else if (error.message.includes('ENOTFOUND') || error.message.includes('getaddrinfo')) {
|
|
183
|
-
throw new Error(`Cannot resolve registry hostname: ${registryUrl}. Check your internet connection.`);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
throw new Error(`Authentication failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* Poll for authentication completion
|
|
191
|
-
*/
|
|
192
|
-
async function pollForAuthentication(registryUrl, userId) {
|
|
193
|
-
const maxAttempts = 60; // 5 minutes with 5-second intervals
|
|
194
|
-
let attempts = 0;
|
|
195
|
-
while (attempts < maxAttempts) {
|
|
196
|
-
try {
|
|
197
|
-
const response = await fetch(`${registryUrl}/api/v1/auth/nango/cli/status/${userId}`);
|
|
198
|
-
if (response.ok) {
|
|
199
|
-
const { authenticated, connectionId } = await response.json();
|
|
200
|
-
if (authenticated && connectionId) {
|
|
201
|
-
// Authentication completed, get the JWT token
|
|
202
|
-
const statusResponse = await fetch(`${registryUrl}/api/v1/auth/nango/status/${connectionId}`);
|
|
203
|
-
if (statusResponse.ok) {
|
|
204
|
-
const result = await statusResponse.json();
|
|
205
|
-
if (result.ready && result.token) {
|
|
206
|
-
return {
|
|
207
|
-
token: result.token,
|
|
208
|
-
username: result.username,
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
catch (error) {
|
|
216
|
-
// Ignore polling errors and continue
|
|
217
|
-
}
|
|
218
|
-
// Wait 5 seconds before next attempt
|
|
219
|
-
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
220
|
-
attempts++;
|
|
221
|
-
}
|
|
222
|
-
throw new Error('Authentication timeout - please try again');
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Login with manual token
|
|
226
|
-
*/
|
|
227
|
-
async function loginWithToken(token, registryUrl) {
|
|
228
|
-
// Verify token by making a request to /api/v1/user
|
|
229
|
-
const response = await fetch(`${registryUrl}/api/v1/user`, {
|
|
230
|
-
headers: {
|
|
231
|
-
'Authorization': `Bearer ${token}`,
|
|
232
|
-
},
|
|
233
|
-
});
|
|
234
|
-
if (!response.ok) {
|
|
235
|
-
throw new Error('Invalid token');
|
|
236
|
-
}
|
|
237
|
-
const user = await response.json();
|
|
238
|
-
return { token, username: user.username };
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* Handle login command
|
|
242
|
-
*/
|
|
243
|
-
async function handleLogin(options) {
|
|
244
|
-
const startTime = Date.now();
|
|
245
|
-
let success = false;
|
|
246
|
-
let error;
|
|
247
|
-
try {
|
|
248
|
-
const config = await (0, user_config_1.getConfig)();
|
|
249
|
-
const registryUrl = config.registryUrl || 'https://registry.prpm.dev';
|
|
250
|
-
console.log('š PRMP Login\n');
|
|
251
|
-
let result;
|
|
252
|
-
if (options.token) {
|
|
253
|
-
// Manual token login
|
|
254
|
-
console.log('š Logging in with provided token...\n');
|
|
255
|
-
result = await loginWithToken(options.token, registryUrl);
|
|
256
|
-
}
|
|
257
|
-
else {
|
|
258
|
-
// OAuth login
|
|
259
|
-
result = await loginWithOAuth(registryUrl);
|
|
260
|
-
}
|
|
261
|
-
// Extract user_id and email from JWT token
|
|
262
|
-
const decoded = jwt.decode(result.token);
|
|
263
|
-
if (!decoded) {
|
|
264
|
-
throw new Error('Failed to decode authentication token');
|
|
265
|
-
}
|
|
266
|
-
// Save token and user info to config
|
|
267
|
-
await (0, user_config_1.saveConfig)({
|
|
268
|
-
...config,
|
|
269
|
-
token: result.token,
|
|
270
|
-
username: result.username,
|
|
271
|
-
userId: decoded.user_id,
|
|
272
|
-
email: decoded.email,
|
|
273
|
-
});
|
|
274
|
-
// Identify user in PostHog with user properties
|
|
275
|
-
await telemetry_1.telemetry.identifyUser(decoded.user_id, {
|
|
276
|
-
username: result.username,
|
|
277
|
-
email: decoded.email,
|
|
278
|
-
cli_version: process.env.npm_package_version,
|
|
279
|
-
platform: process.platform,
|
|
280
|
-
first_login: new Date().toISOString(),
|
|
281
|
-
});
|
|
282
|
-
console.log('ā
Successfully logged in!\n');
|
|
283
|
-
console.log(` Username: ${result.username}`);
|
|
284
|
-
console.log(` Registry: ${registryUrl}\n`);
|
|
285
|
-
console.log('š” You can now publish packages with "prpm publish"\n');
|
|
286
|
-
success = true;
|
|
287
|
-
}
|
|
288
|
-
catch (err) {
|
|
289
|
-
error = err instanceof Error ? err.message : String(err);
|
|
290
|
-
throw new errors_1.CLIError(`\nā Login failed: ${error}\n\nš” Try again or use "prpm login --token YOUR_TOKEN"\n`, 1);
|
|
291
|
-
}
|
|
292
|
-
finally {
|
|
293
|
-
// Track telemetry
|
|
294
|
-
await telemetry_1.telemetry.track({
|
|
295
|
-
command: 'login',
|
|
296
|
-
success,
|
|
297
|
-
error,
|
|
298
|
-
duration: Date.now() - startTime,
|
|
299
|
-
data: {
|
|
300
|
-
method: options.token ? 'token' : 'oauth',
|
|
301
|
-
},
|
|
302
|
-
});
|
|
303
|
-
await telemetry_1.telemetry.shutdown();
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
/**
|
|
307
|
-
* Create the login command
|
|
308
|
-
*/
|
|
309
|
-
function createLoginCommand() {
|
|
310
|
-
return new commander_1.Command('login')
|
|
311
|
-
.description('Login to the PRMP registry')
|
|
312
|
-
.option('--token <token>', 'Login with a personal access token')
|
|
313
|
-
.action(async (options) => {
|
|
314
|
-
await handleLogin(options);
|
|
315
|
-
});
|
|
316
|
-
}
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Outdated command - Check for package updates
|
|
4
|
-
*/
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.handleOutdated = handleOutdated;
|
|
7
|
-
exports.createOutdatedCommand = createOutdatedCommand;
|
|
8
|
-
const commander_1 = require("commander");
|
|
9
|
-
const registry_client_1 = require("@pr-pm/registry-client");
|
|
10
|
-
const user_config_1 = require("../core/user-config");
|
|
11
|
-
const lockfile_1 = require("../core/lockfile");
|
|
12
|
-
const telemetry_1 = require("../core/telemetry");
|
|
13
|
-
const errors_1 = require("../core/errors");
|
|
14
|
-
/**
|
|
15
|
-
* Check for outdated packages
|
|
16
|
-
*/
|
|
17
|
-
async function handleOutdated() {
|
|
18
|
-
const startTime = Date.now();
|
|
19
|
-
let success = false;
|
|
20
|
-
let error;
|
|
21
|
-
try {
|
|
22
|
-
console.log('š Checking for package updates...\n');
|
|
23
|
-
const config = await (0, user_config_1.getConfig)();
|
|
24
|
-
const client = (0, registry_client_1.getRegistryClient)(config);
|
|
25
|
-
const installedPackages = await (0, lockfile_1.listPackages)();
|
|
26
|
-
if (installedPackages.length === 0) {
|
|
27
|
-
console.log('No packages installed.');
|
|
28
|
-
success = true;
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
const outdated = [];
|
|
32
|
-
for (const pkg of installedPackages) {
|
|
33
|
-
try {
|
|
34
|
-
// Get package info from registry
|
|
35
|
-
const registryPkg = await client.getPackage(pkg.id);
|
|
36
|
-
if (!registryPkg.latest_version || !pkg.version) {
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
const currentVersion = pkg.version;
|
|
40
|
-
const latestVersion = registryPkg.latest_version.version;
|
|
41
|
-
// Check if update available
|
|
42
|
-
if (currentVersion !== latestVersion) {
|
|
43
|
-
const updateType = getUpdateType(currentVersion, latestVersion);
|
|
44
|
-
outdated.push({
|
|
45
|
-
id: pkg.id,
|
|
46
|
-
current: currentVersion,
|
|
47
|
-
latest: latestVersion,
|
|
48
|
-
type: updateType,
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
catch (err) {
|
|
53
|
-
// Skip packages that can't be found in registry
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
if (outdated.length === 0) {
|
|
58
|
-
console.log('ā
All packages are up to date!\n');
|
|
59
|
-
success = true;
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
// Display outdated packages
|
|
63
|
-
console.log(`š¦ ${outdated.length} package(s) have updates available:\n`);
|
|
64
|
-
// Group by update type
|
|
65
|
-
const major = outdated.filter(p => p.type === 'major');
|
|
66
|
-
const minor = outdated.filter(p => p.type === 'minor');
|
|
67
|
-
const patch = outdated.filter(p => p.type === 'patch');
|
|
68
|
-
if (major.length > 0) {
|
|
69
|
-
console.log('š“ Major Updates (breaking changes possible):');
|
|
70
|
-
major.forEach(pkg => {
|
|
71
|
-
console.log(` ${pkg.id.padEnd(30)} ${pkg.current} ā ${pkg.latest}`);
|
|
72
|
-
});
|
|
73
|
-
console.log('');
|
|
74
|
-
}
|
|
75
|
-
if (minor.length > 0) {
|
|
76
|
-
console.log('š” Minor Updates (new features):');
|
|
77
|
-
minor.forEach(pkg => {
|
|
78
|
-
console.log(` ${pkg.id.padEnd(30)} ${pkg.current} ā ${pkg.latest}`);
|
|
79
|
-
});
|
|
80
|
-
console.log('');
|
|
81
|
-
}
|
|
82
|
-
if (patch.length > 0) {
|
|
83
|
-
console.log('š¢ Patch Updates (bug fixes):');
|
|
84
|
-
patch.forEach(pkg => {
|
|
85
|
-
console.log(` ${pkg.id.padEnd(30)} ${pkg.current} ā ${pkg.latest}`);
|
|
86
|
-
});
|
|
87
|
-
console.log('');
|
|
88
|
-
}
|
|
89
|
-
console.log('š” Run "prpm update" to update to latest minor/patch versions');
|
|
90
|
-
console.log('š” Run "prpm upgrade" to upgrade to latest major versions\n');
|
|
91
|
-
success = true;
|
|
92
|
-
}
|
|
93
|
-
catch (err) {
|
|
94
|
-
error = err instanceof Error ? err.message : String(err);
|
|
95
|
-
throw new errors_1.CLIError(`\nā Failed to check for updates: ${error}`, 1);
|
|
96
|
-
}
|
|
97
|
-
finally {
|
|
98
|
-
await telemetry_1.telemetry.track({
|
|
99
|
-
command: 'outdated',
|
|
100
|
-
success,
|
|
101
|
-
error,
|
|
102
|
-
duration: Date.now() - startTime,
|
|
103
|
-
});
|
|
104
|
-
await telemetry_1.telemetry.shutdown();
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Determine update type based on semver
|
|
109
|
-
*/
|
|
110
|
-
function getUpdateType(current, latest) {
|
|
111
|
-
const currentParts = current.split('.').map(Number);
|
|
112
|
-
const latestParts = latest.split('.').map(Number);
|
|
113
|
-
const [currMajor = 0, currMinor = 0, currPatch = 0] = currentParts;
|
|
114
|
-
const [latestMajor = 0, latestMinor = 0, latestPatch = 0] = latestParts;
|
|
115
|
-
if (latestMajor > currMajor)
|
|
116
|
-
return 'major';
|
|
117
|
-
if (latestMinor > currMinor)
|
|
118
|
-
return 'minor';
|
|
119
|
-
return 'patch';
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Create the outdated command
|
|
123
|
-
*/
|
|
124
|
-
function createOutdatedCommand() {
|
|
125
|
-
return new commander_1.Command('outdated')
|
|
126
|
-
.description('Check for package updates')
|
|
127
|
-
.action(async () => {
|
|
128
|
-
await handleOutdated();
|
|
129
|
-
});
|
|
130
|
-
}
|