prpm 0.1.9 ā 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/install.js +57 -3
- package/dist/commands/publish.js +39 -8
- package/package.json +3 -3
package/dist/commands/install.js
CHANGED
|
@@ -356,10 +356,14 @@ async function handleInstall(packageSpec, options) {
|
|
|
356
356
|
const destDir = (0, filesystem_1.getDestinationDir)(effectiveFormat, effectiveSubtype, pkg.name);
|
|
357
357
|
// Multi-file package - create directory for package
|
|
358
358
|
// For Claude skills, destDir already includes package name, so use it directly
|
|
359
|
+
// For Cursor rules converted from Claude skills, use flat structure
|
|
359
360
|
const packageName = (0, filesystem_1.stripAuthorNamespace)(packageId);
|
|
361
|
+
const isCursorConversion = (effectiveFormat === 'cursor' && pkg.format === 'claude' && pkg.subtype === 'skill');
|
|
360
362
|
const packageDir = (effectiveFormat === 'claude' && effectiveSubtype === 'skill')
|
|
361
363
|
? destDir
|
|
362
|
-
:
|
|
364
|
+
: isCursorConversion
|
|
365
|
+
? destDir // Cursor uses flat structure
|
|
366
|
+
: `${destDir}/${packageName}`;
|
|
363
367
|
destPath = packageDir;
|
|
364
368
|
console.log(` š Multi-file package - creating directory: ${packageDir}`);
|
|
365
369
|
// For Claude skills, verify SKILL.md exists
|
|
@@ -385,6 +389,8 @@ async function handleInstall(packageSpec, options) {
|
|
|
385
389
|
}
|
|
386
390
|
}
|
|
387
391
|
}
|
|
392
|
+
// Track JSON files for @reference insertion in Cursor conversion
|
|
393
|
+
const jsonFiles = [];
|
|
388
394
|
for (const file of extractedFiles) {
|
|
389
395
|
// Strip the tarball's root directory prefix to preserve subdirectories
|
|
390
396
|
// Example: ".claude/skills/agent-builder/docs/examples.md" ā "docs/examples.md"
|
|
@@ -404,10 +410,58 @@ async function handleInstall(packageSpec, options) {
|
|
|
404
410
|
// Fallback: just take the filename (last part)
|
|
405
411
|
relativeFileName = pathParts[pathParts.length - 1];
|
|
406
412
|
}
|
|
407
|
-
|
|
408
|
-
|
|
413
|
+
let fileContent = file.content;
|
|
414
|
+
let fileName = relativeFileName;
|
|
415
|
+
// Handle Cursor conversion from Claude skill
|
|
416
|
+
if (isCursorConversion) {
|
|
417
|
+
// Convert SKILL.md to .mdc
|
|
418
|
+
if (fileName === 'SKILL.md' || fileName.endsWith('/SKILL.md')) {
|
|
419
|
+
fileName = `${packageName}.mdc`;
|
|
420
|
+
// Add MDC header if missing
|
|
421
|
+
if (!(0, cursor_config_1.hasMDCHeader)(fileContent)) {
|
|
422
|
+
console.log(` ā ļø Adding MDC header to converted skill...`);
|
|
423
|
+
fileContent = (0, cursor_config_1.addMDCHeader)(fileContent, pkg.description);
|
|
424
|
+
}
|
|
425
|
+
// Apply cursor config if available
|
|
426
|
+
if (config.cursor) {
|
|
427
|
+
console.log(` āļø Applying cursor config...`);
|
|
428
|
+
fileContent = (0, cursor_config_1.applyCursorConfig)(fileContent, config.cursor);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
// Track JSON files for @reference
|
|
432
|
+
else if (fileName.endsWith('.json')) {
|
|
433
|
+
// Flatten structure - remove subdirectories
|
|
434
|
+
const jsonFileName = fileName.split('/').pop() || fileName;
|
|
435
|
+
fileName = jsonFileName;
|
|
436
|
+
jsonFiles.push(jsonFileName);
|
|
437
|
+
}
|
|
438
|
+
// For other files (docs, etc), flatten the structure
|
|
439
|
+
else {
|
|
440
|
+
fileName = fileName.split('/').pop() || fileName;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
const filePath = `${packageDir}/${fileName}`;
|
|
444
|
+
await (0, filesystem_1.saveFile)(filePath, fileContent);
|
|
409
445
|
fileCount++;
|
|
410
446
|
}
|
|
447
|
+
// Add @references to .mdc file for JSON files
|
|
448
|
+
if (isCursorConversion && jsonFiles.length > 0) {
|
|
449
|
+
const mdcFile = `${packageDir}/${packageName}.mdc`;
|
|
450
|
+
const { readFile } = await Promise.resolve().then(() => __importStar(require('fs/promises')));
|
|
451
|
+
let mdcContent = await readFile(mdcFile, 'utf-8');
|
|
452
|
+
// Find the end of frontmatter (if exists)
|
|
453
|
+
const frontmatterMatch = mdcContent.match(/^---\n[\s\S]*?\n---\n/);
|
|
454
|
+
if (frontmatterMatch) {
|
|
455
|
+
const frontmatterEnd = frontmatterMatch[0].length;
|
|
456
|
+
const beforeFrontmatter = mdcContent.slice(0, frontmatterEnd);
|
|
457
|
+
const afterFrontmatter = mdcContent.slice(frontmatterEnd);
|
|
458
|
+
// Add @references right after frontmatter
|
|
459
|
+
const references = jsonFiles.map(f => `@${f}`).join('\n');
|
|
460
|
+
mdcContent = `${beforeFrontmatter}\n${references}\n${afterFrontmatter}`;
|
|
461
|
+
await (0, filesystem_1.saveFile)(mdcFile, mdcContent);
|
|
462
|
+
console.log(` ā Added ${jsonFiles.length} @reference(s) to ${packageName}.mdc`);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
411
465
|
}
|
|
412
466
|
// Update or create lock file
|
|
413
467
|
const updatedLockfile = lockfile || (0, lockfile_1.createLockfile)();
|
package/dist/commands/publish.js
CHANGED
|
@@ -254,6 +254,28 @@ function normalizeFilePaths(files) {
|
|
|
254
254
|
}
|
|
255
255
|
});
|
|
256
256
|
}
|
|
257
|
+
/**
|
|
258
|
+
* Predict what the scoped package name will be after publishing
|
|
259
|
+
* This matches the server-side logic in packages.ts
|
|
260
|
+
*/
|
|
261
|
+
function predictScopedPackageName(manifestName, username, organization) {
|
|
262
|
+
const usernameLowercase = username.toLowerCase();
|
|
263
|
+
// If organization is specified, use @org-name/
|
|
264
|
+
if (organization) {
|
|
265
|
+
const orgNameLowercase = organization.toLowerCase();
|
|
266
|
+
const expectedPrefix = `@${orgNameLowercase}/`;
|
|
267
|
+
if (!manifestName.startsWith(expectedPrefix)) {
|
|
268
|
+
return `${expectedPrefix}${manifestName}`;
|
|
269
|
+
}
|
|
270
|
+
return manifestName;
|
|
271
|
+
}
|
|
272
|
+
// If package name doesn't already have a scope, add @username/
|
|
273
|
+
if (!manifestName.startsWith('@')) {
|
|
274
|
+
return `@${usernameLowercase}/${manifestName}`;
|
|
275
|
+
}
|
|
276
|
+
// Package already has a scope, return as-is
|
|
277
|
+
return manifestName;
|
|
278
|
+
}
|
|
257
279
|
/**
|
|
258
280
|
* Create tarball from current directory
|
|
259
281
|
*/
|
|
@@ -442,6 +464,7 @@ async function handlePublish(options) {
|
|
|
442
464
|
console.log('');
|
|
443
465
|
}
|
|
444
466
|
let selectedOrgId;
|
|
467
|
+
let selectedOrgName;
|
|
445
468
|
// Check if organization is specified in manifest
|
|
446
469
|
if (manifest.organization && userInfo) {
|
|
447
470
|
const orgFromManifest = userInfo.organizations?.find((org) => org.name === manifest.organization || org.id === manifest.organization);
|
|
@@ -454,9 +477,12 @@ async function handlePublish(options) {
|
|
|
454
477
|
`Your role: ${orgFromManifest.role}. Required: owner, admin, or maintainer`);
|
|
455
478
|
}
|
|
456
479
|
selectedOrgId = orgFromManifest.id;
|
|
480
|
+
selectedOrgName = orgFromManifest.name;
|
|
457
481
|
}
|
|
482
|
+
// Predict what the scoped package name will be
|
|
483
|
+
const scopedPackageName = predictScopedPackageName(manifest.name, userInfo?.username || config.username || 'unknown', selectedOrgName || manifest.organization);
|
|
458
484
|
console.log(` Source: ${source}`);
|
|
459
|
-
console.log(` Package: ${
|
|
485
|
+
console.log(` Package: ${scopedPackageName}@${manifest.version}`);
|
|
460
486
|
console.log(` Format: ${manifest.format} | Subtype: ${manifest.subtype}`);
|
|
461
487
|
console.log(` Description: ${manifest.description}`);
|
|
462
488
|
console.log(` Access: ${manifest.private ? 'private' : 'public'}`);
|
|
@@ -480,7 +506,7 @@ async function handlePublish(options) {
|
|
|
480
506
|
manifest.license_url = licenseInfo.url || undefined;
|
|
481
507
|
}
|
|
482
508
|
// Validate and warn about license (optional - will extract if present)
|
|
483
|
-
(0, license_extractor_1.validateLicenseInfo)(licenseInfo,
|
|
509
|
+
(0, license_extractor_1.validateLicenseInfo)(licenseInfo, scopedPackageName);
|
|
484
510
|
console.log('');
|
|
485
511
|
// Extract content snippet
|
|
486
512
|
console.log('š Extracting content snippet...');
|
|
@@ -488,7 +514,7 @@ async function handlePublish(options) {
|
|
|
488
514
|
if (snippet) {
|
|
489
515
|
manifest.snippet = snippet;
|
|
490
516
|
}
|
|
491
|
-
(0, snippet_extractor_1.validateSnippet)(snippet,
|
|
517
|
+
(0, snippet_extractor_1.validateSnippet)(snippet, scopedPackageName);
|
|
492
518
|
console.log('');
|
|
493
519
|
// Create tarball
|
|
494
520
|
console.log('š¦ Creating package tarball...');
|
|
@@ -509,7 +535,7 @@ async function handlePublish(options) {
|
|
|
509
535
|
if (options.dryRun) {
|
|
510
536
|
console.log('ā
Dry run successful! Package is ready to publish.');
|
|
511
537
|
publishedPackages.push({
|
|
512
|
-
name:
|
|
538
|
+
name: scopedPackageName,
|
|
513
539
|
version: manifest.version,
|
|
514
540
|
url: ''
|
|
515
541
|
});
|
|
@@ -537,7 +563,8 @@ async function handlePublish(options) {
|
|
|
537
563
|
// Default to registry URL for unknown environments
|
|
538
564
|
webappUrl = registryUrl;
|
|
539
565
|
}
|
|
540
|
-
|
|
566
|
+
// Use the name returned from the API (which includes auto-prefixed scope)
|
|
567
|
+
const packageUrl = `${webappUrl}/packages/${encodeURIComponent(result.name)}`;
|
|
541
568
|
console.log('');
|
|
542
569
|
console.log('ā
Package published successfully!');
|
|
543
570
|
console.log('');
|
|
@@ -545,16 +572,20 @@ async function handlePublish(options) {
|
|
|
545
572
|
console.log(` Install: prpm install ${result.name}`);
|
|
546
573
|
console.log('');
|
|
547
574
|
publishedPackages.push({
|
|
548
|
-
name:
|
|
575
|
+
name: result.name, // Use scoped name from server
|
|
549
576
|
version: result.version,
|
|
550
577
|
url: packageUrl
|
|
551
578
|
});
|
|
552
579
|
}
|
|
553
580
|
catch (err) {
|
|
554
581
|
const pkgError = err instanceof Error ? err.message : String(err);
|
|
555
|
-
|
|
582
|
+
// Try to use scoped name if we have user info, otherwise fall back to manifest name
|
|
583
|
+
const displayName = userInfo
|
|
584
|
+
? predictScopedPackageName(manifest.name, userInfo.username, manifest.organization)
|
|
585
|
+
: manifest.name;
|
|
586
|
+
console.error(`\nā Failed to publish ${displayName}: ${pkgError}\n`);
|
|
556
587
|
failedPackages.push({
|
|
557
|
-
name:
|
|
588
|
+
name: displayName,
|
|
558
589
|
error: pkgError
|
|
559
590
|
});
|
|
560
591
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prpm",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Prompt Package Manager CLI - Install and manage prompt-based files",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"license": "MIT",
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@octokit/rest": "^22.0.0",
|
|
48
|
-
"@pr-pm/registry-client": "^1.3.
|
|
49
|
-
"@pr-pm/types": "^0.2.
|
|
48
|
+
"@pr-pm/registry-client": "^1.3.8",
|
|
49
|
+
"@pr-pm/types": "^0.2.9",
|
|
50
50
|
"ajv": "^8.17.1",
|
|
51
51
|
"ajv-formats": "^3.0.1",
|
|
52
52
|
"commander": "^11.1.0",
|