prpm 2.1.37 → 2.1.39

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 (3) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +128 -36
  3. package/package.json +4 -4
package/README.md CHANGED
@@ -14,7 +14,7 @@ prpm install collections/nextjs-pro # Entire Next.js setup in one command
14
14
  ```
15
15
  Installs 20 packages: backend-architect, cloud-architect, database-architect, and more
16
16
 
17
- 7,5000+ cross platform packages
17
+ 7,500+ cross platform packages
18
18
 
19
19
  [Docs](https://docs.prpm.dev) | [Search Packages](https://prpm.dev/search) | [Search Collections](https://prpm.dev/search?tab=collections)
20
20
 
package/dist/index.js CHANGED
@@ -102,7 +102,8 @@ function parseLockfileKey(key) {
102
102
  function addToLockfile(lockfile, packageId, packageInfo) {
103
103
  var _a;
104
104
  const snippetLocation = packageInfo.subtype === "snippet" ? (_a = packageInfo.snippetMetadata) == null ? void 0 : _a.targetPath : void 0;
105
- const lockfileKey = getLockfileKey(packageId, packageInfo.format, snippetLocation);
105
+ const locationKey = packageInfo.global ? "global" : snippetLocation;
106
+ const lockfileKey = getLockfileKey(packageId, packageInfo.format, locationKey);
106
107
  lockfile.packages[lockfileKey] = {
107
108
  version: packageInfo.version,
108
109
  resolved: packageInfo.tarballUrl,
@@ -111,6 +112,7 @@ function addToLockfile(lockfile, packageId, packageInfo) {
111
112
  dependencies: packageInfo.dependencies,
112
113
  format: packageInfo.format,
113
114
  subtype: packageInfo.subtype,
115
+ global: packageInfo.global,
114
116
  sourceFormat: packageInfo.sourceFormat,
115
117
  sourceSubtype: packageInfo.sourceSubtype,
116
118
  installedPath: packageInfo.installedPath,
@@ -140,13 +142,13 @@ function verifyPackageIntegrity(lockfile, packageId, tarballBuffer, format, loca
140
142
  const expectedHash = pkg.integrity.replace("sha256-", "");
141
143
  return hash === expectedHash;
142
144
  }
143
- function getLockedVersion(lockfile, packageId, format) {
145
+ function getLockedVersion(lockfile, packageId, format, location) {
144
146
  var _a;
145
147
  if (!lockfile) {
146
148
  return null;
147
149
  }
148
150
  if (format) {
149
- const lockfileKey = getLockfileKey(packageId, format);
151
+ const lockfileKey = getLockfileKey(packageId, format, location);
150
152
  return ((_a = lockfile.packages[lockfileKey]) == null ? void 0 : _a.version) || null;
151
153
  }
152
154
  if (lockfile.packages[packageId]) {
@@ -17641,6 +17643,36 @@ ${lines.join("\n")}
17641
17643
  ---
17642
17644
  ${body}`;
17643
17645
  }
