prpm 2.1.13 → 2.1.15

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.
Files changed (2) hide show
  1. package/dist/index.js +207 -23
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -7290,6 +7290,15 @@ function fromOpencode(content, metadata) {
7290
7290
  disable: fm.disable
7291
7291
  };
7292
7292
  }
7293
+ if (fm.template) {
7294
+ metadataSection.data.opencodeSlashCommand = {
7295
+ template: fm.template,
7296
+ description: fm.description,
7297
+ agent: fm.agent,
7298
+ model: fm.model,
7299
+ subtask: fm.subtask
7300
+ };
7301
+ }
7293
7302
  sections.push(metadataSection);
7294
7303
  if (fm.tools) {
7295
7304
  const enabledTools = Object.entries(fm.tools).filter(([_, enabled]) => enabled === true).map(([tool, _]) => {
@@ -7303,7 +7312,11 @@ function fromOpencode(content, metadata) {
7303
7312
  "webfetch": "WebFetch",
7304
7313
  "websearch": "WebSearch"
7305
7314
  };
7306
- return toolMap[tool.toLowerCase()] || tool;
7315
+ const normalized = toolMap[tool.toLowerCase()];
7316
+ if (normalized) {
7317
+ return normalized;
7318
+ }
7319
+ return tool.charAt(0).toUpperCase() + tool.slice(1).toLowerCase();
7307
7320
  });
7308
7321
  if (enabledTools.length > 0) {
7309
7322
  const toolsSection = {
@@ -7325,6 +7338,9 @@ function fromOpencode(content, metadata) {
7325
7338
  version: "1.0",
7326
7339
  sections
7327
7340
  };
7341
+ const templateValue = fm.template;
7342
+ const isSlashCommand = typeof templateValue === "string" && templateValue.trim().length > 0;
7343
+ const detectedSubtype = isSlashCommand ? "slash-command" : "agent";
7328
7344
  const pkg = {
7329
7345
  ...metadata,
7330
7346
  id: metadata.id,
@@ -7334,11 +7350,10 @@ function fromOpencode(content, metadata) {
7334
7350
  description: metadata.description || fm.description || "",
7335
7351
  tags: metadata.tags || [],
7336
7352
  format: "opencode",
7337
- subtype: "agent",
7338
- // OpenCode only supports agents
7353
+ subtype: detectedSubtype,
7339
7354
  content: canonicalContent
7340
7355
  };
7341
- setTaxonomy(pkg, "opencode", "agent");
7356
+ setTaxonomy(pkg, "opencode", detectedSubtype);
7342
7357
  return pkg;
7343
7358
  }
7344
7359
  var init_from_opencode = __esm({
@@ -8883,8 +8898,14 @@ function parseMarkdownWithFrontmatter(markdown) {
8883
8898
  return { frontmatter, content };
8884
8899
  }
8885
8900
  function validateMarkdown(format, markdown, subtype) {
8901
+ var _a;
8886
8902
  const { frontmatter, content } = parseMarkdownWithFrontmatter(markdown);
8887
- if (format === "windsurf" || format === "agents.md" || format === "ruler") {
8903
+ const noFrontmatterFormats = ["windsurf", "agents.md", "ruler"];
8904
+ const noFrontmatterSubtypes = {
8905
+ cursor: ["slash-command"]
8906
+ };
8907
+ const isNoFrontmatter = noFrontmatterFormats.includes(format) || subtype && ((_a = noFrontmatterSubtypes[format]) == null ? void 0 : _a.includes(subtype));
8908
+ if (isNoFrontmatter) {
8888
8909
  return validateFormat(format, { content: markdown }, subtype);
8889
8910
  }
8890
8911
  return validateConversion(format, frontmatter, content, subtype);
@@ -21074,7 +21095,7 @@ async function validatePackageFiles(manifest) {
21074
21095
  return false;
21075
21096
  }
21076
21097
  if (formatType === "cursor") {
21077
- return filePath.includes(".cursorrules") || filePath.endsWith(".mdc");
21098
+ return filePath.includes(".cursorrules") || filePath.endsWith(".mdc") || filePath.endsWith(".md");
21078
21099
  } else if (formatType === "claude") {
21079
21100
  if (manifest.subtype === "skill") {
21080
21101
  return filePath.endsWith("SKILL.md");
@@ -21085,16 +21106,13 @@ async function validatePackageFiles(manifest) {
21085
21106
  if (filePath.endsWith(".json")) {
21086
21107
  return false;
21087
21108
  }
21088
- if (manifest.subtype === "agent") {
21089
- return filePath.includes(".claude/agents/") && filePath.endsWith(".md");
21090
- } else if (manifest.subtype === "slash-command") {
21091
- return filePath.includes(".claude/commands/") && filePath.endsWith(".md");
21092
- }
21093
- return filePath.endsWith(".md") && !filePath.endsWith(".json");
21109
+ return filePath.endsWith(".md");
21094
21110
  } else if (formatType === "continue") {
21095
- return filePath.includes(".continue/") && filePath.endsWith(".json");
21111
+ return filePath.endsWith(".md") || filePath.endsWith(".json");
21096
21112
  } else if (formatType === "windsurf") {
21097
- return filePath.includes(".windsurf/rules");
21113
+ return filePath.endsWith(".md");
21114
+ } else if (formatType === "copilot") {
21115
+ return filePath.endsWith(".md");
21098
21116
  } else if (formatType === "agents.md") {
21099
21117
  return filePath === "agents.md";
21100
21118
  } else if (formatType === "kiro") {
@@ -21136,8 +21154,20 @@ async function validatePackageFiles(manifest) {
21136
21154
  }
21137
21155
  if (manifest.format === "claude" && manifest.subtype === "skill") {
21138
21156
  const hasSkillMd = filePaths.some((path10) => path10.endsWith("/SKILL.md") || path10 === "SKILL.md");
21139
- if (!hasSkillMd) {
21140
- errors.push("Claude skills must contain a SKILL.md file");
21157
+ const mdFiles = filePaths.filter((path10) => {
21158
+ var _a;
21159
+ if (!path10.endsWith(".md")) return false;
21160
+ const filename = ((_a = path10.split(/[\\/]/).pop()) == null ? void 0 : _a.toLowerCase()) || "";
21161
+ if (filename === "readme.md") return false;
21162
+ if (path10.includes("examples/") || path10.includes("example/") || path10.includes("tests/") || path10.includes("__tests__/") || path10.includes("docs/") || path10.includes("doc/")) return false;
21163
+ return true;
21164
+ });
21165
+ if (!hasSkillMd && mdFiles.length === 0) {
21166
+ errors.push("Claude skills must contain a markdown file (.md)");
21167
+ } else if (!hasSkillMd && mdFiles.length === 1) {
21168
+ warnings.push("Skill file will be auto-renamed to SKILL.md during publish");
21169
+ } else if (!hasSkillMd && mdFiles.length > 1) {
21170
+ errors.push(`Claude skills with multiple .md files must use SKILL.md for the main skill file (found ${mdFiles.length} .md files)`);
21141
21171
  }
21142
21172
  }
21143
21173
  if (manifest.format === "windsurf") {
@@ -21527,12 +21557,29 @@ function validateManifest(manifest, contextLabel) {
21527
21557
  const hasSkillMd = filePaths.some(
21528
21558
  (path10) => path10.endsWith("/SKILL.md") || path10 === "SKILL.md"
21529
21559
  );
21530
- if (!hasSkillMd) {
21560
+ const mdFiles = filePaths.filter((filePath) => {
21561
+ var _a2;
21562
+ if (!filePath.endsWith(".md")) return false;
21563
+ const filename = ((_a2 = filePath.split(/[\\/]/).pop()) == null ? void 0 : _a2.toLowerCase()) || "";
21564
+ return filename !== "readme.md";
21565
+ });
21566
+ if (!hasSkillMd && mdFiles.length === 0) {
21567
+ throw new Error(
21568
+ `${prefix}Claude skills must contain a markdown file.
21569
+ No .md file found in the files array.
21570
+ Please add your skill file to the prpm.json files array.`
21571
+ );
21572
+ }
21573
+ if (!hasSkillMd && mdFiles.length === 1) {
21574
+ console.log(
21575
+ `${prefix}\u26A0\uFE0F Skill file will be auto-renamed to SKILL.md during publish`
21576
+ );
21577
+ }
21578
+ if (!hasSkillMd && mdFiles.length > 1) {
21531
21579
  throw new Error(
21532
- `${prefix}Claude skills must contain a SKILL.md file.
21533
- According to Claude documentation at https://docs.claude.com/en/docs/claude-code/skills,
21534
- skills must have a file named SKILL.md in their directory.
21535
- Please rename your skill file to SKILL.md (all caps) and update your prpm.json files array.`
21580
+ `${prefix}Claude skills with multiple .md files must use SKILL.md for the main skill file.
21581
+ Found ${mdFiles.length} .md files but no SKILL.md.
21582
+ Please rename your main skill file to SKILL.md so we know which file is the skill.`
21536
21583
  );
21537
21584
  }
21538
21585
  if (manifest.name.length > 64) {
@@ -21622,11 +21669,98 @@ var import_path18 = require("path");
21622
21669
  var tar2 = __toESM(require("tar"));
21623
21670
  var import_os5 = require("os");
21624
21671
  var import_crypto2 = require("crypto");
21672
+ var RELOCATION_CONFIG = {
21673
+ claude: {
21674
+ "slash-command": {
21675
+ directory: ".claude/commands",
21676
+ checkPath: ".claude/commands/"
21677
+ },
21678
+ agent: {
21679
+ directory: ".claude/agents",
21680
+ checkPath: ".claude/agents/"
21681
+ }
21682
+ },
21683
+ cursor: {
21684
+ rule: {
21685
+ directory: ".cursor/rules",
21686
+ extension: ".mdc",
21687
+ checkPath: ".cursor/rules/"
21688
+ },
21689
+ agent: {
21690
+ directory: ".cursor/agents",
21691
+ checkPath: ".cursor/agents/"
21692
+ },
21693
+ "slash-command": {
21694
+ directory: ".cursor/commands",
21695
+ checkPath: ".cursor/commands/"
21696
+ }
21697
+ },
21698
+ continue: {
21699
+ rule: {
21700
+ directory: ".continue/rules",
21701
+ checkPath: ".continue/rules/"
21702
+ },
21703
+ prompt: {
21704
+ directory: ".continue/prompts",
21705
+ checkPath: ".continue/prompts/"
21706
+ }
21707
+ },
21708
+ windsurf: {
21709
+ rule: {
21710
+ directory: ".windsurf/rules",
21711
+ checkPath: ".windsurf/rules/"
21712
+ }
21713
+ },
21714
+ copilot: {
21715
+ rule: {
21716
+ directory: ".github/instructions",
21717
+ extension: ".instructions.md",
21718
+ checkPath: ".github/instructions/"
21719
+ },
21720
+ chatmode: {
21721
+ directory: ".github/chatmodes",
21722
+ extension: ".chatmode.md",
21723
+ checkPath: ".github/chatmodes/"
21724
+ }
21725
+ },
21726
+ kiro: {
21727
+ rule: {
21728
+ directory: ".kiro/steering",
21729
+ checkPath: ".kiro/steering/"
21730
+ },
21731
+ agent: {
21732
+ directory: ".kiro/agents",
21733
+ checkPath: ".kiro/agents/"
21734
+ }
21735
+ },
21736
+ opencode: {
21737
+ agent: {
21738
+ directory: ".opencode/agent",
21739
+ checkPath: ".opencode/agent/"
21740
+ },
21741
+ "slash-command": {
21742
+ directory: ".opencode/command",
21743
+ checkPath: ".opencode/command/"
21744
+ },
21745
+ tool: {
21746
+ directory: ".opencode/tool",
21747
+ checkPath: ".opencode/tool/"
21748
+ }
21749
+ },
21750
+ factory: {
21751
+ "slash-command": {
21752
+ directory: ".factory/commands",
21753
+ checkPath: ".factory/commands/"
21754
+ }
21755
+ }
21756
+ };
21625
21757
  async function createTarball(manifest) {
21626
21758
  const tmpDir = (0, import_path18.join)((0, import_os5.tmpdir)(), `prpm-${(0, import_crypto2.randomBytes)(8).toString("hex")}`);
21627
21759
  const tarballPath = (0, import_path18.join)(tmpDir, "package.tar.gz");
21760
+ const stagingDir = (0, import_path18.join)(tmpDir, "staging");
21628
21761
  try {
21629
21762
  await (0, import_promises7.mkdir)(tmpDir, { recursive: true });
21763
+ await (0, import_promises7.mkdir)(stagingDir, { recursive: true });
21630
21764
  const filePaths = normalizeFilePaths2(manifest.files);
21631
21765
  const standardFiles = ["prpm.json", "README.md", "LICENSE"];
21632
21766
  for (const file of standardFiles) {
@@ -21635,10 +21769,60 @@ async function createTarball(manifest) {
21635
21769
  }
21636
21770
  }
21637
21771
  const existingFiles = [];
21772
+ const fileRenames = /* @__PURE__ */ new Map();
21773
+ if (manifest.format === "claude" && manifest.subtype === "skill") {
21774
+ const hasSkillMd = filePaths.some(
21775
+ (path10) => path10.endsWith("/SKILL.md") || path10 === "SKILL.md"
21776
+ );
21777
+ if (!hasSkillMd) {
21778
+ const mdFiles = filePaths.filter(
21779
+ (path10) => path10.endsWith(".md") && !path10.toLowerCase().includes("readme")
21780
+ );
21781
+ if (mdFiles.length === 1) {
21782
+ const file = mdFiles[0];
21783
+ try {
21784
+ await (0, import_promises7.stat)(file);
21785
+ const dir = (0, import_path18.dirname)(file);
21786
+ const newPath = dir === "." ? "SKILL.md" : (0, import_path18.join)(dir, "SKILL.md");
21787
+ fileRenames.set(file, newPath);
21788
+ console.log(` \u{1F4DD} Renaming ${file} \u2192 ${newPath}`);
21789
+ } catch {
21790
+ }
21791
+ }
21792
+ }
21793
+ }
21794
+ const formatConfig = RELOCATION_CONFIG[manifest.format];
21795
+ const subtypeConfig = formatConfig == null ? void 0 : formatConfig[manifest.subtype || "rule"];
21796
+ if (subtypeConfig) {
21797
+ const contentFiles = filePaths.filter(
21798
+ (path10) => !path10.toLowerCase().includes("readme") && !path10.toLowerCase().includes("license") && path10 !== "prpm.json" && (path10.endsWith(".md") || path10.endsWith(".mdc") || path10.endsWith(".json"))
21799
+ );
21800
+ for (const file of contentFiles) {
21801
+ if (file.includes(subtypeConfig.checkPath)) {
21802
+ continue;
21803
+ }
21804
+ try {
21805
+ await (0, import_promises7.stat)(file);
21806
+ let fileName = (0, import_path18.basename)(file);
21807
+ if (subtypeConfig.extension) {
21808
+ const nameWithoutExt = fileName.replace(/\.[^.]+$/, "");
21809
+ fileName = nameWithoutExt + subtypeConfig.extension;
21810
+ }
21811
+ const newPath = (0, import_path18.join)(subtypeConfig.directory, fileName);
21812
+ fileRenames.set(file, newPath);
21813
+ console.log(` \u{1F4DD} Relocating ${file} \u2192 ${newPath}`);
21814
+ } catch {
21815
+ }
21816
+ }
21817
+ }
21638
21818
  for (const file of filePaths) {
21639
21819
  try {
21640
21820
  await (0, import_promises7.stat)(file);
21641
- existingFiles.push(file);
21821
+ const targetPath = fileRenames.get(file) || file;
21822
+ const stagingPath = (0, import_path18.join)(stagingDir, targetPath);
21823
+ await (0, import_promises7.mkdir)((0, import_path18.dirname)(stagingPath), { recursive: true });
21824
+ await (0, import_promises7.copyFile)(file, stagingPath);
21825
+ existingFiles.push(targetPath);
21642
21826
  } catch {
21643
21827
  }
21644
21828
  }
@@ -21649,7 +21833,7 @@ async function createTarball(manifest) {
21649
21833
  {
21650
21834
  gzip: true,
21651
21835
  file: tarballPath,
21652
- cwd: process.cwd()
21836
+ cwd: stagingDir
21653
21837
  },
21654
21838
  existingFiles
21655
21839
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prpm",
3
- "version": "2.1.13",
3
+ "version": "2.1.15",
4
4
  "description": "Prompt Package Manager CLI - Install and manage prompt-based files",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -45,9 +45,9 @@
45
45
  "license": "MIT",
46
46
  "dependencies": {
47
47
  "@octokit/rest": "^22.0.0",
48
- "@pr-pm/converters": "^2.1.14",
49
- "@pr-pm/registry-client": "^2.3.13",
50
- "@pr-pm/types": "^2.1.14",
48
+ "@pr-pm/converters": "^2.1.16",
49
+ "@pr-pm/registry-client": "^2.3.15",
50
+ "@pr-pm/types": "^2.1.16",
51
51
  "ajv": "^8.17.1",
52
52
  "ajv-formats": "^3.0.1",
53
53
  "commander": "^11.1.0",