prpm 1.0.2 → 1.0.4
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 +86 -358
- package/dist/index.js +60 -30
- package/dist/schemas/agents-md.schema.json +23 -0
- package/dist/schemas/canonical.schema.json +435 -0
- package/dist/schemas/claude-agent.schema.json +57 -0
- package/dist/schemas/claude-hook.schema.json +68 -0
- package/dist/schemas/claude-skill.schema.json +51 -0
- package/dist/schemas/claude-slash-command.schema.json +63 -0
- package/dist/schemas/claude.schema.json +51 -0
- package/dist/schemas/continue.schema.json +97 -0
- package/dist/schemas/copilot.schema.json +75 -0
- package/dist/schemas/cursor-command.schema.json +26 -0
- package/dist/schemas/cursor.schema.json +88 -0
- package/dist/schemas/kiro-hooks.schema.json +119 -0
- package/dist/schemas/kiro-steering.schema.json +73 -0
- package/dist/schemas/prpm-manifest.schema.json +6 -2
- package/dist/schemas/windsurf.schema.json +21 -0
- package/package.json +4 -4
- package/schemas/prpm-manifest.schema.json +6 -2
package/dist/index.js
CHANGED
|
@@ -4633,8 +4633,28 @@ function loadSchema(format, subtype) {
|
|
|
4633
4633
|
};
|
|
4634
4634
|
schemaFilename = schemaMap[format] || `${format}.schema.json`;
|
|
4635
4635
|
}
|
|
4636
|
-
const
|
|
4637
|
-
|
|
4636
|
+
const schemaDirectories = [
|
|
4637
|
+
(0, import_path7.join)(currentDirname, "..", "schemas"),
|
|
4638
|
+
(0, import_path7.join)(currentDirname, "schemas")
|
|
4639
|
+
];
|
|
4640
|
+
let schemaContent = null;
|
|
4641
|
+
let schemaPath = null;
|
|
4642
|
+
for (const dir of schemaDirectories) {
|
|
4643
|
+
const candidate = (0, import_path7.join)(dir, schemaFilename);
|
|
4644
|
+
try {
|
|
4645
|
+
schemaContent = (0, import_fs8.readFileSync)(candidate, "utf-8");
|
|
4646
|
+
schemaPath = candidate;
|
|
4647
|
+
break;
|
|
4648
|
+
} catch (error) {
|
|
4649
|
+
if ((error == null ? void 0 : error.code) !== "ENOENT") {
|
|
4650
|
+
throw error;
|
|
4651
|
+
}
|
|
4652
|
+
continue;
|
|
4653
|
+
}
|
|
4654
|
+
}
|
|
4655
|
+
if (!schemaContent || !schemaPath) {
|
|
4656
|
+
throw new Error(`Schema file "${schemaFilename}" not found. Looked in: ${schemaDirectories.join(", ")}`);
|
|
4657
|
+
}
|
|
4638
4658
|
const schema3 = JSON.parse(schemaContent);
|
|
4639
4659
|
const compiled = ajv.compile(schema3);
|
|
4640
4660
|
schemaCache.set(cacheKey, compiled);
|
|
@@ -6655,7 +6675,9 @@ function getPackageIcon2(format, subtype) {
|
|
|
6655
6675
|
"collection": "\u{1F4E6}",
|
|
6656
6676
|
"chatmode": "\u{1F4AC}",
|
|
6657
6677
|
"tool": "\u{1F527}",
|
|
6658
|
-
"hook": "\u{1FA9D}"
|
|
6678
|
+
"hook": "\u{1FA9D}",
|
|
6679
|
+
"workflow": "\u{1F504}",
|
|
6680
|
+
"template": "\u{1F4C4}"
|
|
6659
6681
|
};
|
|
6660
6682
|
const formatIcons = {
|
|
6661
6683
|
"claude": "\u{1F916}",
|
|
@@ -6691,7 +6713,9 @@ function getPackageLabel2(format, subtype) {
|
|
|
6691
6713
|
"collection": "Collection",
|
|
6692
6714
|
"chatmode": "Chat Mode",
|
|
6693
6715
|
"tool": "Tool",
|
|
6694
|
-
"hook": "Hook"
|
|
6716
|
+
"hook": "Hook",
|
|
6717
|
+
"workflow": "Workflow",
|
|
6718
|
+
"template": "Template"
|
|
6695
6719
|
};
|
|
6696
6720
|
const formatLabel = formatLabels[format];
|
|
6697
6721
|
const subtypeLabel = subtypeLabels[subtype];
|
|
@@ -9520,12 +9544,12 @@ async function handleTrending(options) {
|
|
|
9520
9544
|
}
|
|
9521
9545
|
function createTrendingCommand() {
|
|
9522
9546
|
const command = new import_commander5.Command("trending");
|
|
9523
|
-
command.description("Show trending packages").option("--format <format>", "Filter by format (cursor, claude, continue, windsurf, copilot, kiro, agents.md, generic)").option("--subtype <subtype>", "Filter by subtype (rule, agent, skill, slash-command, prompt, workflow, tool, template, collection)").option("--limit <number>", "Number of packages to show", "10").action(async (options) => {
|
|
9547
|
+
command.description("Show trending packages").option("--format <format>", "Filter by format (cursor, claude, continue, windsurf, copilot, kiro, agents.md, generic)").option("--subtype <subtype>", "Filter by subtype (rule, agent, skill, slash-command, prompt, workflow, tool, template, collection, chatmode, hook)").option("--limit <number>", "Number of packages to show", "10").action(async (options) => {
|
|
9524
9548
|
const format = options.format;
|
|
9525
9549
|
const subtype = options.subtype;
|
|
9526
9550
|
const limit = options.limit ? parseInt(options.limit, 10) : 10;
|
|
9527
9551
|
const validFormats = ["cursor", "claude", "continue", "windsurf", "copilot", "kiro", "agents.md", "generic", "mcp"];
|
|
9528
|
-
const validSubtypes = ["rule", "agent", "skill", "slash-command", "prompt", "workflow", "tool", "template", "collection"];
|
|
9552
|
+
const validSubtypes = ["rule", "agent", "skill", "slash-command", "prompt", "workflow", "tool", "template", "collection", "chatmode", "hook"];
|
|
9529
9553
|
if (options.format && !validFormats.includes(format)) {
|
|
9530
9554
|
console.error(`\u274C Format must be one of: ${validFormats.join(", ")}`);
|
|
9531
9555
|
throw new CLIError(`\u274C Format must be one of: ${validFormats.join(", ")}`, 1);
|
|
@@ -9548,7 +9572,7 @@ async function handlePopular(options) {
|
|
|
9548
9572
|
});
|
|
9549
9573
|
}
|
|
9550
9574
|
function createPopularCommand() {
|
|
9551
|
-
return new import_commander6.Command("popular").description("Show popular packages (all time)").option("--format <format>", "Filter by format (cursor, claude, continue, windsurf, copilot, kiro, agents.md, generic)").option("--subtype <subtype>", "Filter by subtype (rule, agent, skill, slash-command, prompt, workflow, tool, template, collection)").action(async (options) => {
|
|
9575
|
+
return new import_commander6.Command("popular").description("Show popular packages (all time)").option("--format <format>", "Filter by format (cursor, claude, continue, windsurf, copilot, kiro, agents.md, generic)").option("--subtype <subtype>", "Filter by subtype (rule, agent, skill, slash-command, prompt, workflow, tool, template, collection, chatmode, hook)").action(async (options) => {
|
|
9552
9576
|
await handlePopular(options);
|
|
9553
9577
|
});
|
|
9554
9578
|
}
|
|
@@ -9571,7 +9595,9 @@ function getPackageIcon(format, subtype) {
|
|
|
9571
9595
|
"collection": "\u{1F4E6}",
|
|
9572
9596
|
"chatmode": "\u{1F4AC}",
|
|
9573
9597
|
"tool": "\u{1F527}",
|
|
9574
|
-
"hook": "\u{1FA9D}"
|
|
9598
|
+
"hook": "\u{1FA9D}",
|
|
9599
|
+
"workflow": "\u{1F504}",
|
|
9600
|
+
"template": "\u{1F4C4}"
|
|
9575
9601
|
};
|
|
9576
9602
|
const formatIcons = {
|
|
9577
9603
|
"claude": "\u{1F916}",
|
|
@@ -9607,7 +9633,9 @@ function getPackageLabel(format, subtype) {
|
|
|
9607
9633
|
"collection": "Collection",
|
|
9608
9634
|
"chatmode": "Chat Mode",
|
|
9609
9635
|
"tool": "Tool",
|
|
9610
|
-
"hook": "Hook"
|
|
9636
|
+
"hook": "Hook",
|
|
9637
|
+
"workflow": "Workflow",
|
|
9638
|
+
"template": "Template"
|
|
9611
9639
|
};
|
|
9612
9640
|
const formatLabel = formatLabels[format];
|
|
9613
9641
|
const subtypeLabel = subtypeLabels[subtype];
|
|
@@ -9871,7 +9899,7 @@ function createSearchCommand() {
|
|
|
9871
9899
|
const limit = options.limit ? parseInt(options.limit, 10) : 20;
|
|
9872
9900
|
const page = options.page ? parseInt(options.page, 10) : 1;
|
|
9873
9901
|
const validFormats = ["cursor", "claude", "continue", "windsurf", "copilot", "kiro", "agents.md", "generic", "mcp"];
|
|
9874
|
-
const validSubtypes = ["rule", "agent", "skill", "slash-command", "prompt", "
|
|
9902
|
+
const validSubtypes = ["rule", "agent", "skill", "slash-command", "prompt", "workflow", "tool", "template", "collection", "chatmode", "hook"];
|
|
9875
9903
|
if (options.format && !validFormats.includes(format)) {
|
|
9876
9904
|
console.error(`\u274C Format must be one of: ${validFormats.join(", ")}`);
|
|
9877
9905
|
throw new CLIError(`\u274C Format must be one of: ${validFormats.join(", ")}`, 1);
|
|
@@ -10520,12 +10548,6 @@ async function validatePackageFiles(manifest) {
|
|
|
10520
10548
|
errors.push("Claude skills must contain a SKILL.md file");
|
|
10521
10549
|
}
|
|
10522
10550
|
}
|
|
10523
|
-
if (manifest.format === "cursor") {
|
|
10524
|
-
const hasCursorRules = filePaths.some((path7) => path7.includes(".cursorrules"));
|
|
10525
|
-
if (!hasCursorRules) {
|
|
10526
|
-
warnings.push("Cursor packages typically use .cursorrules filename");
|
|
10527
|
-
}
|
|
10528
|
-
}
|
|
10529
10551
|
if (manifest.format === "windsurf") {
|
|
10530
10552
|
const hasWindsurfRules = filePaths.some((path7) => path7.includes(".windsurf/rules"));
|
|
10531
10553
|
if (!hasWindsurfRules) {
|
|
@@ -10573,14 +10595,15 @@ async function findAndLoadManifests() {
|
|
|
10573
10595
|
engines: pkg.engines,
|
|
10574
10596
|
main: pkg.main
|
|
10575
10597
|
};
|
|
10576
|
-
|
|
10598
|
+
const label = pkg.name || `package #${idx + 1}`;
|
|
10599
|
+
return validateManifest(packageWithDefaults, label);
|
|
10577
10600
|
});
|
|
10578
10601
|
return { manifests: validatedManifests, collections, source: "prpm.json (multi-package)" };
|
|
10579
10602
|
}
|
|
10580
10603
|
if (collections.length > 0) {
|
|
10581
10604
|
return { manifests: [], collections, source: "prpm.json (collections-only)" };
|
|
10582
10605
|
}
|
|
10583
|
-
const validated = validateManifest(manifest);
|
|
10606
|
+
const validated = validateManifest(manifest, manifest.name);
|
|
10584
10607
|
return { manifests: [validated], collections, source: "prpm.json" };
|
|
10585
10608
|
} catch (error) {
|
|
10586
10609
|
prpmJsonError = error;
|
|
@@ -10598,7 +10621,7 @@ async function findAndLoadManifests() {
|
|
|
10598
10621
|
const manifests = [];
|
|
10599
10622
|
for (let i = 0; i < marketplaceData.plugins.length; i++) {
|
|
10600
10623
|
const manifest = marketplaceToManifest(marketplaceData, i);
|
|
10601
|
-
const validated = validateManifest(manifest);
|
|
10624
|
+
const validated = validateManifest(manifest, manifest.name);
|
|
10602
10625
|
manifests.push(validated);
|
|
10603
10626
|
}
|
|
10604
10627
|
return { manifests, collections: [], source: ".claude/marketplace.json" };
|
|
@@ -10614,7 +10637,7 @@ async function findAndLoadManifests() {
|
|
|
10614
10637
|
const manifests = [];
|
|
10615
10638
|
for (let i = 0; i < marketplaceData.plugins.length; i++) {
|
|
10616
10639
|
const manifest = marketplaceToManifest(marketplaceData, i);
|
|
10617
|
-
const validated = validateManifest(manifest);
|
|
10640
|
+
const validated = validateManifest(manifest, manifest.name);
|
|
10618
10641
|
manifests.push(validated);
|
|
10619
10642
|
}
|
|
10620
10643
|
return { manifests, collections: [], source: ".claude-plugin/marketplace.json" };
|
|
@@ -10624,15 +10647,17 @@ async function findAndLoadManifests() {
|
|
|
10624
10647
|
"No manifest file found. Expected either:\n - prpm.json in the current directory, or\n - .claude/marketplace.json (Claude format), or\n - .claude-plugin/marketplace.json (Claude format)"
|
|
10625
10648
|
);
|
|
10626
10649
|
}
|
|
10627
|
-
function validateManifest(manifest) {
|
|
10650
|
+
function validateManifest(manifest, contextLabel) {
|
|
10628
10651
|
var _a;
|
|
10652
|
+
const context = contextLabel || manifest.name || "manifest";
|
|
10653
|
+
const prefix = `[${context}] `;
|
|
10629
10654
|
if (!manifest.subtype) {
|
|
10630
10655
|
manifest.subtype = "rule";
|
|
10631
10656
|
}
|
|
10632
10657
|
const schemaValidation = validateManifestSchema(manifest);
|
|
10633
10658
|
if (!schemaValidation.valid) {
|
|
10634
10659
|
const errorMessages = ((_a = schemaValidation.errors) == null ? void 0 : _a.join("\n - ")) || "Unknown validation error";
|
|
10635
|
-
throw new Error(
|
|
10660
|
+
throw new Error(`${prefix}Manifest validation failed:
|
|
10636
10661
|
- ${errorMessages}`);
|
|
10637
10662
|
}
|
|
10638
10663
|
const hasEnhancedFormat = manifest.files.some((f) => typeof f === "object");
|
|
@@ -10641,7 +10666,7 @@ function validateManifest(manifest) {
|
|
|
10641
10666
|
manifest.files.filter((f) => typeof f === "object").map((f) => f.format)
|
|
10642
10667
|
);
|
|
10643
10668
|
if (fileFormats.size > 1 && manifest.subtype !== "collection") {
|
|
10644
|
-
console.warn(
|
|
10669
|
+
console.warn(`${prefix}\u26A0\uFE0F Package contains multiple file formats. Consider setting subtype to "collection" for clarity.`);
|
|
10645
10670
|
}
|
|
10646
10671
|
}
|
|
10647
10672
|
if (manifest.format === "claude" && manifest.subtype === "skill") {
|
|
@@ -10649,39 +10674,42 @@ function validateManifest(manifest) {
|
|
|
10649
10674
|
const hasSkillMd = filePaths.some((path7) => path7.endsWith("/SKILL.md") || path7 === "SKILL.md");
|
|
10650
10675
|
if (!hasSkillMd) {
|
|
10651
10676
|
throw new Error(
|
|
10652
|
-
|
|
10677
|
+
`${prefix}Claude skills must contain a SKILL.md file.
|
|
10678
|
+
According to Claude documentation at https://docs.claude.com/en/docs/claude-code/skills,
|
|
10679
|
+
skills must have a file named SKILL.md in their directory.
|
|
10680
|
+
Please rename your skill file to SKILL.md (all caps) and update your prpm.json files array.`
|
|
10653
10681
|
);
|
|
10654
10682
|
}
|
|
10655
10683
|
if (manifest.name.length > 64) {
|
|
10656
10684
|
throw new Error(
|
|
10657
|
-
|
|
10685
|
+
`${prefix}Claude skill name "${manifest.name}" exceeds 64 character limit (${manifest.name.length} characters).
|
|
10658
10686
|
According to Claude documentation, skill names must be max 64 characters.
|
|
10659
10687
|
Please shorten your package name.`
|
|
10660
10688
|
);
|
|
10661
10689
|
}
|
|
10662
10690
|
if (!/^[a-z0-9-]+$/.test(manifest.name)) {
|
|
10663
10691
|
throw new Error(
|
|
10664
|
-
|
|
10692
|
+
`${prefix}Claude skill name "${manifest.name}" contains invalid characters.
|
|
10665
10693
|
According to Claude documentation, skill names must use lowercase letters, numbers, and hyphens only.
|
|
10666
10694
|
Please update your package name.`
|
|
10667
10695
|
);
|
|
10668
10696
|
}
|
|
10669
10697
|
if (manifest.description.length > 1024) {
|
|
10670
10698
|
throw new Error(
|
|
10671
|
-
|
|
10699
|
+
`${prefix}Claude skill description exceeds 1024 character limit (${manifest.description.length} characters).
|
|
10672
10700
|
According to Claude documentation, skill descriptions must be max 1024 characters.
|
|
10673
10701
|
Please shorten your description.`
|
|
10674
10702
|
);
|
|
10675
10703
|
}
|
|
10676
10704
|
if (manifest.description.length > 819) {
|
|
10677
10705
|
console.warn(
|
|
10678
|
-
|
|
10706
|
+
`${prefix}\u26A0\uFE0F Warning: Skill description is ${manifest.description.length}/1024 characters (${Math.round(manifest.description.length / 1024 * 100)}% of limit).
|
|
10679
10707
|
Consider keeping it concise for better discoverability.`
|
|
10680
10708
|
);
|
|
10681
10709
|
}
|
|
10682
10710
|
if (manifest.description.length < 100) {
|
|
10683
10711
|
console.warn(
|
|
10684
|
-
|
|
10712
|
+
`${prefix}\u26A0\uFE0F Warning: Skill description is only ${manifest.description.length} characters.
|
|
10685
10713
|
Claude uses descriptions for skill discovery - consider adding more detail about:
|
|
10686
10714
|
- What the skill does
|
|
10687
10715
|
- When Claude should use it
|
|
@@ -10995,7 +11023,9 @@ ${"=".repeat(60)}`);
|
|
|
10995
11023
|
} else {
|
|
10996
11024
|
webappUrl = registryUrl;
|
|
10997
11025
|
}
|
|
10998
|
-
const
|
|
11026
|
+
const packageSlug = result.name.startsWith("@") ? result.name.slice(1) : result.name;
|
|
11027
|
+
const packagePath = packageSlug.split("/").map((segment) => encodeURIComponent(segment)).join("/");
|
|
11028
|
+
const packageUrl = `${webappUrl}/packages/${packagePath}`;
|
|
10999
11029
|
console.log("");
|
|
11000
11030
|
console.log("\u2705 Package published successfully!");
|
|
11001
11031
|
console.log("");
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://prpm.dev/schemas/agents-md.schema.json",
|
|
4
|
+
"title": "agents.md Format",
|
|
5
|
+
"description": "JSON Schema for agents.md format - plain markdown project-specific AI instructions (NO frontmatter)",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["content"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"content": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "Plain markdown content with project-specific instructions, architecture notes, conventions, etc. No frontmatter allowed."
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"additionalProperties": false,
|
|
15
|
+
"examples": [
|
|
16
|
+
{
|
|
17
|
+
"content": "# Backend Guidelines\n\n## Architecture\n\nWe use a clean architecture pattern.\n\n## Database\n\nPostgreSQL with Prisma ORM.\n\n## Coding Standards\n\n- Use TypeScript strict mode\n- Write unit tests for all services"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"content": "# Project Context\n\nThis is a React + TypeScript web application.\n\n## Stack\n\n- React 18\n- TypeScript 5\n- Vite\n- Tailwind CSS"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|