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/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 schemaPath = (0, import_path7.join)(currentDirname, "..", "schemas", schemaFilename);
4637
- const schemaContent = (0, import_fs8.readFileSync)(schemaPath, "utf-8");
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", "collection", "chatmode", "tool", "hook"];
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
- return validateManifest(packageWithDefaults);
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(`Manifest validation failed:
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('\u26A0\uFE0F Package contains multiple file formats. Consider setting subtype to "collection" for clarity.');
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
- "Claude skills must contain a SKILL.md file.\nAccording to Claude documentation at https://docs.claude.com/en/docs/claude-code/skills,\nskills must have a file named SKILL.md in their directory.\nPlease rename your skill file to SKILL.md (all caps) and update your prpm.json files array."
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
- `Claude skill name "${manifest.name}" exceeds 64 character limit (${manifest.name.length} characters).
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
- `Claude skill name "${manifest.name}" contains invalid characters.
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
- `Claude skill description exceeds 1024 character limit (${manifest.description.length} characters).
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
- `\u26A0\uFE0F Warning: Skill description is ${manifest.description.length}/1024 characters (${Math.round(manifest.description.length / 1024 * 100)}% of limit).
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
- `\u26A0\uFE0F Warning: Skill description is only ${manifest.description.length} characters.
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 packageUrl = `${webappUrl}/packages/${encodeURIComponent(result.name)}`;
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
+ }