prpm 2.1.35 → 2.1.37

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.
@@ -96,7 +96,7 @@
96
96
  "supportsAgentsMd": true,
97
97
  "supportsSlashCommands": true,
98
98
  "markdownFallback": "opencode-agent.md",
99
- "notes": "OpenCode supports agents, skills, plugins, and slash commands. Skills use Agent Skills spec in .opencode/skill/${name}/SKILL.md. Plugins are JavaScript/TypeScript modules in .opencode/plugin with 40+ event hooks. Full agents.md support."
99
+ "notes": "OpenCode supports agents, skills, plugins, and slash commands. Skills use Agent Skills spec in .opencode/skills/${name}/SKILL.md. Plugins are JavaScript/TypeScript modules in .opencode/plugin with 40+ event hooks. Full agents.md support."
100
100
  },
101
101
  "ruler": {
102
102
  "name": "Ruler",
package/dist/index.js CHANGED
@@ -13708,7 +13708,7 @@ var init_format_registry = __esm({
13708
13708
  fileExtension: ".md"
13709
13709
  },
13710
13710
  skill: {
13711
- directory: ".opencode/skill",
13711
+ directory: ".opencode/skills",
13712
13712
  filePatterns: ["SKILL.md"],
13713
13713
  nested: true,
13714
13714
  nestedIndicator: "SKILL.md",
@@ -18360,6 +18360,7 @@ This could indicate:
18360
18360
  }
18361
18361
  }
18362
18362
  const fileExtension = (registryExtension == null ? void 0 : registryExtension.replace(/^\./, "")) || "md";
18363
+ const nestedIndicator = getNestedIndicator(effectiveFormat, effectiveSubtype);
18363
18364
  const packageName = stripAuthorNamespace2(packageId);
18364
18365
  if (effectiveFormat === "claude" && effectiveSubtype === "skill") {
18365
18366
  destPath = `${destDir}/SKILL.md`;
@@ -18425,6 +18426,8 @@ This could indicate:
18425
18426
  destPath = `${destDir}/SKILL.md`;
18426
18427
  } else if (effectiveFormat === "copilot" && effectiveSubtype === "skill") {
18427
18428
  destPath = `${destDir}/SKILL.md`;
18429
+ } else if (nestedIndicator) {
18430
+ destPath = `${destDir}/${nestedIndicator}`;
18428
18431
  } else {
18429
18432
  const nativeSubtypes2 = import_types.FORMAT_NATIVE_SUBTYPES[effectiveFormat];
18430
18433
  const needsProgressiveDisclosureHere = nativeSubtypes2 && !nativeSubtypes2.includes(effectiveSubtype) && (effectiveSubtype === "skill" || effectiveSubtype === "agent" || effectiveSubtype === "slash-command");
@@ -18544,7 +18547,9 @@ This could indicate:
18544
18547
  console.log(` \u{1F4C1} Installing Cursor package to custom location: ${destDir}`);
18545
18548
  }
18546
18549
  const isCursorConversion = effectiveFormat === "cursor" && pkg.format === "claude" && pkg.subtype === "skill";
18547
- const packageDir = effectiveFormat === "claude" && effectiveSubtype === "skill" ? destDir : isCursorConversion ? destDir : needsProgressiveDisclosureMulti ? destDir : `${destDir}/${packageName}`;
18550
+ const nativeSubtypeConfig = getSubtypeConfig(effectiveFormat, effectiveSubtype);
18551
+ const usesNativePackageSubdirectory = !needsProgressiveDisclosureMulti && Boolean(nativeSubtypeConfig == null ? void 0 : nativeSubtypeConfig.usesPackageSubdirectory);
18552
+ const packageDir = effectiveFormat === "claude" && effectiveSubtype === "skill" ? destDir : isCursorConversion ? destDir : needsProgressiveDisclosureMulti ? destDir : usesNativePackageSubdirectory ? destDir : `${destDir}/${packageName}`;
18548
18553
  destPath = packageDir;
18549
18554
  console.log(` \u{1F4C1} Multi-file package - creating directory: ${packageDir}`);
18550
18555
  if (effectiveFormat === "claude" && effectiveSubtype === "skill") {
@@ -18574,7 +18579,7 @@ This could indicate:
18574
18579
  for (const file of extractedFiles) {
18575
18580
  const pathParts = file.name.split("/");
18576
18581
  let relativeFileName = file.name;
18577
- const skillsDirIndex = pathParts.indexOf("skills");
18582
+ const skillsDirIndex = pathParts.findIndex((part) => part === "skills" || part === "skill");
18578
18583
  if (skillsDirIndex !== -1 && pathParts.length > skillsDirIndex + 2) {
18579
18584
  relativeFileName = pathParts.slice(skillsDirIndex + 2).join("/");
18580
18585
  } else if (pathParts.length > 1) {
@@ -18958,25 +18963,37 @@ async function installFromLockfile(options) {
18958
18963
  }
18959
18964
  function createInstallCommand() {
18960
18965
  const command = new import_commander12.Command("install");
18961
- command.description("Install a package from the registry, or install all packages from prpm.lock if no package specified").argument("[package]", "Package to install (e.g., react-rules or react-rules@1.2.0). If omitted, installs all packages from prpm.lock").option("--version <version>", "Specific version to install").option("--as <format>", `Convert and install in specific format (${import_types.FORMATS.join(", ")})`).option("--format <format>", "Alias for --as").option("--location <path>", "Custom location for installed files (Agents.md or nested Cursor rules)").option("--subtype <subtype>", "Specify subtype when converting (skill, agent, rule, etc.)").option("--hook-mapping <strategy>", "Hook mapping strategy: auto (default), strict, skip", "auto").option("--frozen-lockfile", "Fail if lock file needs to be updated (for CI)").option("-y, --yes", "Auto-confirm prompts (overwrite files without asking)").option("--no-append", "Skip adding skill to manifest file (skill files only)").option("--manifest-file <filename>", "Custom manifest filename for progressive disclosure").option("--eager", "Force skill/agent to always activate (not on-demand)").option("--lazy", "Use default on-demand activation (overrides package eager setting)").option("--tools <tools>", "Override Claude/Codex tool list for this install (comma- or space-separated)").option("--global", "Install MCP servers to global config (e.g., ~/.claude/settings.json, ~/.codex/config.toml, ~/.cursor/mcp.json, ~/.kiro/settings/mcp.json)").option("--editor <editor>", "[Deprecated: use --as] Target editor for MCP server installation").action(async (packageSpec, options) => {
18966
+ command.description("Install a package from the registry, or install all packages from prpm.lock if no package specified").argument("[package]", "Package to install (e.g., react-rules or react-rules@1.2.0). If omitted, installs all packages from prpm.lock").option("--version <version>", "Specific version to install").option("--as <format>", `Convert and install in specific format. Accepts a comma-separated list to install to multiple formats in one command (${import_types.FORMATS.join(", ")})`).option("--format <format>", "Alias for --as").option("--location <path>", "Custom location for installed files (Agents.md or nested Cursor rules)").option("--subtype <subtype>", "Specify subtype when converting (skill, agent, rule, etc.)").option("--hook-mapping <strategy>", "Hook mapping strategy: auto (default), strict, skip", "auto").option("--frozen-lockfile", "Fail if lock file needs to be updated (for CI)").option("-y, --yes", "Auto-confirm prompts (overwrite files without asking)").option("--no-append", "Skip adding skill to manifest file (skill files only)").option("--manifest-file <filename>", "Custom manifest filename for progressive disclosure").option("--eager", "Force skill/agent to always activate (not on-demand)").option("--lazy", "Use default on-demand activation (overrides package eager setting)").option("--tools <tools>", "Override Claude/Codex tool list for this install (comma- or space-separated)").option("--global", "Install MCP servers to global config (e.g., ~/.claude/settings.json, ~/.codex/config.toml, ~/.cursor/mcp.json, ~/.kiro/settings/mcp.json)").option("--editor <editor>", "[Deprecated: use --as] Target editor for MCP server installation").action(async (packageSpec, options) => {
18962
18967
  const rawAs = options.format || options.as;
18963
18968
  const validFormats = import_types.FORMATS;
18964
- const isMCPEditorOnly = rawAs && !validFormats.includes(rawAs) && MCP_EDITORS.includes(rawAs);
18965
- const convertTo = isMCPEditorOnly ? void 0 : rawAs;
18966
- if (convertTo && !validFormats.includes(convertTo)) {
18967
- throw new CLIError(`\u274C Format must be one of: ${validFormats.join(", ")}
18969
+ const asTokens = rawAs ? Array.from(new Set(rawAs.split(",").map((s) => s.trim()).filter(Boolean))) : [];
18970
+ if (rawAs !== void 0 && asTokens.length === 0) {
18971
+ throw new CLIError(
18972
+ `\u274C --as requires at least one format. Got: "${rawAs}"
18973
+
18974
+ \u{1F4A1} Examples:
18975
+ prpm install my-package --as claude
18976
+ prpm install my-package --as claude,codex`,
18977
+ 1
18978
+ );
18979
+ }
18980
+ for (const token of asTokens) {
18981
+ const isFormat = validFormats.includes(token);
18982
+ const isMCPEditor = MCP_EDITORS.includes(token);
18983
+ if (!isFormat && !isMCPEditor) {
18984
+ throw new CLIError(`\u274C Format must be one of: ${validFormats.join(", ")}
18968
18985
 
18969
18986
  \u{1F4A1} Examples:
18970
- prpm install my-package --as cursor # Convert to Cursor format
18971
- prpm install my-package --format claude # Convert to Claude format
18972
- prpm install my-package --format claude.md # Convert to Claude.md format
18973
- prpm install my-package --format kiro # Convert to Kiro format
18974
- prpm install my-package --format agents.md # Convert to Agents.md format
18975
- prpm install my-package --format gemini.md # Convert to Gemini format
18976
- prpm install my-mcp-server --as codex # Install MCP server to Codex
18977
- prpm install my-package # Install in native format`, 1);
18978
- }
18979
- const mcpEditor = options.editor || rawAs;
18987
+ prpm install my-package --as cursor # Convert to Cursor format
18988
+ prpm install my-package --as claude,codex # Install to both Claude and Codex
18989
+ prpm install my-package --format claude.md # Convert to Claude.md format
18990
+ prpm install my-package --format kiro # Convert to Kiro format
18991
+ prpm install my-package --format agents.md # Convert to Agents.md format
18992
+ prpm install my-package --format gemini.md # Convert to Gemini format
18993
+ prpm install my-mcp-server --as codex # Install MCP server to Codex
18994
+ prpm install my-package # Install in native format`, 1);
18995
+ }
18996
+ }
18980
18997
  if (options.editor && !MCP_EDITORS.includes(options.editor)) {
18981
18998
  throw new CLIError(
18982
18999
  `Invalid MCP editor: ${options.editor}
@@ -19008,8 +19025,18 @@ Valid strategies: ${VALID_HOOK_MAPPING_STRATEGIES.join(", ")}`
19008
19025
  if (options.tools) {
19009
19026
  console.warn("\u26A0\uFE0F --tools is ignored when installing from prpm.lock (no package specified)");
19010
19027
  }
19028
+ if (asTokens.length > 1) {
19029
+ throw new CLIError(
19030
+ `\u274C Multi-format --as is not supported when installing from prpm.lock.
19031
+
19032
+ The lockfile already records the target format for each package. Run prpm install <package> --as ${asTokens.join(",")} for specific packages instead.`,
19033
+ 1
19034
+ );
19035
+ }
19036
+ const [singleAs] = asTokens;
19037
+ const isMCPEditorOnly = singleAs && !validFormats.includes(singleAs) && MCP_EDITORS.includes(singleAs);
19011
19038
  await installFromLockfile({
19012
- as: convertTo,
19039
+ as: isMCPEditorOnly ? void 0 : singleAs,
19013
19040
  subtype: options.subtype,
19014
19041
  frozenLockfile: options.frozenLockfile,
19015
19042
  location: options.location,
@@ -19018,21 +19045,73 @@ Valid strategies: ${VALID_HOOK_MAPPING_STRATEGIES.join(", ")}`
19018
19045
  return;
19019
19046
  }
19020
19047
  const eager = options.eager ? true : options.lazy ? false : void 0;
19021
- await handleInstall(packageSpec, {
19022
- version: options.version,
19023
- as: convertTo,
19024
- subtype: options.subtype,
19025
- frozenLockfile: options.frozenLockfile,
19026
- force: options.yes,
19027
- location: options.location,
19028
- noAppend: options.noAppend,
19029
- manifestFile: options.manifestFile,
19030
- hookMapping: options.hookMapping,
19031
- eager,
19032
- tools: options.tools,
19033
- global: options.global,
19034
- editor: mcpEditor
19035
- });
19048
+ if (asTokens.length <= 1) {
19049
+ const [singleAs] = asTokens;
19050
+ const isMCPEditorOnly = singleAs && !validFormats.includes(singleAs) && MCP_EDITORS.includes(singleAs);
19051
+ const convertTo = isMCPEditorOnly ? void 0 : singleAs;
19052
+ const mcpEditor = options.editor || singleAs;
19053
+ await handleInstall(packageSpec, {
19054
+ version: options.version,
19055
+ as: convertTo,
19056
+ subtype: options.subtype,
19057
+ frozenLockfile: options.frozenLockfile,
19058
+ force: options.yes,
19059
+ location: options.location,
19060
+ noAppend: options.noAppend,
19061
+ manifestFile: options.manifestFile,
19062
+ hookMapping: options.hookMapping,
19063
+ eager,
19064
+ tools: options.tools,
19065
+ global: options.global,
19066
+ editor: mcpEditor
19067
+ });
19068
+ return;
19069
+ }
19070
+ console.log(`\u{1F4E6} Installing ${packageSpec} to ${asTokens.length} targets: ${asTokens.join(", ")}
19071
+ `);
19072
+ let successCount = 0;
19073
+ const failures = [];
19074
+ const isCollectionSpec = packageSpec.startsWith("collections/");
19075
+ for (const token of asTokens) {
19076
+ const isMCPEditorOnly = !validFormats.includes(token) && MCP_EDITORS.includes(token);
19077
+ const convertTo = isMCPEditorOnly ? void 0 : token;
19078
+ const mcpEditor = token;
19079
+ console.log(source_default.cyan(`
19080
+ \u2501\u2501 [${token}] \u2501\u2501`));
19081
+ try {
19082
+ await handleInstall(packageSpec, {
19083
+ version: options.version,
19084
+ as: convertTo,
19085
+ subtype: options.subtype,
19086
+ frozenLockfile: options.frozenLockfile,
19087
+ force: options.yes,
19088
+ location: options.location,
19089
+ noAppend: options.noAppend,
19090
+ manifestFile: options.manifestFile,
19091
+ hookMapping: options.hookMapping,
19092
+ eager,
19093
+ tools: options.tools,
19094
+ global: options.global,
19095
+ editor: options.editor || mcpEditor
19096
+ });
19097
+ successCount++;
19098
+ } catch (err) {
19099
+ if (err instanceof CLIError && err.exitCode === 0) {
19100
+ successCount++;
19101
+ continue;
19102
+ }
19103
+ const message = err instanceof Error ? err.message : String(err);
19104
+ failures.push({ target: token, error: message });
19105
+ console.error(source_default.red(`\u274C Failed to install ${packageSpec} as ${token}: ${message}`));
19106
+ }
19107
+ }
19108
+ console.log(`
19109
+ \u2705 Installed ${packageSpec} to ${successCount}/${asTokens.length} targets` + (isCollectionSpec ? " (collection)" : ""));
19110
+ if (failures.length > 0) {
19111
+ const detail = failures.map((f) => ` \u2022 ${f.target}: ${f.error}`).join("\n");
19112
+ throw new CLIError(`\u274C ${failures.length} target${failures.length === 1 ? "" : "s"} failed:
19113
+ ${detail}`, 1);
19114
+ }
19036
19115
  });
19037
19116
  return command;
19038
19117
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prpm",
3
- "version": "2.1.35",
3
+ "version": "2.1.37",
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.36",
49
- "@pr-pm/registry-client": "^2.3.35",
50
- "@pr-pm/types": "^2.1.36",
48
+ "@pr-pm/converters": "^2.1.38",
49
+ "@pr-pm/registry-client": "^2.3.37",
50
+ "@pr-pm/types": "^2.1.38",
51
51
  "ajv": "^8.17.1",
52
52
  "ajv-formats": "^3.0.1",
53
53
  "chalk": "^5.6.2",