17646
+ function replaceLeadingDirectory(filePath, from, to) {
17647
+ const normalizedPath = filePath.startsWith("./") ? filePath.slice(2) : filePath;
17648
+ if (normalizedPath === from) {
17649
+ return to;
17650
+ }
17651
+ if (normalizedPath.startsWith(`${from}/`)) {
17652
+ return import_path15.default.join(to, normalizedPath.slice(from.length + 1));
17653
+ }
17654
+ return filePath;
17655
+ }
17656
+ function getGlobalDestinationDir(format, destDir) {
17657
+ const homeDir = import_os5.default.homedir();
17658
+ if (format === "claude") {
17659
+ return replaceLeadingDirectory(destDir, ".claude", import_path15.default.join(homeDir, ".claude"));
17660
+ }
17661
+ if (format === "codex") {
17662
+ if (destDir === "." || destDir === "./") {
17663
+ return import_path15.default.join(homeDir, ".codex");
17664
+ }
17665
+ const codexPath = replaceLeadingDirectory(destDir, ".codex", import_path15.default.join(homeDir, ".codex"));
17666
+ if (codexPath !== destDir) {
17667
+ return codexPath;
17668
+ }
17669
+ return replaceLeadingDirectory(destDir, ".agents", import_path15.default.join(homeDir, ".agents"));
17670
+ }
17671
+ return destDir;
17672
+ }
17673
+ function getLockfileLocationKey(options) {
17674
+ return options.global ? "global" : void 0;
17675
+ }
17644
17676
  function getPackageLabel2(format, subtype) {
17645
17677
  const formatLabels = {
17646
17678
  "claude": "Claude",
@@ -17783,7 +17815,8 @@ async function handleInstall(packageSpec, options) {
17783
17815
  if (!targetFormat) {
17784
17816
  targetFormat = config.defaultFormat || await autoDetectFormat() || void 0;
17785
17817
  }
17786
- const lockedVersion = getLockedVersion(lockfile, packageId, targetFormat);
17818
+ const lockfileLocationKey = getLockfileLocationKey(options);
17819
+ const lockedVersion = getLockedVersion(lockfile, packageId, targetFormat, lockfileLocationKey);
17787
17820
  let version;
17788
17821
  if (options.frozenLockfile) {
17789
17822
  if (!lockedVersion) {
@@ -17804,7 +17837,7 @@ async function handleInstall(packageSpec, options) {
17804
17837
  matchedKey = snippetKey;
17805
17838
  }
17806
17839
  if (!installedPkg) {
17807
- const standardKey = getLockfileKey(packageId, targetFormat);
17840
+ const standardKey = getLockfileKey(packageId, targetFormat, lockfileLocationKey);
17808
17841
  if (lockfile.packages[standardKey]) {
17809
17842
  installedPkg = lockfile.packages[standardKey];
17810
17843
  matchedKey = standardKey;
@@ -17954,11 +17987,11 @@ async function handleInstall(packageSpec, options) {
17954
17987
  }
17955
17988
  console.log(` \u2B07\uFE0F Downloading...`);
17956
17989
  const tarball = await client.downloadPackage(tarballUrl);
17957
- const lockfileKeyForVerification = getLockfileKey(packageId, targetFormat);
17990
+ const lockfileKeyForVerification = getLockfileKey(packageId, targetFormat, lockfileLocationKey);
17958
17991
  const existingEntry = lockfile == null ? void 0 : lockfile.packages[lockfileKeyForVerification];
17959
17992
  if ((existingEntry == null ? void 0 : existingEntry.integrity) && existingEntry.version === actualVersion) {
17960
17993
  console.log(` \u{1F512} Verifying integrity...`);
17961
- const isValid = verifyPackageIntegrity(lockfile, packageId, tarball, targetFormat);
17994
+ const isValid = verifyPackageIntegrity(lockfile, packageId, tarball, targetFormat, lockfileLocationKey);
17962
17995
  if (!isValid) {
17963
17996
  throw new CLIError(
17964
17997
  `\u274C Integrity verification failed for ${packageId}
@@ -17982,6 +18015,7 @@ This could indicate:
17982
18015
  if (options.as && format && format !== pkg.format && effectiveSubtype !== "snippet" && !isMCPToEditor) {
17983
18016
  console.log(` \u{1F504} Converting from ${pkg.format} to ${format}...`);
17984
18017
  let sourceContent;
18018
+ let mainFileIndex = 0;
17985
18019
  if (extractedFiles.length === 1) {
17986
18020
  sourceContent = extractedFiles[0].content;
17987
18021
  } else {
@@ -17991,6 +18025,7 @@ This could indicate:
17991
18025
  `Could not identify main file for multi-file ${pkg.format} ${pkg.subtype} package. Expected files like SKILL.md, agent.md, or similar main entry points.`
17992
18026
  );
17993
18027
  }
18028
+ mainFileIndex = extractedFiles.indexOf(mainFile);
17994
18029
  console.log(` \u{1F4C4} Using main file: ${mainFile.name}`);
17995
18030
  sourceContent = mainFile.content;
17996
18031
  }
@@ -18142,10 +18177,16 @@ This could indicate:
18142
18177
  if (!convertedContent) {
18143
18178
  throw new CLIError("Conversion failed: No content generated");
18144
18179
  }
18145
- extractedFiles = [{
18146
- name: extractedFiles[0].name,
18147
- content: convertedContent
18148
- }];
18180
+ if (extractedFiles.length === 1) {
18181
+ extractedFiles = [{
18182
+ name: extractedFiles[0].name,
18183
+ content: convertedContent
18184
+ }];
18185
+ } else {
18186
+ extractedFiles = extractedFiles.map(
18187
+ (file, index) => index === mainFileIndex ? { ...file, content: convertedContent } : file
18188
+ );
18189
+ }
18149
18190
  console.log(` \u2713 Converted from ${pkg.format} to ${format}`);
18150
18191
  }
18151
18192
  const locationSupportedFormats = ["agents.md", "cursor"];
@@ -18164,6 +18205,7 @@ This could indicate:
18164
18205
  const isClaudePlugin = pkg.format === "claude" && pkg.subtype === "plugin";
18165
18206
  if (isClaudePlugin) {
18166
18207
  console.log(` \u{1F50C} Installing Claude Plugin...`);
18208
+ const claudeRoot = options.global ? import_path15.default.join(import_os5.default.homedir(), ".claude") : ".claude";
18167
18209
  const pluginJsonFile = extractedFiles.find(
18168
18210
  (f) => f.name === "plugin.json" || f.name === ".claude-plugin/plugin.json" || f.name.endsWith("/plugin.json")
18169
18211
  );
@@ -18180,14 +18222,15 @@ This could indicate:
18180
18222
  (f) => f.name.startsWith("agents/") && f.name.endsWith(".md")
18181
18223
  );
18182
18224
  if (agentFiles.length > 0) {
18183
- await import_promises4.default.mkdir(".claude/agents", { recursive: true });
18225
+ const agentDir = import_path15.default.join(claudeRoot, "agents");
18226
+ await import_promises4.default.mkdir(agentDir, { recursive: true });
18184
18227
  for (const file of agentFiles) {
18185
18228
  const filename = import_path15.default.basename(file.name);
18186
- const destFile = `.claude/agents/${filename}`;
18229
+ const destFile = import_path15.default.join(agentDir, filename);
18187
18230
  await saveFile(destFile, file.content);
18188
18231
  installedFiles.push(destFile);
18189
18232
  }
18190
- console.log(` \u2713 Installed ${agentFiles.length} agents to .claude/agents/`);
18233
+ console.log(` \u2713 Installed ${agentFiles.length} agents to ${agentDir}/`);
18191
18234
  }
18192
18235
  const skillFiles = extractedFiles.filter(
18193
18236
  (f) => f.name.startsWith("skills/") && (f.name.endsWith(".md") || f.name.includes("SKILL.md"))
@@ -18195,26 +18238,27 @@ This could indicate:
18195
18238
  if (skillFiles.length > 0) {
18196
18239
  for (const file of skillFiles) {
18197
18240
  const relativePath = file.name.replace(/^skills\//, "");
18198
- const destFile = `.claude/skills/${relativePath}`;
18241
+ const destFile = import_path15.default.join(claudeRoot, "skills", relativePath);
18199
18242
  const destFileDir = import_path15.default.dirname(destFile);
18200
18243
  await import_promises4.default.mkdir(destFileDir, { recursive: true });
18201
18244
  await saveFile(destFile, file.content);
18202
18245
  installedFiles.push(destFile);
18203
18246
  }
18204
- console.log(` \u2713 Installed ${skillFiles.length} skill files to .claude/skills/`);
18247
+ console.log(` \u2713 Installed ${skillFiles.length} skill files to ${import_path15.default.join(claudeRoot, "skills")}/`);
18205
18248
  }
18206
18249
  const commandFiles = extractedFiles.filter(
18207
18250
  (f) => f.name.startsWith("commands/") && f.name.endsWith(".md")
18208
18251
  );
18209
18252
  if (commandFiles.length > 0) {
18210
- await import_promises4.default.mkdir(".claude/commands", { recursive: true });
18253
+ const commandDir = import_path15.default.join(claudeRoot, "commands");
18254
+ await import_promises4.default.mkdir(commandDir, { recursive: true });
18211
18255
  for (const file of commandFiles) {
18212
18256
  const filename = import_path15.default.basename(file.name);
18213
- const destFile = `.claude/commands/${filename}`;
18257
+ const destFile = import_path15.default.join(commandDir, filename);
18214
18258
  await saveFile(destFile, file.content);
18215
18259
  installedFiles.push(destFile);
18216
18260
  }
18217
- console.log(` \u2713 Installed ${commandFiles.length} commands to .claude/commands/`);
18261
+ console.log(` \u2713 Installed ${commandFiles.length} commands to ${commandDir}/`);
18218
18262
  }
18219
18263
  if (pluginConfig.mcpServers && Object.keys(pluginConfig.mcpServers).length > 0) {
18220
18264
  const editor = options.editor || "claude";
@@ -18251,7 +18295,7 @@ This could indicate:
18251
18295
  files: installedFiles
18252
18296
  };
18253
18297
  }
18254
- destPath = ".claude/";
18298
+ destPath = `${claudeRoot}/`;
18255
18299
  fileCount = installedFiles.length;
18256
18300
  } else if (effectiveFormat === "mcp" && (effectiveSubtype === "server" || effectiveSubtype === "tool") || isMCPServerPackage && (pkg.subtype === "server" || pkg.subtype === "tool") && isMCPToEditor) {
18257
18301
  console.log(` \u{1F527} Installing MCP Server...`);
@@ -18341,11 +18385,18 @@ This could indicate:
18341
18385
  throw new Error("CLAUDE.md format only supports single-file packages");
18342
18386
  }
18343
18387
  let mainFile = extractedFiles[0].content;
18344
- destPath = "CLAUDE.md";
18388
+ destPath = options.global ? import_path15.default.join(import_os5.default.homedir(), ".claude", "CLAUDE.md") : "CLAUDE.md";
18345
18389
  await saveFile(destPath, mainFile);
18346
18390
  fileCount = 1;
18347
18391
  } else if (extractedFiles.length === 1) {
18348
18392
  destDir = getDestinationDir2(effectiveFormat, effectiveSubtype, pkg.name);
18393
+ if (options.global) {
18394
+ const globalDestDir = getGlobalDestinationDir(effectiveFormat, destDir);
18395
+ if (globalDestDir !== destDir) {
18396
+ destDir = globalDestDir;
18397
+ console.log(` \u{1F310} Installing globally to ${destDir}`);
18398
+ }
18399
+ }
18349
18400
  if (locationOverride && effectiveFormat === "cursor") {
18350
18401
  const relativeDestDir = destDir.startsWith("./") ? destDir.slice(2) : destDir;
18351
18402
  destDir = import_path15.default.join(locationOverride, relativeDestDir);
@@ -18369,7 +18420,11 @@ This could indicate:
18369
18420
  } else if (effectiveFormat === "agents.md" || effectiveFormat === "gemini.md" || effectiveFormat === "claude.md" || effectiveFormat === "codex") {
18370
18421
  if (effectiveSubtype === "skill") {
18371
18422
  destPath = `${destDir}/SKILL.md`;
18372
- console.log(` \u{1F4E6} Installing skill to ${destDir}/ for progressive disclosure`);
18423
+ if (effectiveFormat === "codex") {
18424
+ console.log(` \u{1F4E6} Installing Codex skill to ${destDir}/`);
18425
+ } else {
18426
+ console.log(` \u{1F4E6} Installing skill to ${destDir}/ for progressive disclosure`);
18427
+ }
18373
18428
  } else if (effectiveSubtype === "agent") {
18374
18429
  if (effectiveFormat === "codex") {
18375
18430
  destPath = `${destDir}/${packageName}.toml`;
@@ -18541,12 +18596,19 @@ This could indicate:
18541
18596
  } else {
18542
18597
  destDir = getDestinationDir2(effectiveFormat, effectiveSubtype, pkg.name);
18543
18598
  }
18599
+ if (options.global) {
18600
+ const globalDestDir = getGlobalDestinationDir(effectiveFormat, destDir);
18601
+ if (globalDestDir !== destDir) {
18602
+ destDir = globalDestDir;
18603
+ console.log(` \u{1F310} Installing globally to ${destDir}`);
18604
+ }
18605
+ }
18544
18606
  if (locationOverride && effectiveFormat === "cursor") {
18545
18607
  const relativeDestDir = destDir.startsWith("./") ? destDir.slice(2) : destDir;
18546
18608
  destDir = import_path15.default.join(locationOverride, relativeDestDir);
18547
18609
  console.log(` \u{1F4C1} Installing Cursor package to custom location: ${destDir}`);
18548
18610
  }
18549
- const isCursorConversion = effectiveFormat === "cursor" && pkg.format === "claude" && pkg.subtype === "skill";
18611
+ const isCursorConversion = effectiveFormat === "cursor" && pkg.format === "claude" && pkg.subtype === "skill" && !needsProgressiveDisclosureMulti;
18550
18612
  const nativeSubtypeConfig = getSubtypeConfig(effectiveFormat, effectiveSubtype);
18551
18613
  const usesNativePackageSubdirectory = !needsProgressiveDisclosureMulti && Boolean(nativeSubtypeConfig == null ? void 0 : nativeSubtypeConfig.usesPackageSubdirectory);
18552
18614
  const packageDir = effectiveFormat === "claude" && effectiveSubtype === "skill" ? destDir : isCursorConversion ? destDir : needsProgressiveDisclosureMulti ? destDir : usesNativePackageSubdirectory ? destDir : `${destDir}/${packageName}`;
@@ -18704,11 +18766,13 @@ ${afterFrontmatter}`;
18704
18766
  progressiveDisclosure: progressiveDisclosureMetadata,
18705
18767
  pluginMetadata,
18706
18768
  // Track plugin installation metadata for uninstall
18707
- snippetMetadata
18769
+ snippetMetadata,
18708
18770
  // Track snippet installation metadata for uninstall
18771
+ global: options.global
18709
18772
  });
18710
18773
  const snippetTargetPath = effectiveSubtype === "snippet" ? snippetMetadata == null ? void 0 : snippetMetadata.targetPath : void 0;
18711
- setPackageIntegrity(updatedLockfile, packageId, tarball, effectiveFormat, snippetTargetPath);
18774
+ const integrityLocationKey = lockfileLocationKey || snippetTargetPath;
18775
+ setPackageIntegrity(updatedLockfile, packageId, tarball, effectiveFormat, integrityLocationKey);
18712
18776
  await writeLockfile(updatedLockfile);
18713
18777
  await client.trackDownload(packageId, {
18714
18778
  version: actualVersion || version,
@@ -18889,7 +18953,7 @@ async function collectExtractedFiles(rootDir, excludedNames, fs16) {
18889
18953
  return files;
18890
18954
  }
18891
18955
  async function installFromLockfile(options) {
18892
- var _a, _b;
18956
+ var _a, _b, _c, _d;
18893
18957
  try {
18894
18958
  const lockfile = await readLockfile();
18895
18959
  if (!lockfile) {
@@ -18906,7 +18970,7 @@ async function installFromLockfile(options) {
18906
18970
  let failCount = 0;
18907
18971
  for (const lockfileKey of packageIds) {
18908
18972
  const lockEntry = lockfile.packages[lockfileKey];
18909
- const { packageId, format } = parseLockfileKey(lockfileKey);
18973
+ const { packageId, format, location } = parseLockfileKey(lockfileKey);
18910
18974
  const displayName = format ? `${packageId} (${format})` : packageId;
18911
18975
  try {
18912
18976
  const packageSpec = packageId.includes("@") && !packageId.startsWith("@") ? packageId.substring(0, packageId.lastIndexOf("@")) : packageId;
@@ -18921,6 +18985,8 @@ async function installFromLockfile(options) {
18921
18985
  }
18922
18986
  }
18923
18987
  const manifestFile = (_a = lockEntry.progressiveDisclosure) == null ? void 0 : _a.manifestPath;
18988
+ const preservedGlobal = options.global ?? lockEntry.global ?? ((_b = lockEntry.pluginMetadata) == null ? void 0 : _b.mcpGlobal) ?? (location === "global" ? true : void 0);
18989
+ const preservedEditor = options.editor ?? ((_c = lockEntry.pluginMetadata) == null ? void 0 : _c.mcpEditor);
18924
18990
  await handleInstall(packageSpec, {
18925
18991
  version: lockEntry.version,
18926
18992
  as: options.as || lockEntry.format,
@@ -18931,8 +18997,10 @@ async function installFromLockfile(options) {
18931
18997
  location: locationOverride,
18932
18998
  manifestFile,
18933
18999
  hookMapping: options.hookMapping,
18934
- fromCollection: lockEntry.fromCollection
19000
+ fromCollection: lockEntry.fromCollection,
18935
19001
  // Preserve collection metadata
19002
+ global: preservedGlobal,
19003
+ editor: preservedEditor
18936
19004
  });
18937
19005
  successCount++;
18938
19006
  } catch (error) {
@@ -18941,7 +19009,7 @@ async function installFromLockfile(options) {
18941
19009
  } else {
18942
19010
  failCount++;
18943
19011
  console.error(` \u274C Failed to install ${displayName}:`);
18944
- console.error(` Type: ${(_b = error == null ? void 0 : error.constructor) == null ? void 0 : _b.name}`);
19012
+ console.error(` Type: ${(_d = error == null ? void 0 : error.constructor) == null ? void 0 : _d.name}`);
18945
19013
  console.error(` Message: ${error instanceof Error ? error.message : String(error)}`);
18946
19014
  if (error instanceof CLIError) {
18947
19015
  console.error(` ExitCode: ${error.exitCode}`);
@@ -18963,7 +19031,7 @@ async function installFromLockfile(options) {
18963
19031
  }
18964
19032
  function createInstallCommand() {
18965
19033
  const command = new import_commander12.Command("install");
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) => {
19034
+ 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 to user-level/global locations where supported (e.g., ~/.claude/skills, ~/.agents/skills, ~/.codex/agents, or global MCP config)").option("--editor <editor>", "[Deprecated: use --as] Target editor for MCP server installation").action(async (packageSpec, options) => {
18967
19035
  const rawAs = options.format || options.as;
18968
19036
  const validFormats = import_types.FORMATS;
18969
19037
  const asTokens = rawAs ? Array.from(new Set(rawAs.split(",").map((s) => s.trim()).filter(Boolean))) : [];
@@ -19040,7 +19108,9 @@ The lockfile already records the target format for each package. Run prpm instal
19040
19108
  subtype: options.subtype,
19041
19109
  frozenLockfile: options.frozenLockfile,
19042
19110
  location: options.location,
19043
- hookMapping: options.hookMapping
19111
+ hookMapping: options.hookMapping,
19112
+ global: options.global,
19113
+ editor: options.editor ?? (isMCPEditorOnly ? singleAs : void 0)
19044
19114
  });
19045
19115
  return;
19046
19116
  }
@@ -21074,7 +21144,14 @@ async function handleUninstall(name, options = {}) {
21074
21144
  if (requestedFormat) {
21075
21145
  const requestedKey = getLockfileKey(name, requestedFormat);
21076
21146
  if (!lockfile.packages[requestedKey]) {
21077
- if (lockfile.packages[name] && lockfile.packages[name].format === requestedFormat) {
21147
+ const matchingFormatKeys = matchingKeys.filter((key) => {
21148
+ const parsed = parseLockfileKey(key);
21149
+ const pkg = lockfile.packages[key];
21150
+ return parsed.format === requestedFormat || pkg.format === requestedFormat;
21151
+ });
21152
+ if (matchingFormatKeys.length > 0) {
21153
+ keysToUninstall = matchingFormatKeys;
21154
+ } else if (lockfile.packages[name] && lockfile.packages[name].format === requestedFormat) {
21078
21155
  keysToUninstall = [name];
21079
21156
  } else {
21080
21157
  throw new CLIError(`\u274C Package "${name}" with format "${requestedFormat}" not found`, 1);
@@ -24760,6 +24837,14 @@ init_lockfile();
24760
24837
  init_install();
24761
24838
  init_telemetry();
24762
24839
  init_errors();
24840
+ function getPreservedGlobal(pkg, location) {
24841
+ var _a;
24842
+ return pkg.global ?? ((_a = pkg.pluginMetadata) == null ? void 0 : _a.mcpGlobal) ?? (location === "global" ? true : void 0);
24843
+ }
24844
+ function getPreservedEditor(pkg) {
24845
+ var _a;
24846
+ return (_a = pkg.pluginMetadata) == null ? void 0 : _a.mcpEditor;
24847
+ }
24763
24848
  async function handleUpdate(packageName, options = {}) {
24764
24849
  const startTime = Date.now();
24765
24850
  let success = false;
@@ -24786,7 +24871,7 @@ async function handleUpdate(packageName, options = {}) {
24786
24871
  }
24787
24872
  console.log("\u{1F504} Checking for updates...\n");
24788
24873
  for (const pkg of packagesToUpdate) {
24789
- const { packageId, format: installedFormat } = parseLockfileKey(pkg.id);
24874
+ const { packageId, format: installedFormat, location } = parseLockfileKey(pkg.id);
24790
24875
  try {
24791
24876
  const registryPkg = await client.getPackage(packageId);
24792
24877
  if (!registryPkg.latest_version || !pkg.version) {
@@ -24812,9 +24897,16 @@ async function handleUpdate(packageName, options = {}) {
24812
24897
  \u{1F4E6} Updating ${packageId}: ${currentVersion} \u2192 ${latestVersion}`
24813
24898
  );
24814
24899
  const targetFormat = pkg.format || installedFormat;
24815
- await handleInstall(`${packageId}@${latestVersion}`, {
24816
- as: targetFormat
24817
- });
24900
+ const installOptions = { as: targetFormat };
24901
+ const preservedGlobal = getPreservedGlobal(pkg, location);
24902
+ const preservedEditor = getPreservedEditor(pkg);
24903
+ if (preservedGlobal !== void 0) {
24904
+ installOptions.global = preservedGlobal;
24905
+ }
24906
+ if (preservedEditor) {
24907
+ installOptions.editor = preservedEditor;
24908
+ }
24909
+ await handleInstall(`${packageId}@${latestVersion}`, installOptions);
24818
24910
  updatedCount++;
24819
24911
  } catch (err) {
24820
24912
  console.error(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prpm",
3
- "version": "2.1.37",
3
+ "version": "2.1.39",
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.38",
49
- "@pr-pm/registry-client": "^2.3.37",
50
- "@pr-pm/types": "^2.1.38",
48
+ "@pr-pm/converters": "^2.1.40",
49
+ "@pr-pm/registry-client": "^2.3.39",
50
+ "@pr-pm/types": "^2.1.40",
51
51
  "ajv": "^8.17.1",
52
52
  "ajv-formats": "^3.0.1",
53
53
  "chalk": "^5.6.2",