prpm 0.0.1
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/README.md +928 -0
- package/dist/commands/add.js +107 -0
- package/dist/commands/collections.js +409 -0
- package/dist/commands/deps.js +92 -0
- package/dist/commands/index.js +124 -0
- package/dist/commands/info.js +81 -0
- package/dist/commands/install.js +252 -0
- package/dist/commands/list.js +89 -0
- package/dist/commands/login.js +219 -0
- package/dist/commands/outdated.js +127 -0
- package/dist/commands/popular.js +27 -0
- package/dist/commands/publish.js +217 -0
- package/dist/commands/remove.js +43 -0
- package/dist/commands/search.js +179 -0
- package/dist/commands/telemetry.js +103 -0
- package/dist/commands/trending.js +75 -0
- package/dist/commands/update.js +120 -0
- package/dist/commands/upgrade.js +120 -0
- package/dist/commands/whoami.js +51 -0
- package/dist/core/config.js +91 -0
- package/dist/core/downloader.js +64 -0
- package/dist/core/filesystem.js +94 -0
- package/dist/core/lockfile.js +182 -0
- package/dist/core/registry-client.js +265 -0
- package/dist/core/telemetry.js +170 -0
- package/dist/core/user-config.js +79 -0
- package/dist/index.js +69 -0
- package/dist/types.js +5 -0
- package/package.json +67 -0
|
@@ -0,0 +1,219 @@
|
|
|
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 telemetry_1 = require("../core/telemetry");
|
|
44
|
+
const user_config_1 = require("../core/user-config");
|
|
45
|
+
/**
|
|
46
|
+
* Start OAuth callback server
|
|
47
|
+
*/
|
|
48
|
+
function startCallbackServer() {
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
const server = (0, http_1.createServer)((req, res) => {
|
|
51
|
+
const url = new URL(req.url || '', 'http://localhost:8765');
|
|
52
|
+
if (url.pathname === '/callback') {
|
|
53
|
+
const token = url.searchParams.get('token') || undefined;
|
|
54
|
+
const username = url.searchParams.get('username') || undefined;
|
|
55
|
+
const error = url.searchParams.get('error') || undefined;
|
|
56
|
+
if (error) {
|
|
57
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
58
|
+
res.end(`
|
|
59
|
+
<html>
|
|
60
|
+
<body>
|
|
61
|
+
<h1>ā Authentication Failed</h1>
|
|
62
|
+
<p>Error: ${error}</p>
|
|
63
|
+
<p>You can close this window.</p>
|
|
64
|
+
</body>
|
|
65
|
+
</html>
|
|
66
|
+
`);
|
|
67
|
+
server.close();
|
|
68
|
+
reject(new Error(`OAuth error: ${error}`));
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (token) {
|
|
72
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
73
|
+
res.end(`
|
|
74
|
+
<html>
|
|
75
|
+
<body>
|
|
76
|
+
<h1>ā
Authentication Successful!</h1>
|
|
77
|
+
<p>You can close this window and return to your terminal.</p>
|
|
78
|
+
</body>
|
|
79
|
+
</html>
|
|
80
|
+
`);
|
|
81
|
+
server.close();
|
|
82
|
+
resolve({ token, username });
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
86
|
+
res.end(`
|
|
87
|
+
<html>
|
|
88
|
+
<body>
|
|
89
|
+
<h1>ā Invalid Request</h1>
|
|
90
|
+
<p>No token received from authentication.</p>
|
|
91
|
+
</body>
|
|
92
|
+
</html>
|
|
93
|
+
`);
|
|
94
|
+
server.close();
|
|
95
|
+
reject(new Error('No token received'));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
server.listen(8765, () => {
|
|
100
|
+
console.log(' Waiting for authentication...');
|
|
101
|
+
});
|
|
102
|
+
// Timeout after 5 minutes
|
|
103
|
+
setTimeout(() => {
|
|
104
|
+
server.close();
|
|
105
|
+
reject(new Error('Authentication timeout'));
|
|
106
|
+
}, 5 * 60 * 1000);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Login with GitHub OAuth
|
|
111
|
+
*/
|
|
112
|
+
async function loginWithOAuth(registryUrl) {
|
|
113
|
+
console.log('\nš Opening browser for GitHub authentication...\n');
|
|
114
|
+
// Open browser to registry OAuth page with CLI redirect
|
|
115
|
+
const callbackUrl = 'http://localhost:8765/callback';
|
|
116
|
+
const authUrl = `${registryUrl}/api/v1/auth/github?redirect=${encodeURIComponent(callbackUrl)}`;
|
|
117
|
+
console.log(` If browser doesn't open, visit: ${authUrl}\n`);
|
|
118
|
+
// Try to open browser
|
|
119
|
+
const { exec } = await Promise.resolve().then(() => __importStar(require('child_process')));
|
|
120
|
+
const platform = process.platform;
|
|
121
|
+
const cmd = platform === 'darwin' ? 'open' : platform === 'win32' ? 'start' : 'xdg-open';
|
|
122
|
+
exec(`${cmd} "${authUrl}"`);
|
|
123
|
+
// Start callback server and receive token directly
|
|
124
|
+
console.log(' Waiting for authentication...\n');
|
|
125
|
+
const result = await startCallbackServer();
|
|
126
|
+
if (!result.token) {
|
|
127
|
+
throw new Error('No token received from authentication');
|
|
128
|
+
}
|
|
129
|
+
// Extract username from token if not provided
|
|
130
|
+
let username = result.username || '';
|
|
131
|
+
if (!username) {
|
|
132
|
+
// Decode JWT to get username (basic JWT decode without verification)
|
|
133
|
+
try {
|
|
134
|
+
const payload = JSON.parse(Buffer.from(result.token.split('.')[1], 'base64').toString());
|
|
135
|
+
username = payload.username || 'unknown';
|
|
136
|
+
}
|
|
137
|
+
catch (e) {
|
|
138
|
+
username = 'unknown';
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return { token: result.token, username: username || 'unknown' };
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Login with manual token
|
|
145
|
+
*/
|
|
146
|
+
async function loginWithToken(token, registryUrl) {
|
|
147
|
+
// Verify token by making a request to /api/v1/user
|
|
148
|
+
const response = await fetch(`${registryUrl}/api/v1/user`, {
|
|
149
|
+
headers: {
|
|
150
|
+
'Authorization': `Bearer ${token}`,
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
if (!response.ok) {
|
|
154
|
+
throw new Error('Invalid token');
|
|
155
|
+
}
|
|
156
|
+
const user = await response.json();
|
|
157
|
+
return { token, username: user.username };
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Handle login command
|
|
161
|
+
*/
|
|
162
|
+
async function handleLogin(options) {
|
|
163
|
+
const startTime = Date.now();
|
|
164
|
+
let success = false;
|
|
165
|
+
let error;
|
|
166
|
+
try {
|
|
167
|
+
const config = await (0, user_config_1.getConfig)();
|
|
168
|
+
const registryUrl = config.registryUrl || 'https://registry.prpm.dev';
|
|
169
|
+
console.log('š PRMP Login\n');
|
|
170
|
+
let result;
|
|
171
|
+
if (options.token) {
|
|
172
|
+
// Manual token login
|
|
173
|
+
console.log('š Logging in with provided token...\n');
|
|
174
|
+
result = await loginWithToken(options.token, registryUrl);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
// OAuth login
|
|
178
|
+
result = await loginWithOAuth(registryUrl);
|
|
179
|
+
}
|
|
180
|
+
// Save token to config
|
|
181
|
+
await (0, user_config_1.saveConfig)({
|
|
182
|
+
...config,
|
|
183
|
+
token: result.token,
|
|
184
|
+
username: result.username,
|
|
185
|
+
});
|
|
186
|
+
console.log('ā
Successfully logged in!\n');
|
|
187
|
+
console.log(` Username: ${result.username}`);
|
|
188
|
+
console.log(` Registry: ${registryUrl}\n`);
|
|
189
|
+
console.log('š” You can now publish packages with "prpm publish"\n');
|
|
190
|
+
success = true;
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
error = err instanceof Error ? err.message : String(err);
|
|
194
|
+
console.error(`\nā Login failed: ${error}\n`);
|
|
195
|
+
console.error('š” Try again or use "prpm login --token YOUR_TOKEN"\n');
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
198
|
+
finally {
|
|
199
|
+
// Track telemetry
|
|
200
|
+
await telemetry_1.telemetry.track({
|
|
201
|
+
command: 'login',
|
|
202
|
+
success,
|
|
203
|
+
error,
|
|
204
|
+
duration: Date.now() - startTime,
|
|
205
|
+
data: {
|
|
206
|
+
method: options.token ? 'token' : 'oauth',
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Create the login command
|
|
213
|
+
*/
|
|
214
|
+
function createLoginCommand() {
|
|
215
|
+
return new commander_1.Command('login')
|
|
216
|
+
.description('Login to the PRMP registry')
|
|
217
|
+
.option('--token <token>', 'Login with a personal access token')
|
|
218
|
+
.action(handleLogin);
|
|
219
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
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("@prpm/registry-client");
|
|
10
|
+
const user_config_1 = require("../core/user-config");
|
|
11
|
+
const config_1 = require("../core/config");
|
|
12
|
+
const telemetry_1 = require("../core/telemetry");
|
|
13
|
+
/**
|
|
14
|
+
* Check for outdated packages
|
|
15
|
+
*/
|
|
16
|
+
async function handleOutdated() {
|
|
17
|
+
const startTime = Date.now();
|
|
18
|
+
let success = false;
|
|
19
|
+
let error;
|
|
20
|
+
try {
|
|
21
|
+
console.log('š Checking for package updates...\n');
|
|
22
|
+
const config = await (0, user_config_1.getConfig)();
|
|
23
|
+
const client = (0, registry_client_1.getRegistryClient)(config);
|
|
24
|
+
const installedPackages = await (0, config_1.listPackages)();
|
|
25
|
+
if (installedPackages.length === 0) {
|
|
26
|
+
console.log('No packages installed.');
|
|
27
|
+
success = true;
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const outdated = [];
|
|
31
|
+
for (const pkg of installedPackages) {
|
|
32
|
+
try {
|
|
33
|
+
// Get package info from registry
|
|
34
|
+
const registryPkg = await client.getPackage(pkg.id);
|
|
35
|
+
if (!registryPkg.latest_version || !pkg.version) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const currentVersion = pkg.version;
|
|
39
|
+
const latestVersion = registryPkg.latest_version.version;
|
|
40
|
+
// Check if update available
|
|
41
|
+
if (currentVersion !== latestVersion) {
|
|
42
|
+
const updateType = getUpdateType(currentVersion, latestVersion);
|
|
43
|
+
outdated.push({
|
|
44
|
+
id: pkg.id,
|
|
45
|
+
current: currentVersion,
|
|
46
|
+
latest: latestVersion,
|
|
47
|
+
type: updateType,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
// Skip packages that can't be found in registry
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (outdated.length === 0) {
|
|
57
|
+
console.log('ā
All packages are up to date!\n');
|
|
58
|
+
success = true;
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
// Display outdated packages
|
|
62
|
+
console.log(`š¦ ${outdated.length} package(s) have updates available:\n`);
|
|
63
|
+
// Group by update type
|
|
64
|
+
const major = outdated.filter(p => p.type === 'major');
|
|
65
|
+
const minor = outdated.filter(p => p.type === 'minor');
|
|
66
|
+
const patch = outdated.filter(p => p.type === 'patch');
|
|
67
|
+
if (major.length > 0) {
|
|
68
|
+
console.log('š“ Major Updates (breaking changes possible):');
|
|
69
|
+
major.forEach(pkg => {
|
|
70
|
+
console.log(` ${pkg.id.padEnd(30)} ${pkg.current} ā ${pkg.latest}`);
|
|
71
|
+
});
|
|
72
|
+
console.log('');
|
|
73
|
+
}
|
|
74
|
+
if (minor.length > 0) {
|
|
75
|
+
console.log('š” Minor Updates (new features):');
|
|
76
|
+
minor.forEach(pkg => {
|
|
77
|
+
console.log(` ${pkg.id.padEnd(30)} ${pkg.current} ā ${pkg.latest}`);
|
|
78
|
+
});
|
|
79
|
+
console.log('');
|
|
80
|
+
}
|
|
81
|
+
if (patch.length > 0) {
|
|
82
|
+
console.log('š¢ Patch Updates (bug fixes):');
|
|
83
|
+
patch.forEach(pkg => {
|
|
84
|
+
console.log(` ${pkg.id.padEnd(30)} ${pkg.current} ā ${pkg.latest}`);
|
|
85
|
+
});
|
|
86
|
+
console.log('');
|
|
87
|
+
}
|
|
88
|
+
console.log('š” Run "prpm update" to update to latest minor/patch versions');
|
|
89
|
+
console.log('š” Run "prpm upgrade" to upgrade to latest major versions\n');
|
|
90
|
+
success = true;
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
error = err instanceof Error ? err.message : String(err);
|
|
94
|
+
console.error(`\nā Failed to check for updates: ${error}`);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
await telemetry_1.telemetry.track({
|
|
99
|
+
command: 'outdated',
|
|
100
|
+
success,
|
|
101
|
+
error,
|
|
102
|
+
duration: Date.now() - startTime,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Determine update type based on semver
|
|
108
|
+
*/
|
|
109
|
+
function getUpdateType(current, latest) {
|
|
110
|
+
const currentParts = current.split('.').map(Number);
|
|
111
|
+
const latestParts = latest.split('.').map(Number);
|
|
112
|
+
const [currMajor = 0, currMinor = 0, currPatch = 0] = currentParts;
|
|
113
|
+
const [latestMajor = 0, latestMinor = 0, latestPatch = 0] = latestParts;
|
|
114
|
+
if (latestMajor > currMajor)
|
|
115
|
+
return 'major';
|
|
116
|
+
if (latestMinor > currMinor)
|
|
117
|
+
return 'minor';
|
|
118
|
+
return 'patch';
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Create the outdated command
|
|
122
|
+
*/
|
|
123
|
+
function createOutdatedCommand() {
|
|
124
|
+
return new commander_1.Command('outdated')
|
|
125
|
+
.description('Check for package updates')
|
|
126
|
+
.action(handleOutdated);
|
|
127
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Popular packages command implementation
|
|
4
|
+
* Shows all-time popular packages (delegates to trending)
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.handlePopular = handlePopular;
|
|
8
|
+
exports.createPopularCommand = createPopularCommand;
|
|
9
|
+
const commander_1 = require("commander");
|
|
10
|
+
const trending_1 = require("./trending");
|
|
11
|
+
/**
|
|
12
|
+
* Show popular packages (wrapper around trending)
|
|
13
|
+
*/
|
|
14
|
+
async function handlePopular(options) {
|
|
15
|
+
// Delegate to trending command
|
|
16
|
+
console.log('š Popular Packages (All Time)\n');
|
|
17
|
+
await (0, trending_1.handleTrending)({ type: options.type });
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Create the popular command
|
|
21
|
+
*/
|
|
22
|
+
function createPopularCommand() {
|
|
23
|
+
return new commander_1.Command('popular')
|
|
24
|
+
.description('Show popular packages (all time)')
|
|
25
|
+
.option('-t, --type <type>', 'Filter by package type (cursor, claude, continue, windsurf)')
|
|
26
|
+
.action(handlePopular);
|
|
27
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Publish 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.handlePublish = handlePublish;
|
|
40
|
+
exports.createPublishCommand = createPublishCommand;
|
|
41
|
+
const commander_1 = require("commander");
|
|
42
|
+
const promises_1 = require("fs/promises");
|
|
43
|
+
const path_1 = require("path");
|
|
44
|
+
const tar = __importStar(require("tar"));
|
|
45
|
+
const os_1 = require("os");
|
|
46
|
+
const crypto_1 = require("crypto");
|
|
47
|
+
const registry_client_1 = require("@prpm/registry-client");
|
|
48
|
+
const user_config_1 = require("../core/user-config");
|
|
49
|
+
const telemetry_1 = require("../core/telemetry");
|
|
50
|
+
/**
|
|
51
|
+
* Validate package manifest
|
|
52
|
+
*/
|
|
53
|
+
async function validateManifest(manifestPath) {
|
|
54
|
+
try {
|
|
55
|
+
const content = await (0, promises_1.readFile)(manifestPath, 'utf-8');
|
|
56
|
+
const manifest = JSON.parse(content);
|
|
57
|
+
// Required fields
|
|
58
|
+
const required = ['name', 'version', 'description', 'type'];
|
|
59
|
+
const missing = required.filter(field => !manifest[field]);
|
|
60
|
+
if (missing.length > 0) {
|
|
61
|
+
throw new Error(`Missing required fields: ${missing.join(', ')}`);
|
|
62
|
+
}
|
|
63
|
+
// Validate name format
|
|
64
|
+
if (!/^(@[a-z0-9-]+\/)?[a-z0-9-]+$/.test(manifest.name)) {
|
|
65
|
+
throw new Error('Package name must be lowercase alphanumeric with hyphens only');
|
|
66
|
+
}
|
|
67
|
+
// Validate version format
|
|
68
|
+
if (!/^\d+\.\d+\.\d+/.test(manifest.version)) {
|
|
69
|
+
throw new Error('Version must be semver format (e.g., 1.0.0)');
|
|
70
|
+
}
|
|
71
|
+
// Validate type
|
|
72
|
+
const validTypes = ['cursor', 'claude', 'continue', 'windsurf', 'generic'];
|
|
73
|
+
if (!validTypes.includes(manifest.type)) {
|
|
74
|
+
throw new Error(`Type must be one of: ${validTypes.join(', ')}`);
|
|
75
|
+
}
|
|
76
|
+
return manifest;
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
if (error instanceof Error && error.message.includes('ENOENT')) {
|
|
80
|
+
throw new Error('prpm.json not found. Run this command in your package directory.');
|
|
81
|
+
}
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Create tarball from current directory
|
|
87
|
+
*/
|
|
88
|
+
async function createTarball(manifest) {
|
|
89
|
+
const tmpDir = (0, path_1.join)((0, os_1.tmpdir)(), `prpm-${(0, crypto_1.randomBytes)(8).toString('hex')}`);
|
|
90
|
+
const tarballPath = (0, path_1.join)(tmpDir, 'package.tar.gz');
|
|
91
|
+
try {
|
|
92
|
+
// Get files to include (from manifest.files or default)
|
|
93
|
+
const files = manifest.files || [
|
|
94
|
+
'prpm.json',
|
|
95
|
+
'.cursorrules',
|
|
96
|
+
'README.md',
|
|
97
|
+
'LICENSE',
|
|
98
|
+
'.clinerules',
|
|
99
|
+
'.continuerc.json',
|
|
100
|
+
'.windsurfrules'
|
|
101
|
+
];
|
|
102
|
+
// Check which files exist
|
|
103
|
+
const existingFiles = [];
|
|
104
|
+
for (const file of files) {
|
|
105
|
+
try {
|
|
106
|
+
await (0, promises_1.stat)(file);
|
|
107
|
+
existingFiles.push(file);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// File doesn't exist, skip
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (existingFiles.length === 0) {
|
|
114
|
+
throw new Error('No package files found to include in tarball');
|
|
115
|
+
}
|
|
116
|
+
// Create tarball
|
|
117
|
+
await tar.create({
|
|
118
|
+
gzip: true,
|
|
119
|
+
file: tarballPath,
|
|
120
|
+
cwd: process.cwd(),
|
|
121
|
+
}, existingFiles);
|
|
122
|
+
// Read tarball into buffer
|
|
123
|
+
const tarballBuffer = await (0, promises_1.readFile)(tarballPath);
|
|
124
|
+
// Check size (max 10MB)
|
|
125
|
+
const sizeMB = tarballBuffer.length / (1024 * 1024);
|
|
126
|
+
if (sizeMB > 10) {
|
|
127
|
+
throw new Error(`Package size (${sizeMB.toFixed(2)}MB) exceeds 10MB limit`);
|
|
128
|
+
}
|
|
129
|
+
return tarballBuffer;
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Publish a package to the registry
|
|
137
|
+
*/
|
|
138
|
+
async function handlePublish(options) {
|
|
139
|
+
const startTime = Date.now();
|
|
140
|
+
let success = false;
|
|
141
|
+
let error;
|
|
142
|
+
let packageName;
|
|
143
|
+
let version;
|
|
144
|
+
try {
|
|
145
|
+
const config = await (0, user_config_1.getConfig)();
|
|
146
|
+
// Check if logged in
|
|
147
|
+
if (!config.token) {
|
|
148
|
+
console.error('ā Not logged in. Run "prpm login" first.');
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
console.log('š¦ Publishing package...\n');
|
|
152
|
+
// Read and validate manifest
|
|
153
|
+
console.log('š Validating package manifest...');
|
|
154
|
+
const manifestPath = (0, path_1.join)(process.cwd(), 'prpm.json');
|
|
155
|
+
const manifest = await validateManifest(manifestPath);
|
|
156
|
+
packageName = manifest.name;
|
|
157
|
+
version = manifest.version;
|
|
158
|
+
console.log(` Package: ${manifest.name}@${manifest.version}`);
|
|
159
|
+
console.log(` Type: ${manifest.type}`);
|
|
160
|
+
console.log(` Description: ${manifest.description}`);
|
|
161
|
+
console.log('');
|
|
162
|
+
// Create tarball
|
|
163
|
+
console.log('š¦ Creating package tarball...');
|
|
164
|
+
const tarball = await createTarball(manifest);
|
|
165
|
+
const sizeMB = (tarball.length / (1024 * 1024)).toFixed(2);
|
|
166
|
+
console.log(` Size: ${sizeMB}MB`);
|
|
167
|
+
console.log('');
|
|
168
|
+
if (options.dryRun) {
|
|
169
|
+
console.log('ā
Dry run successful! Package is ready to publish.');
|
|
170
|
+
console.log(' Run without --dry-run to publish.');
|
|
171
|
+
success = true;
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
// Publish to registry
|
|
175
|
+
console.log('š Publishing to registry...');
|
|
176
|
+
const client = (0, registry_client_1.getRegistryClient)(config);
|
|
177
|
+
const result = await client.publish(manifest, tarball);
|
|
178
|
+
console.log('');
|
|
179
|
+
console.log('ā
Package published successfully!');
|
|
180
|
+
console.log('');
|
|
181
|
+
console.log(` Package: ${result.name}@${result.version}`);
|
|
182
|
+
console.log(` Install: prpm install ${result.name}`);
|
|
183
|
+
console.log(` View: ${config.registryUrl}/packages/${result.id}`);
|
|
184
|
+
console.log('');
|
|
185
|
+
success = true;
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
error = err instanceof Error ? err.message : String(err);
|
|
189
|
+
console.error(`\nā Failed to publish package: ${error}\n`);
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
192
|
+
finally {
|
|
193
|
+
// Track telemetry
|
|
194
|
+
await telemetry_1.telemetry.track({
|
|
195
|
+
command: 'publish',
|
|
196
|
+
success,
|
|
197
|
+
error,
|
|
198
|
+
duration: Date.now() - startTime,
|
|
199
|
+
data: {
|
|
200
|
+
packageName,
|
|
201
|
+
version,
|
|
202
|
+
dryRun: options.dryRun,
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Create the publish command
|
|
209
|
+
*/
|
|
210
|
+
function createPublishCommand() {
|
|
211
|
+
return new commander_1.Command('publish')
|
|
212
|
+
.description('Publish a package to the registry')
|
|
213
|
+
.option('--access <type>', 'Package access (public or private)', 'public')
|
|
214
|
+
.option('--tag <tag>', 'NPM-style tag (e.g., latest, beta)', 'latest')
|
|
215
|
+
.option('--dry-run', 'Validate package without publishing')
|
|
216
|
+
.action(handlePublish);
|
|
217
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Remove command implementation
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handleRemove = handleRemove;
|
|
7
|
+
exports.createRemoveCommand = createRemoveCommand;
|
|
8
|
+
const commander_1 = require("commander");
|
|
9
|
+
const config_1 = require("../core/config");
|
|
10
|
+
const filesystem_1 = require("../core/filesystem");
|
|
11
|
+
/**
|
|
12
|
+
* Handle the remove command
|
|
13
|
+
*/
|
|
14
|
+
async function handleRemove(id) {
|
|
15
|
+
try {
|
|
16
|
+
console.log(`šļø Removing package: ${id}`);
|
|
17
|
+
// Remove from config and get package info
|
|
18
|
+
const pkg = await (0, config_1.removePackage)(id);
|
|
19
|
+
if (!pkg) {
|
|
20
|
+
console.error(`ā Package "${id}" not found`);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
// Delete the file
|
|
24
|
+
console.log(`š Deleting file: ${pkg.dest}`);
|
|
25
|
+
await (0, filesystem_1.deleteFile)(pkg.dest);
|
|
26
|
+
console.log(`ā
Successfully removed ${id} (${pkg.type})`);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.error(`ā Failed to remove package: ${error}`);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Create the remove command
|
|
35
|
+
*/
|
|
36
|
+
function createRemoveCommand() {
|
|
37
|
+
const command = new commander_1.Command('remove');
|
|
38
|
+
command
|
|
39
|
+
.description('Remove a prompt package')
|
|
40
|
+
.argument('<id>', 'Package ID to remove')
|
|
41
|
+
.action(handleRemove);
|
|
42
|
+
return command;
|
|
43
|
+
}
|