prpm 1.2.1 → 2.1.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/README.md +90 -862
- package/dist/index.js +24163 -65
- package/dist/schemas/agents-md.schema.json +24 -0
- package/dist/schemas/aider.schema.json +24 -0
- package/dist/schemas/canonical.schema.json +435 -0
- package/dist/schemas/claude-agent.schema.json +62 -0
- package/dist/schemas/claude-hook.schema.json +70 -0
- package/dist/schemas/claude-plugin.schema.json +122 -0
- package/dist/schemas/claude-skill.schema.json +51 -0
- package/dist/schemas/claude-slash-command.schema.json +77 -0
- package/dist/schemas/claude.schema.json +52 -0
- package/dist/schemas/continue.schema.json +98 -0
- package/dist/schemas/copilot.schema.json +76 -0
- package/dist/schemas/cursor-command.schema.json +27 -0
- package/dist/schemas/cursor-hooks.schema.json +59 -0
- package/dist/schemas/cursor.schema.json +74 -0
- package/dist/schemas/droid-hook.schema.json +103 -0
- package/dist/schemas/droid-skill.schema.json +46 -0
- package/dist/schemas/droid-slash-command.schema.json +53 -0
- package/dist/schemas/droid.schema.json +46 -0
- package/dist/schemas/format-capabilities.schema.json +101 -0
- package/dist/schemas/format-registry.schema.json +99 -0
- package/dist/schemas/gemini-extension.schema.json +77 -0
- package/dist/schemas/gemini-md.schema.json +24 -0
- package/dist/schemas/gemini.schema.json +30 -0
- package/dist/schemas/kiro-agent.schema.json +146 -0
- package/dist/schemas/kiro-hook.schema.json +165 -0
- package/dist/schemas/kiro-steering.schema.json +74 -0
- package/dist/schemas/mcp-server.schema.json +130 -0
- package/dist/schemas/opencode-plugin.schema.json +391 -0
- package/dist/schemas/opencode-slash-command.schema.json +60 -0
- package/dist/schemas/opencode.schema.json +111 -0
- package/dist/schemas/prpm-manifest.schema.json +758 -0
- package/dist/schemas/replit.schema.json +21 -0
- package/dist/schemas/ruler.schema.json +22 -0
- package/dist/schemas/trae.schema.json +24 -0
- package/dist/schemas/windsurf.schema.json +22 -0
- package/dist/schemas/zed-extension.schema.json +238 -0
- package/dist/schemas/zed.schema.json +44 -0
- package/dist/schemas/zencoder.schema.json +51 -0
- package/package.json +20 -14
- package/schemas/prpm-manifest.schema.json +490 -39
- package/dist/__tests__/e2e/test-helpers.js +0 -150
- package/dist/commands/collections.js +0 -606
- package/dist/commands/index.js +0 -186
- package/dist/commands/info.js +0 -82
- package/dist/commands/install.js +0 -477
- package/dist/commands/list.js +0 -166
- package/dist/commands/login.js +0 -281
- package/dist/commands/outdated.js +0 -128
- package/dist/commands/popular.js +0 -27
- package/dist/commands/publish.js +0 -274
- package/dist/commands/schema.js +0 -37
- package/dist/commands/search.js +0 -404
- package/dist/commands/telemetry.js +0 -103
- package/dist/commands/trending.js +0 -76
- package/dist/commands/uninstall.js +0 -77
- package/dist/commands/update.js +0 -121
- package/dist/commands/upgrade.js +0 -121
- package/dist/commands/whoami.js +0 -75
- 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/filesystem.js +0 -124
- package/dist/core/lockfile.js +0 -239
- package/dist/core/marketplace-converter.js +0 -198
- package/dist/core/registry-client.js +0 -265
- package/dist/core/schema-validator.js +0 -74
- package/dist/core/telemetry.js +0 -175
- package/dist/core/user-config.js +0 -79
- package/dist/types/registry.js +0 -5
- package/dist/types.js +0 -5
package/dist/commands/install.js
DELETED
|
@@ -1,477 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Install command - Install packages from registry
|
|
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.handleInstall = handleInstall;
|
|
40
|
-
exports.createInstallCommand = createInstallCommand;
|
|
41
|
-
const commander_1 = require("commander");
|
|
42
|
-
const registry_client_1 = require("@pr-pm/registry-client");
|
|
43
|
-
const user_config_1 = require("../core/user-config");
|
|
44
|
-
const filesystem_1 = require("../core/filesystem");
|
|
45
|
-
const telemetry_1 = require("../core/telemetry");
|
|
46
|
-
const tar = __importStar(require("tar"));
|
|
47
|
-
const lockfile_1 = require("../core/lockfile");
|
|
48
|
-
const cursor_config_1 = require("../core/cursor-config");
|
|
49
|
-
const claude_config_1 = require("../core/claude-config");
|
|
50
|
-
/**
|
|
51
|
-
* Get icon for package type
|
|
52
|
-
*/
|
|
53
|
-
function getTypeIcon(type) {
|
|
54
|
-
const icons = {
|
|
55
|
-
'claude-skill': '🎓',
|
|
56
|
-
'claude-agent': '🤖',
|
|
57
|
-
'claude-slash-command': '⚡',
|
|
58
|
-
'claude': '🤖',
|
|
59
|
-
'cursor': '📋',
|
|
60
|
-
'cursor-agent': '🤖',
|
|
61
|
-
'cursor-slash-command': '⚡',
|
|
62
|
-
'windsurf': '🌊',
|
|
63
|
-
'continue': '➡️',
|
|
64
|
-
'mcp': '🔗',
|
|
65
|
-
'generic': '📦',
|
|
66
|
-
// Legacy mappings
|
|
67
|
-
skill: '🎓',
|
|
68
|
-
agent: '🤖',
|
|
69
|
-
rule: '📋',
|
|
70
|
-
plugin: '🔌',
|
|
71
|
-
prompt: '💬',
|
|
72
|
-
workflow: '⚡',
|
|
73
|
-
tool: '🔧',
|
|
74
|
-
template: '📄',
|
|
75
|
-
};
|
|
76
|
-
return icons[type] || '📦';
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Get human-readable label for package type
|
|
80
|
-
*/
|
|
81
|
-
function getTypeLabel(type) {
|
|
82
|
-
const labels = {
|
|
83
|
-
'claude-skill': 'Claude Skill',
|
|
84
|
-
'claude-agent': 'Claude Agent',
|
|
85
|
-
'claude-slash-command': 'Claude Slash Command',
|
|
86
|
-
'claude': 'Claude Agent',
|
|
87
|
-
'cursor': 'Cursor Rule',
|
|
88
|
-
'cursor-agent': 'Cursor Agent',
|
|
89
|
-
'cursor-slash-command': 'Cursor Slash Command',
|
|
90
|
-
'windsurf': 'Windsurf Rule',
|
|
91
|
-
'continue': 'Continue Rule',
|
|
92
|
-
'mcp': 'MCP Server',
|
|
93
|
-
'generic': 'Package',
|
|
94
|
-
// Legacy mappings
|
|
95
|
-
skill: 'Skill',
|
|
96
|
-
agent: 'Agent',
|
|
97
|
-
rule: 'Rule',
|
|
98
|
-
plugin: 'Plugin',
|
|
99
|
-
prompt: 'Prompt',
|
|
100
|
-
workflow: 'Workflow',
|
|
101
|
-
tool: 'Tool',
|
|
102
|
-
template: 'Template',
|
|
103
|
-
};
|
|
104
|
-
return labels[type] || type;
|
|
105
|
-
}
|
|
106
|
-
async function handleInstall(packageSpec, options) {
|
|
107
|
-
const startTime = Date.now();
|
|
108
|
-
let success = false;
|
|
109
|
-
let error;
|
|
110
|
-
try {
|
|
111
|
-
// Parse package spec (e.g., "react-rules" or "react-rules@1.2.0" or "@pr-pm/pkg@1.0.0")
|
|
112
|
-
// For scoped packages (@scope/name), the first @ is part of the package name
|
|
113
|
-
let packageId;
|
|
114
|
-
let specVersion;
|
|
115
|
-
if (packageSpec.startsWith('@')) {
|
|
116
|
-
// Scoped package: @scope/name or @scope/name@version
|
|
117
|
-
const match = packageSpec.match(/^(@[^/]+\/[^@]+)(?:@(.+))?$/);
|
|
118
|
-
if (!match) {
|
|
119
|
-
throw new Error('Invalid package spec format. Use: @scope/package or @scope/package@version');
|
|
120
|
-
}
|
|
121
|
-
packageId = match[1];
|
|
122
|
-
specVersion = match[2];
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
125
|
-
// Unscoped package: name or name@version
|
|
126
|
-
const parts = packageSpec.split('@');
|
|
127
|
-
packageId = parts[0];
|
|
128
|
-
specVersion = parts[1];
|
|
129
|
-
}
|
|
130
|
-
// Read existing lock file
|
|
131
|
-
const lockfile = await (0, lockfile_1.readLockfile)();
|
|
132
|
-
const lockedVersion = (0, lockfile_1.getLockedVersion)(lockfile, packageId);
|
|
133
|
-
// Determine version to install
|
|
134
|
-
let version;
|
|
135
|
-
if (options.frozenLockfile) {
|
|
136
|
-
// Frozen lockfile mode - must use exact locked version
|
|
137
|
-
if (!lockedVersion) {
|
|
138
|
-
throw new Error(`Package ${packageId} not found in lock file. Run without --frozen-lockfile to update.`);
|
|
139
|
-
}
|
|
140
|
-
version = lockedVersion;
|
|
141
|
-
}
|
|
142
|
-
else {
|
|
143
|
-
// Normal mode - use specified version or locked version or latest
|
|
144
|
-
version = options.version || specVersion || lockedVersion || 'latest';
|
|
145
|
-
}
|
|
146
|
-
// Check if package is already installed
|
|
147
|
-
if (lockfile && lockfile.packages[packageId]) {
|
|
148
|
-
const installedPkg = lockfile.packages[packageId];
|
|
149
|
-
const requestedVersion = options.version || specVersion;
|
|
150
|
-
// If no specific version requested, or same version requested
|
|
151
|
-
if (!requestedVersion || requestedVersion === 'latest' || requestedVersion === installedPkg.version) {
|
|
152
|
-
console.log(`\n✨ Package already installed!`);
|
|
153
|
-
console.log(` 📦 ${packageId}@${installedPkg.version}`);
|
|
154
|
-
console.log(` 🔄 Format: ${installedPkg.format || installedPkg.type || 'unknown'}`);
|
|
155
|
-
console.log(`\n💡 To reinstall or upgrade:`);
|
|
156
|
-
console.log(` prpm upgrade ${packageId} # Upgrade to latest version`);
|
|
157
|
-
console.log(` prpm uninstall ${packageId} # Uninstall first, then install`);
|
|
158
|
-
success = true;
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
else if (requestedVersion !== installedPkg.version) {
|
|
162
|
-
// Different version requested - allow upgrade/downgrade
|
|
163
|
-
console.log(`📦 Upgrading ${packageId}: ${installedPkg.version} → ${requestedVersion}`);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
console.log(`📥 Installing ${packageId}@${version}...`);
|
|
167
|
-
const config = await (0, user_config_1.getConfig)();
|
|
168
|
-
const client = (0, registry_client_1.getRegistryClient)(config);
|
|
169
|
-
// Check if this is a collection first (by trying to fetch it)
|
|
170
|
-
// Collections can be: name, scope/name, or @scope/name
|
|
171
|
-
let isCollection = false;
|
|
172
|
-
try {
|
|
173
|
-
// Try to parse as collection
|
|
174
|
-
let scope;
|
|
175
|
-
let name_slug;
|
|
176
|
-
const matchWithScope = packageId.match(/^@?([^/]+)\/([^/@]+)$/);
|
|
177
|
-
if (matchWithScope) {
|
|
178
|
-
[, scope, name_slug] = matchWithScope;
|
|
179
|
-
}
|
|
180
|
-
else {
|
|
181
|
-
// No scope, assume 'collection' scope
|
|
182
|
-
scope = 'collection';
|
|
183
|
-
name_slug = packageId;
|
|
184
|
-
}
|
|
185
|
-
// Try to fetch as collection
|
|
186
|
-
await client.getCollection(scope, name_slug, version === 'latest' ? undefined : version);
|
|
187
|
-
isCollection = true;
|
|
188
|
-
// If successful, delegate to collection install handler
|
|
189
|
-
const { handleCollectionInstall } = await Promise.resolve().then(() => __importStar(require('./collections.js')));
|
|
190
|
-
return await handleCollectionInstall(packageId, {
|
|
191
|
-
format: options.as,
|
|
192
|
-
skipOptional: false,
|
|
193
|
-
dryRun: false,
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
catch (err) {
|
|
197
|
-
// Not a collection, continue with package install
|
|
198
|
-
isCollection = false;
|
|
199
|
-
}
|
|
200
|
-
// Get package info
|
|
201
|
-
const pkg = await client.getPackage(packageId);
|
|
202
|
-
const typeIcon = getTypeIcon(pkg.type);
|
|
203
|
-
const typeLabel = getTypeLabel(pkg.type);
|
|
204
|
-
console.log(` ${pkg.name} ${pkg.official ? '🏅' : ''}`);
|
|
205
|
-
console.log(` ${pkg.description || 'No description'}`);
|
|
206
|
-
console.log(` ${typeIcon} Type: ${typeLabel}`);
|
|
207
|
-
// Determine format preference - use package type if no explicit conversion requested
|
|
208
|
-
const format = options.as || pkg.type;
|
|
209
|
-
if (options.as && format !== 'canonical') {
|
|
210
|
-
console.log(` 🔄 Converting to ${format} format...`);
|
|
211
|
-
}
|
|
212
|
-
// Determine version to install
|
|
213
|
-
let tarballUrl;
|
|
214
|
-
if (version === 'latest') {
|
|
215
|
-
if (!pkg.latest_version) {
|
|
216
|
-
throw new Error('No versions available for this package');
|
|
217
|
-
}
|
|
218
|
-
tarballUrl = pkg.latest_version.tarball_url;
|
|
219
|
-
console.log(` 📦 Installing version ${pkg.latest_version.version}`);
|
|
220
|
-
}
|
|
221
|
-
else {
|
|
222
|
-
const versionInfo = await client.getPackageVersion(packageId, version);
|
|
223
|
-
tarballUrl = versionInfo.tarball_url;
|
|
224
|
-
console.log(` 📦 Installing version ${version}`);
|
|
225
|
-
}
|
|
226
|
-
// Download package in requested format
|
|
227
|
-
console.log(` ⬇️ Downloading...`);
|
|
228
|
-
const tarball = await client.downloadPackage(tarballUrl, { format });
|
|
229
|
-
// Extract tarball and save files
|
|
230
|
-
console.log(` 📂 Extracting...`);
|
|
231
|
-
// Determine effective type based on format and original package type
|
|
232
|
-
let effectiveType;
|
|
233
|
-
if (format === 'cursor') {
|
|
234
|
-
// Map package types to cursor equivalents
|
|
235
|
-
if (pkg.type === 'claude-slash-command' || pkg.type === 'cursor-slash-command') {
|
|
236
|
-
effectiveType = 'cursor-slash-command';
|
|
237
|
-
}
|
|
238
|
-
else if (pkg.type === 'claude-agent' || pkg.type === 'cursor-agent') {
|
|
239
|
-
effectiveType = 'cursor-agent';
|
|
240
|
-
}
|
|
241
|
-
else {
|
|
242
|
-
effectiveType = 'cursor';
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
else if (format === 'claude') {
|
|
246
|
-
// Map package types to claude equivalents
|
|
247
|
-
if (pkg.type === 'cursor-slash-command' || pkg.type === 'claude-slash-command') {
|
|
248
|
-
effectiveType = 'claude-slash-command';
|
|
249
|
-
}
|
|
250
|
-
else if (pkg.type === 'cursor-agent' || pkg.type === 'claude-agent') {
|
|
251
|
-
effectiveType = 'claude-agent';
|
|
252
|
-
}
|
|
253
|
-
else if (pkg.type === 'claude-skill') {
|
|
254
|
-
effectiveType = 'claude-skill';
|
|
255
|
-
}
|
|
256
|
-
else {
|
|
257
|
-
effectiveType = 'claude-agent';
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
else if (format === 'continue' || format === 'windsurf') {
|
|
261
|
-
effectiveType = format;
|
|
262
|
-
}
|
|
263
|
-
else {
|
|
264
|
-
effectiveType = (options.type || pkg.type);
|
|
265
|
-
}
|
|
266
|
-
const destDir = (0, filesystem_1.getDestinationDir)(effectiveType);
|
|
267
|
-
// Extract all files from tarball
|
|
268
|
-
const extractedFiles = await extractTarball(tarball, packageId);
|
|
269
|
-
// Track where files were saved for user feedback
|
|
270
|
-
let destPath;
|
|
271
|
-
let fileCount = 0;
|
|
272
|
-
// Check if this is a multi-file package
|
|
273
|
-
if (extractedFiles.length === 1) {
|
|
274
|
-
// Single file package
|
|
275
|
-
let mainFile = extractedFiles[0].content;
|
|
276
|
-
// Determine file extension based on effective type
|
|
277
|
-
// Cursor rules use .mdc, but slash commands and other files use .md
|
|
278
|
-
const fileExtension = (effectiveType === 'cursor' && format === 'cursor') ? 'mdc' : 'md';
|
|
279
|
-
const packageName = (0, filesystem_1.stripAuthorNamespace)(packageId);
|
|
280
|
-
destPath = `${destDir}/${packageName}.${fileExtension}`;
|
|
281
|
-
// Handle cursor format - add header if missing for .mdc files
|
|
282
|
-
if (format === 'cursor' && effectiveType === 'cursor') {
|
|
283
|
-
if (!(0, cursor_config_1.hasMDCHeader)(mainFile)) {
|
|
284
|
-
console.log(` ⚠️ Adding missing MDC header...`);
|
|
285
|
-
mainFile = (0, cursor_config_1.addMDCHeader)(mainFile, pkg.description);
|
|
286
|
-
}
|
|
287
|
-
// Apply cursor config if available
|
|
288
|
-
if (config.cursor) {
|
|
289
|
-
console.log(` ⚙️ Applying cursor config...`);
|
|
290
|
-
mainFile = (0, cursor_config_1.applyCursorConfig)(mainFile, config.cursor);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
// Apply Claude config if downloading in Claude format
|
|
294
|
-
if (format === 'claude' && (0, claude_config_1.hasClaudeHeader)(mainFile)) {
|
|
295
|
-
if (config.claude) {
|
|
296
|
-
console.log(` ⚙️ Applying Claude agent config...`);
|
|
297
|
-
mainFile = (0, claude_config_1.applyClaudeConfig)(mainFile, config.claude);
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
await (0, filesystem_1.saveFile)(destPath, mainFile);
|
|
301
|
-
fileCount = 1;
|
|
302
|
-
}
|
|
303
|
-
else {
|
|
304
|
-
// Multi-file package - create directory for package
|
|
305
|
-
const packageName = (0, filesystem_1.stripAuthorNamespace)(packageId);
|
|
306
|
-
const packageDir = `${destDir}/${packageName}`;
|
|
307
|
-
destPath = packageDir;
|
|
308
|
-
console.log(` 📁 Multi-file package - creating directory: ${packageDir}`);
|
|
309
|
-
for (const file of extractedFiles) {
|
|
310
|
-
const filePath = `${packageDir}/${file.name}`;
|
|
311
|
-
await (0, filesystem_1.saveFile)(filePath, file.content);
|
|
312
|
-
fileCount++;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
// Update or create lock file
|
|
316
|
-
const updatedLockfile = lockfile || (0, lockfile_1.createLockfile)();
|
|
317
|
-
const actualVersion = version === 'latest' ? pkg.latest_version?.version : version;
|
|
318
|
-
(0, lockfile_1.addToLockfile)(updatedLockfile, packageId, {
|
|
319
|
-
version: actualVersion || version,
|
|
320
|
-
tarballUrl,
|
|
321
|
-
type: pkg.type,
|
|
322
|
-
format,
|
|
323
|
-
installedPath: destPath,
|
|
324
|
-
});
|
|
325
|
-
(0, lockfile_1.setPackageIntegrity)(updatedLockfile, packageId, tarball);
|
|
326
|
-
await (0, lockfile_1.writeLockfile)(updatedLockfile);
|
|
327
|
-
// Update lockfile (already done above via addToLockfile + writeLockfile)
|
|
328
|
-
// No need to call addPackage again as it would be redundant
|
|
329
|
-
// Track download analytics
|
|
330
|
-
await client.trackDownload(packageId, {
|
|
331
|
-
version: actualVersion || version,
|
|
332
|
-
client: 'cli',
|
|
333
|
-
format,
|
|
334
|
-
});
|
|
335
|
-
// Display the incremented download count
|
|
336
|
-
const newDownloadCount = pkg.total_downloads + 1;
|
|
337
|
-
console.log(`\n✅ Successfully installed ${packageId}`);
|
|
338
|
-
console.log(` 📁 Saved to: ${destPath}`);
|
|
339
|
-
console.log(` 🔒 Lock file updated`);
|
|
340
|
-
console.log(`\n💡 This package has been downloaded ${newDownloadCount.toLocaleString()} times`);
|
|
341
|
-
success = true;
|
|
342
|
-
}
|
|
343
|
-
catch (err) {
|
|
344
|
-
error = err instanceof Error ? err.message : String(err);
|
|
345
|
-
console.error(`\n❌ Installation failed: ${error}`);
|
|
346
|
-
console.log(`\n💡 Tips:`);
|
|
347
|
-
console.log(` - Check package name: prpm search <query>`);
|
|
348
|
-
console.log(` - Get package info: prpm info <package>`);
|
|
349
|
-
process.exit(1);
|
|
350
|
-
}
|
|
351
|
-
finally {
|
|
352
|
-
await telemetry_1.telemetry.track({
|
|
353
|
-
command: 'install',
|
|
354
|
-
success,
|
|
355
|
-
error,
|
|
356
|
-
duration: Date.now() - startTime,
|
|
357
|
-
data: {
|
|
358
|
-
packageId: packageSpec.split('@')[0],
|
|
359
|
-
version: options.version || 'latest',
|
|
360
|
-
type: options.type,
|
|
361
|
-
},
|
|
362
|
-
});
|
|
363
|
-
await telemetry_1.telemetry.shutdown();
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
async function extractTarball(tarball, packageId) {
|
|
367
|
-
const files = [];
|
|
368
|
-
const zlib = await Promise.resolve().then(() => __importStar(require('zlib')));
|
|
369
|
-
const fs = await Promise.resolve().then(() => __importStar(require('fs')));
|
|
370
|
-
const os = await Promise.resolve().then(() => __importStar(require('os')));
|
|
371
|
-
const path = await Promise.resolve().then(() => __importStar(require('path')));
|
|
372
|
-
return new Promise((resolve, reject) => {
|
|
373
|
-
// Decompress gzip first
|
|
374
|
-
zlib.gunzip(tarball, async (err, result) => {
|
|
375
|
-
if (err) {
|
|
376
|
-
reject(err);
|
|
377
|
-
return;
|
|
378
|
-
}
|
|
379
|
-
// Check if this is a tar archive by looking for tar header
|
|
380
|
-
const isTar = result.length > 257 && result.toString('utf-8', 257, 262) === 'ustar';
|
|
381
|
-
if (!isTar) {
|
|
382
|
-
// Not a tar archive, treat as single gzipped file
|
|
383
|
-
files.push({
|
|
384
|
-
name: `${packageId}.md`,
|
|
385
|
-
content: result.toString('utf-8')
|
|
386
|
-
});
|
|
387
|
-
resolve(files);
|
|
388
|
-
return;
|
|
389
|
-
}
|
|
390
|
-
// Create temp directory for extraction
|
|
391
|
-
const tmpDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'prpm-'));
|
|
392
|
-
try {
|
|
393
|
-
// Write tar data to temp file
|
|
394
|
-
const tarPath = path.join(tmpDir, 'package.tar');
|
|
395
|
-
await fs.promises.writeFile(tarPath, result);
|
|
396
|
-
// Extract using tar library
|
|
397
|
-
await tar.extract({
|
|
398
|
-
file: tarPath,
|
|
399
|
-
cwd: tmpDir,
|
|
400
|
-
});
|
|
401
|
-
// Read all extracted files
|
|
402
|
-
const extractedFiles = await fs.promises.readdir(tmpDir, { withFileTypes: true, recursive: true });
|
|
403
|
-
for (const entry of extractedFiles) {
|
|
404
|
-
if (entry.isFile() && entry.name !== 'package.tar') {
|
|
405
|
-
const filePath = path.join(entry.path || tmpDir, entry.name);
|
|
406
|
-
const content = await fs.promises.readFile(filePath, 'utf-8');
|
|
407
|
-
const relativePath = path.relative(tmpDir, filePath);
|
|
408
|
-
files.push({
|
|
409
|
-
name: relativePath,
|
|
410
|
-
content
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
if (files.length === 0) {
|
|
415
|
-
// No files found, fall back to single file
|
|
416
|
-
files.push({
|
|
417
|
-
name: `${packageId}.md`,
|
|
418
|
-
content: result.toString('utf-8')
|
|
419
|
-
});
|
|
420
|
-
}
|
|
421
|
-
// Cleanup
|
|
422
|
-
await fs.promises.rm(tmpDir, { recursive: true, force: true });
|
|
423
|
-
resolve(files);
|
|
424
|
-
}
|
|
425
|
-
catch (tarErr) {
|
|
426
|
-
// Cleanup and fall back to single file
|
|
427
|
-
await fs.promises.rm(tmpDir, { recursive: true, force: true }).catch(() => { });
|
|
428
|
-
files.push({
|
|
429
|
-
name: `${packageId}.md`,
|
|
430
|
-
content: result.toString('utf-8')
|
|
431
|
-
});
|
|
432
|
-
resolve(files);
|
|
433
|
-
}
|
|
434
|
-
});
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
|
-
/**
|
|
438
|
-
* Detect project format from existing directories
|
|
439
|
-
*/
|
|
440
|
-
function detectProjectFormat() {
|
|
441
|
-
const fs = require('fs');
|
|
442
|
-
if (fs.existsSync('.cursor/rules') || fs.existsSync('.cursor'))
|
|
443
|
-
return 'cursor';
|
|
444
|
-
if (fs.existsSync('.claude/agents') || fs.existsSync('.claude'))
|
|
445
|
-
return 'claude';
|
|
446
|
-
if (fs.existsSync('.continue'))
|
|
447
|
-
return 'continue';
|
|
448
|
-
if (fs.existsSync('.windsurf'))
|
|
449
|
-
return 'windsurf';
|
|
450
|
-
return null;
|
|
451
|
-
}
|
|
452
|
-
function createInstallCommand() {
|
|
453
|
-
const command = new commander_1.Command('install');
|
|
454
|
-
command
|
|
455
|
-
.description('Install a package from the registry')
|
|
456
|
-
.argument('<package>', 'Package to install (e.g., react-rules or react-rules@1.2.0)')
|
|
457
|
-
.option('--version <version>', 'Specific version to install')
|
|
458
|
-
.option('--type <type>', 'Override package type (cursor, claude, continue)')
|
|
459
|
-
.option('--as <format>', 'Download in specific format (cursor, claude, continue, windsurf)')
|
|
460
|
-
.option('--frozen-lockfile', 'Fail if lock file needs to be updated (for CI)')
|
|
461
|
-
.action(async (packageSpec, options) => {
|
|
462
|
-
if (options.type && !['cursor', 'claude', 'continue', 'windsurf', 'generic'].includes(options.type)) {
|
|
463
|
-
console.error('❌ Type must be one of: cursor, claude, continue, windsurf, generic');
|
|
464
|
-
process.exit(1);
|
|
465
|
-
}
|
|
466
|
-
if (options.as && !['cursor', 'claude', 'continue', 'windsurf', 'canonical'].includes(options.as)) {
|
|
467
|
-
console.error('❌ Format must be one of: cursor, claude, continue, windsurf, canonical');
|
|
468
|
-
process.exit(1);
|
|
469
|
-
}
|
|
470
|
-
await handleInstall(packageSpec, {
|
|
471
|
-
type: options.type,
|
|
472
|
-
as: options.as,
|
|
473
|
-
frozenLockfile: options.frozenLockfile
|
|
474
|
-
});
|
|
475
|
-
});
|
|
476
|
-
return command;
|
|
477
|
-
}
|
package/dist/commands/list.js
DELETED
|
@@ -1,166 +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
|
-
/**
|
|
17
|
-
* Get destination directory based on package type
|
|
18
|
-
*/
|
|
19
|
-
function getDestinationDir(type) {
|
|
20
|
-
switch (type) {
|
|
21
|
-
case 'cursor':
|
|
22
|
-
return '.cursor/rules';
|
|
23
|
-
case 'claude':
|
|
24
|
-
return '.claude/agents';
|
|
25
|
-
case 'claude-agent':
|
|
26
|
-
return '.claude/agents';
|
|
27
|
-
case 'claude-skill':
|
|
28
|
-
return '.claude/skills';
|
|
29
|
-
case 'claude-slash-command':
|
|
30
|
-
return '.claude/commands';
|
|
31
|
-
case 'continue':
|
|
32
|
-
return '.continue/rules';
|
|
33
|
-
case 'windsurf':
|
|
34
|
-
return '.windsurf/rules';
|
|
35
|
-
case 'generic':
|
|
36
|
-
return '.prompts';
|
|
37
|
-
case 'mcp':
|
|
38
|
-
return '.mcp';
|
|
39
|
-
default:
|
|
40
|
-
return '.prompts';
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Find the actual file location for a package
|
|
45
|
-
*/
|
|
46
|
-
async function findPackageLocation(id, type) {
|
|
47
|
-
if (!type)
|
|
48
|
-
return null;
|
|
49
|
-
const baseDir = getDestinationDir(type);
|
|
50
|
-
// Try direct file: <dir>/<id>.md
|
|
51
|
-
const directPath = path_1.default.join(baseDir, `${id}.md`);
|
|
52
|
-
try {
|
|
53
|
-
await fs_1.promises.access(directPath);
|
|
54
|
-
return directPath;
|
|
55
|
-
}
|
|
56
|
-
catch {
|
|
57
|
-
// File doesn't exist, try subdirectory
|
|
58
|
-
}
|
|
59
|
-
// Try subdirectory: <dir>/<id>/SKILL.md or <dir>/<id>/AGENT.md
|
|
60
|
-
if (type === 'claude-skill') {
|
|
61
|
-
const skillPath = path_1.default.join(baseDir, id, 'SKILL.md');
|
|
62
|
-
try {
|
|
63
|
-
await fs_1.promises.access(skillPath);
|
|
64
|
-
return skillPath;
|
|
65
|
-
}
|
|
66
|
-
catch {
|
|
67
|
-
// Not found
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
if (type === 'claude') {
|
|
71
|
-
const agentPath = path_1.default.join(baseDir, id, 'AGENT.md');
|
|
72
|
-
try {
|
|
73
|
-
await fs_1.promises.access(agentPath);
|
|
74
|
-
return agentPath;
|
|
75
|
-
}
|
|
76
|
-
catch {
|
|
77
|
-
// Not found
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Display packages in a formatted table
|
|
84
|
-
*/
|
|
85
|
-
async function displayPackages(packages) {
|
|
86
|
-
if (packages.length === 0) {
|
|
87
|
-
console.log('📦 No packages installed');
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
console.log('📦 Installed packages:');
|
|
91
|
-
console.log('');
|
|
92
|
-
// Find file locations
|
|
93
|
-
const packagesWithLocations = await Promise.all(packages.map(async (pkg) => ({
|
|
94
|
-
...pkg,
|
|
95
|
-
location: await findPackageLocation(pkg.id, pkg.type)
|
|
96
|
-
})));
|
|
97
|
-
// Calculate column widths
|
|
98
|
-
const idWidth = Math.max(8, ...packagesWithLocations.map(p => p.id.length));
|
|
99
|
-
const versionWidth = Math.max(7, ...packagesWithLocations.map(p => p.version.length));
|
|
100
|
-
const typeWidth = Math.max(6, ...packagesWithLocations.map(p => (p.type || '').length));
|
|
101
|
-
const locationWidth = Math.max(8, ...packagesWithLocations.map(p => (p.location || 'N/A').length));
|
|
102
|
-
// Header
|
|
103
|
-
const header = [
|
|
104
|
-
'ID'.padEnd(idWidth),
|
|
105
|
-
'VERSION'.padEnd(versionWidth),
|
|
106
|
-
'TYPE'.padEnd(typeWidth),
|
|
107
|
-
'LOCATION'.padEnd(locationWidth)
|
|
108
|
-
].join(' | ');
|
|
109
|
-
console.log(header);
|
|
110
|
-
console.log('-'.repeat(header.length));
|
|
111
|
-
// Rows
|
|
112
|
-
packagesWithLocations.forEach(pkg => {
|
|
113
|
-
const row = [
|
|
114
|
-
pkg.id.padEnd(idWidth),
|
|
115
|
-
pkg.version.padEnd(versionWidth),
|
|
116
|
-
(pkg.type || '').padEnd(typeWidth),
|
|
117
|
-
(pkg.location || 'N/A').padEnd(locationWidth)
|
|
118
|
-
].join(' | ');
|
|
119
|
-
console.log(row);
|
|
120
|
-
});
|
|
121
|
-
console.log('');
|
|
122
|
-
console.log(`Total: ${packages.length} package${packages.length === 1 ? '' : 's'}`);
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Handle the list command
|
|
126
|
-
*/
|
|
127
|
-
async function handleList() {
|
|
128
|
-
const startTime = Date.now();
|
|
129
|
-
let success = false;
|
|
130
|
-
let error;
|
|
131
|
-
let packageCount = 0;
|
|
132
|
-
try {
|
|
133
|
-
const packages = await (0, lockfile_1.listPackages)();
|
|
134
|
-
packageCount = packages.length;
|
|
135
|
-
await displayPackages(packages);
|
|
136
|
-
success = true;
|
|
137
|
-
}
|
|
138
|
-
catch (err) {
|
|
139
|
-
error = err instanceof Error ? err.message : String(err);
|
|
140
|
-
console.error(`❌ Failed to list packages: ${error}`);
|
|
141
|
-
process.exit(1);
|
|
142
|
-
}
|
|
143
|
-
finally {
|
|
144
|
-
// Track telemetry
|
|
145
|
-
await telemetry_1.telemetry.track({
|
|
146
|
-
command: 'list',
|
|
147
|
-
success,
|
|
148
|
-
error,
|
|
149
|
-
duration: Date.now() - startTime,
|
|
150
|
-
data: {
|
|
151
|
-
packageCount,
|
|
152
|
-
},
|
|
153
|
-
});
|
|
154
|
-
await telemetry_1.telemetry.shutdown();
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* Create the list command
|
|
159
|
-
*/
|
|
160
|
-
function createListCommand() {
|
|
161
|
-
const command = new commander_1.Command('list');
|
|
162
|
-
command
|
|
163
|
-
.description('List all installed prompt packages')
|
|
164
|
-
.action(handleList);
|
|
165
|
-
return command;
|
|
166
|
-
}
|