prpm 2.1.4 → 2.1.5

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 +216 -73
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -191,6 +191,19 @@ function addCollectionToLockfile(lockfile, collectionKey, collectionInfo) {
191
191
  };
192
192
  lockfile.generated = (/* @__PURE__ */ new Date()).toISOString();
193
193
  }
194
+ function getCollectionFromLockfile(lockfile, collectionKey) {
195
+ if (!lockfile || !lockfile.collections) {
196
+ return null;
197
+ }
198
+ return lockfile.collections[collectionKey] || null;
199
+ }
200
+ function removeCollectionFromLockfile(lockfile, collectionKey) {
201
+ if (!lockfile.collections) {
202
+ return;
203
+ }
204
+ delete lockfile.collections[collectionKey];
205
+ lockfile.generated = (/* @__PURE__ */ new Date()).toISOString();
206
+ }
194
207
  var import_fs, import_path, import_crypto, LOCKFILE_NAME, LOCKFILE_VERSION;
195
208
  var init_lockfile = __esm({
196
209
  "src/core/lockfile.ts"() {
@@ -884,7 +897,8 @@ function fromClaude(content, metadata, sourceFormat = "claude", explicitSubtype)
884
897
  const pkg = {
885
898
  id: metadata.id,
886
899
  version: metadata.version || "1.0.0",
887
- name: frontmatter.name || metadata.id,
900
+ name: metadata.name || frontmatter.name || metadata.id,
901
+ // Package name for registry
888
902
  description: frontmatter.description || "",
889
903
  author: metadata.author || "unknown",
890
904
  tags: metadata.tags || [],
@@ -930,20 +944,27 @@ function parseMarkdownBody(body) {
930
944
  let preamble = [];
931
945
  let h1Title;
932
946
  let h1Icon;
947
+ let inCodeBlock = false;
933
948
  for (let i = 0; i < lines.length; i++) {
934
949
  const line = lines[i];
935
- if (line.startsWith("# ")) {
950
+ if (line.startsWith("```")) {
951
+ inCodeBlock = !inCodeBlock;
952
+ }
953
+ if (line.startsWith("# ") && !inCodeBlock && h1Title === void 0) {
936
954
  const titleText = line.substring(2).trim();
937
- const iconMatch = titleText.match(new RegExp("^(\\p{Emoji})\\s+(.+)$", "u"));
938
- if (iconMatch) {
939
- h1Icon = iconMatch[1];
940
- h1Title = iconMatch[2];
955
+ if (titleText.includes("{") || titleText.includes("[") || titleText.startsWith("Output")) {
941
956
  } else {
942
- h1Title = titleText;
957
+ const iconMatch = titleText.match(new RegExp("^(\\p{Emoji})\\s+(.+)$", "u"));
958
+ if (iconMatch) {
959
+ h1Icon = iconMatch[1];
960
+ h1Title = iconMatch[2];
961
+ } else {
962
+ h1Title = titleText;
963
+ }
964
+ continue;
943
965
  }
944
- continue;
945
966
  }
946
- if (line.startsWith("## ")) {
967
+ if (line.startsWith("## ") && !inCodeBlock) {
947
968
  if (currentSection) {
948
969
  sections.push(createSectionFromBlock(currentSection.title, currentSection.lines.join("\n")));
949
970
  }
@@ -8712,16 +8733,19 @@ function loadSchema(format, subtype) {
8712
8733
  "claude:skill": "claude-skill.schema.json",
8713
8734
  "claude:slash-command": "claude-slash-command.schema.json",
8714
8735
  "claude:hook": "claude-hook.schema.json",
8736
+ "claude:plugin": "claude-plugin.schema.json",
8715
8737
  "cursor:slash-command": "cursor-command.schema.json",
8716
8738
  "cursor:hook": "cursor-hooks.schema.json",
8717
8739
  // cursor + hook subtype uses cursor-hooks schema
8718
- "kiro:hook": "kiro-hooks.schema.json",
8740
+ "kiro:hook": "kiro-hook.schema.json",
8719
8741
  "kiro:agent": "kiro-agent.schema.json",
8720
8742
  "droid:skill": "droid-skill.schema.json",
8721
8743
  "droid:slash-command": "droid-slash-command.schema.json",
8722
8744
  "droid:hook": "droid-hook.schema.json",
8723
8745
  "opencode:slash-command": "opencode-slash-command.schema.json",
8724
- "gemini:extension": "gemini-extension.schema.json"
8746
+ "opencode:plugin": "opencode-plugin.schema.json",
8747
+ "gemini:extension": "gemini-extension.schema.json",
8748
+ "mcp:server": "mcp-server.schema.json"
8725
8749
  };
8726
8750
  schemaFilename = subtypeSchemaMap[cacheKey];
8727
8751
  }
@@ -16508,7 +16532,7 @@ function findMainFile(files, format, subtype) {
16508
16532
  return null;
16509
16533
  }
16510
16534
  async function handleInstall(packageSpec, options) {
16511
- var _a, _b, _c;
16535
+ var _a;
16512
16536
  const startTime = Date.now();
16513
16537
  let success = false;
16514
16538
  let error;
@@ -16873,7 +16897,7 @@ This could indicate:
16873
16897
  console.log(` \u26A0\uFE0F --location option currently applies to Cursor or Agents.md installs. Ignoring provided value for ${effectiveFormat}.`);
16874
16898
  locationOverride = void 0;
16875
16899
  }
16876
- let destPath;
16900
+ let destPath = "";
16877
16901
  let destDir = "";
16878
16902
  let fileCount = 0;
16879
16903
  let hookMetadata = void 0;
@@ -17054,7 +17078,7 @@ This could indicate:
17054
17078
  }
17055
17079
  }
17056
17080
  }
17057
- } else if (effectiveFormat === "copilot") {
17081
+ } else if (effectiveFormat === "copilot" && (effectiveSubtype === "chatmode" || effectiveSubtype === "rule")) {
17058
17082
  if (effectiveSubtype === "chatmode") {
17059
17083
  destPath = `${destDir}/${packageName}.chatmode.md`;
17060
17084
  } else {
@@ -17072,20 +17096,26 @@ This could indicate:
17072
17096
  }
17073
17097
  } else if (effectiveFormat === "droid" && effectiveSubtype === "skill") {
17074
17098
  destPath = `${destDir}/SKILL.md`;
17075
- } else if (effectiveFormat === "droid" && effectiveSubtype === "agent") {
17076
- destDir = `.openagents/${packageName}`;
17077
- destPath = `${destDir}/AGENT.md`;
17078
- console.log(` \u{1F916} Installing agent to ${destDir}/ for progressive disclosure`);
17079
- } else if (effectiveFormat === "cursor" && effectiveSubtype === "agent") {
17080
- destDir = `.openagents/${packageName}`;
17081
- destPath = `${destDir}/AGENT.md`;
17082
- console.log(` \u{1F916} Installing agent to ${destDir}/ for progressive disclosure`);
17083
- } else if (effectiveFormat === "opencode" && effectiveSubtype === "skill") {
17084
- destDir = `.openskills/${packageName}`;
17085
- destPath = `${destDir}/SKILL.md`;
17086
- console.log(` \u{1F4E6} Installing skill to ${destDir}/ for progressive disclosure`);
17087
17099
  } else {
17088
- destPath = `${destDir}/${packageName}.${fileExtension}`;
17100
+ const nativeSubtypes2 = import_types.FORMAT_NATIVE_SUBTYPES[effectiveFormat];
17101
+ const needsProgressiveDisclosureHere = nativeSubtypes2 && !nativeSubtypes2.includes(effectiveSubtype) && (effectiveSubtype === "skill" || effectiveSubtype === "agent" || effectiveSubtype === "slash-command");
17102
+ if (needsProgressiveDisclosureHere) {
17103
+ if (effectiveSubtype === "skill") {
17104
+ destDir = `.openskills/${packageName}`;
17105
+ destPath = `${destDir}/SKILL.md`;
17106
+ console.log(` \u{1F4E6} Installing skill to ${destDir}/ for progressive disclosure`);
17107
+ } else if (effectiveSubtype === "agent") {
17108
+ destDir = `.openagents/${packageName}`;
17109
+ destPath = `${destDir}/AGENT.md`;
17110
+ console.log(` \u{1F916} Installing agent to ${destDir}/ for progressive disclosure`);
17111
+ } else if (effectiveSubtype === "slash-command") {
17112
+ destDir = ".opencommands";
17113
+ destPath = `${destDir}/${packageName}.md`;
17114
+ console.log(` \u26A1 Installing command to ${destDir}/ for progressive disclosure`);
17115
+ }
17116
+ } else {
17117
+ destPath = `${destDir}/${packageName}.${fileExtension}`;
17118
+ }
17089
17119
  }
17090
17120
  if (format === "cursor" && effectiveFormat === "cursor") {
17091
17121
  if (!hasMDCHeader(mainFile)) {
@@ -17104,6 +17134,7 @@ This could indicate:
17104
17134
  }
17105
17135
  }
17106
17136
  if (effectiveFormat === "claude" && effectiveSubtype === "hook") {
17137
+ destPath = destPath || `${destDir}/settings.json`;
17107
17138
  let hookConfig;
17108
17139
  try {
17109
17140
  hookConfig = JSON.parse(mainFile);
@@ -17240,53 +17271,23 @@ ${afterFrontmatter}`;
17240
17271
  }
17241
17272
  }
17242
17273
  let progressiveDisclosureMetadata;
17243
- const progressiveDisclosureFormats = [
17244
- "agents.md",
17245
- // Universal AGENTS.md format
17246
- "gemini.md",
17247
- // Uses GEMINI.md
17248
- "claude.md",
17249
- // Uses CLAUDE.md
17250
- "aider",
17251
- // Uses CONVENTIONS.md
17252
- "codex",
17253
- // Uses AGENTS.md (no native skills/agents/commands)
17254
- "copilot",
17255
- // Uses AGENTS.md (no native skills/agents/commands)
17256
- "kiro",
17257
- // Uses AGENTS.md (no native skills)
17258
- "replit",
17259
- // Uses AGENTS.md (no native skills)
17260
- "zed",
17261
- // Uses AGENTS.md (no native skills)
17262
- "generic"
17263
- // Uses AGENTS.md (fallback format)
17264
- ];
17265
- const partialNativeSupport = {
17266
- "cursor": ["agent"],
17267
- // Cursor has native rules/commands but no native agents
17268
- "opencode": ["skill"],
17269
- // OpenCode has native agents/commands but no native skills
17270
- "droid": ["agent"]
17271
- // Factory Droid has native skills/commands/hooks but no native agents
17272
- };
17273
- const needsProgressiveDisclosure = progressiveDisclosureFormats.includes(effectiveFormat) && (effectiveSubtype === "skill" || effectiveSubtype === "agent" || effectiveSubtype === "slash-command") || ((_b = partialNativeSupport[effectiveFormat]) == null ? void 0 : _b.includes(effectiveSubtype));
17274
+ const nativeSubtypes = import_types.FORMAT_NATIVE_SUBTYPES[effectiveFormat];
17275
+ const isProgressiveDisclosureSubtype = effectiveSubtype === "skill" || effectiveSubtype === "agent" || effectiveSubtype === "slash-command";
17276
+ const hasNativeSupport = (nativeSubtypes == null ? void 0 : nativeSubtypes.includes(effectiveSubtype)) ?? false;
17277
+ const needsProgressiveDisclosure = isProgressiveDisclosureSubtype && !hasNativeSupport;
17274
17278
  if (needsProgressiveDisclosure && !options.noAppend) {
17275
- if ((_c = partialNativeSupport[effectiveFormat]) == null ? void 0 : _c.includes(effectiveSubtype)) {
17276
- const resourceName2 = stripAuthorNamespace2(packageId);
17277
- if (effectiveSubtype === "skill") {
17278
- destDir = `.openskills/${resourceName2}`;
17279
- } else if (effectiveSubtype === "agent") {
17280
- destDir = `.openagents/${resourceName2}`;
17281
- } else if (effectiveSubtype === "slash-command") {
17282
- destDir = ".opencommands";
17283
- }
17279
+ const resourceName = stripAuthorNamespace2(packageId);
17280
+ if (effectiveSubtype === "skill") {
17281
+ destDir = `.openskills/${resourceName}`;
17282
+ } else if (effectiveSubtype === "agent") {
17283
+ destDir = `.openagents/${resourceName}`;
17284
+ } else if (effectiveSubtype === "slash-command") {
17285
+ destDir = ".opencommands";
17284
17286
  }
17285
17287
  if (!destDir) {
17286
17288
  throw new Error("Internal error: destDir not set for progressive disclosure installation");
17287
17289
  }
17288
17290
  const manifestPath = options.manifestFile || getManifestFilename(effectiveFormat);
17289
- const resourceName = stripAuthorNamespace2(packageId);
17290
17291
  const resourceType = effectiveSubtype === "slash-command" ? "command" : effectiveSubtype;
17291
17292
  let mainFile;
17292
17293
  if (resourceType === "command") {
@@ -19427,6 +19428,137 @@ async function promptForFormat(packageId, formats) {
19427
19428
  });
19428
19429
  });
19429
19430
  }
19431
+ async function handleCollectionUninstall(collectionKey, collection, lockfile, requestedFormat) {
19432
+ var _a;
19433
+ if (!collection) {
19434
+ throw new CLIError(`\u274C Collection "collections/${collectionKey}" not found in lockfile`, 1);
19435
+ }
19436
+ console.log(`
19437
+ \u{1F4E6} Uninstalling collection: ${collectionKey}`);
19438
+ console.log(` ${collection.packages.length} packages to uninstall
19439
+ `);
19440
+ let uninstalledCount = 0;
19441
+ let failedCount = 0;
19442
+ for (const packageId of collection.packages) {
19443
+ try {
19444
+ const matchingKeys = [];
19445
+ for (const key of Object.keys(lockfile.packages)) {
19446
+ const parsed = parseLockfileKey(key);
19447
+ if (parsed.packageId === packageId) {
19448
+ const pkg = lockfile.packages[key];
19449
+ if (((_a = pkg.fromCollection) == null ? void 0 : _a.name_slug) === collectionKey) {
19450
+ if (requestedFormat) {
19451
+ if (pkg.format === requestedFormat || parsed.format === requestedFormat) {
19452
+ matchingKeys.push(key);
19453
+ }
19454
+ } else {
19455
+ matchingKeys.push(key);
19456
+ }
19457
+ }
19458
+ }
19459
+ }
19460
+ if (matchingKeys.length === 0) {
19461
+ console.log(` \u26A0\uFE0F ${packageId}: not found (may have been uninstalled manually)`);
19462
+ continue;
19463
+ }
19464
+ for (const lockfileKey of matchingKeys) {
19465
+ const parsed = parseLockfileKey(lockfileKey);
19466
+ const formatDisplay = parsed.format ? ` (${parsed.format})` : "";
19467
+ await uninstallSinglePackage(lockfileKey, packageId, lockfile);
19468
+ console.log(` \u2713 ${packageId}${formatDisplay}`);
19469
+ uninstalledCount++;
19470
+ }
19471
+ } catch (error) {
19472
+ const errorMessage = error instanceof Error ? error.message : String(error);
19473
+ console.error(` \u2717 ${packageId}: ${errorMessage}`);
19474
+ failedCount++;
19475
+ }
19476
+ }
19477
+ const freshLockfile = await readLockfile();
19478
+ if (freshLockfile) {
19479
+ removeCollectionFromLockfile(freshLockfile, collectionKey);
19480
+ await writeLockfile(freshLockfile);
19481
+ }
19482
+ console.log(`
19483
+ \u2705 Collection uninstalled`);
19484
+ console.log(` ${uninstalledCount} packages removed`);
19485
+ if (failedCount > 0) {
19486
+ console.log(` ${failedCount} packages failed to uninstall`);
19487
+ }
19488
+ console.log(` \u{1F512} Collection removed from lock file`);
19489
+ }
19490
+ async function uninstallSinglePackage(lockfileKey, packageId, lockfile) {
19491
+ const parsed = parseLockfileKey(lockfileKey);
19492
+ const pkg = await removePackage(lockfileKey);
19493
+ if (!pkg) {
19494
+ throw new Error(`Package not found in lockfile`);
19495
+ }
19496
+ if (pkg.progressiveDisclosure) {
19497
+ const { manifestPath, resourceName, skillName } = pkg.progressiveDisclosure;
19498
+ const name = resourceName || skillName;
19499
+ if (name) {
19500
+ try {
19501
+ await removeSkillFromManifest(name, manifestPath);
19502
+ } catch (error) {
19503
+ }
19504
+ }
19505
+ }
19506
+ if (pkg.pluginMetadata) {
19507
+ const { files, mcpServers, mcpGlobal } = pkg.pluginMetadata;
19508
+ for (const filePath of files) {
19509
+ try {
19510
+ await import_fs11.promises.unlink(filePath);
19511
+ } catch (error) {
19512
+ const err = error;
19513
+ if (err.code !== "ENOENT") {
19514
+ }
19515
+ }
19516
+ }
19517
+ if (mcpServers && Object.keys(mcpServers).length > 0) {
19518
+ removeMCPServers(mcpServers, mcpGlobal || false);
19519
+ }
19520
+ return;
19521
+ }
19522
+ if (pkg.format === "claude" && pkg.subtype === "hook" && pkg.hookMetadata) {
19523
+ const settingsPath = pkg.installedPath || ".claude/settings.json";
19524
+ try {
19525
+ const settingsContent = await import_fs11.promises.readFile(settingsPath, "utf-8");
19526
+ const settings = JSON.parse(settingsContent);
19527
+ if (settings.hooks) {
19528
+ for (const event of pkg.hookMetadata.events) {
19529
+ if (settings.hooks[event]) {
19530
+ settings.hooks[event] = settings.hooks[event].filter(
19531
+ (hook) => hook.__prpm_hook_id !== pkg.hookMetadata.hookId
19532
+ );
19533
+ if (settings.hooks[event].length === 0) {
19534
+ delete settings.hooks[event];
19535
+ }
19536
+ }
19537
+ }
19538
+ await import_fs11.promises.writeFile(settingsPath, JSON.stringify(settings, null, 2), "utf-8");
19539
+ }
19540
+ } catch (error) {
19541
+ }
19542
+ return;
19543
+ }
19544
+ const targetPath = pkg.installedPath;
19545
+ if (!targetPath) {
19546
+ throw new Error("Installation path unknown");
19547
+ }
19548
+ try {
19549
+ const stats = await import_fs11.promises.stat(targetPath);
19550
+ if (stats.isDirectory()) {
19551
+ await import_fs11.promises.rm(targetPath, { recursive: true, force: true });
19552
+ } else if (stats.isFile()) {
19553
+ await import_fs11.promises.unlink(targetPath);
19554
+ }
19555
+ } catch (error) {
19556
+ const err = error;
19557
+ if (err.code !== "ENOENT") {
19558
+ throw err;
19559
+ }
19560
+ }
19561
+ }
19430
19562
  async function handleUninstall(name, options = {}) {
19431
19563
  try {
19432
19564
  const requestedFormat = options.format || options.as;
@@ -19437,6 +19569,13 @@ async function handleUninstall(name, options = {}) {
19437
19569
  if (!lockfile) {
19438
19570
  throw new CLIError("\u274C No prpm.lock file found", 1);
19439
19571
  }
19572
+ const isCollectionPrefix = name.startsWith("collections/");
19573
+ const collectionKey = isCollectionPrefix ? name.replace("collections/", "") : name;
19574
+ const collection = getCollectionFromLockfile(lockfile, collectionKey);
19575
+ if (collection || isCollectionPrefix) {
19576
+ await handleCollectionUninstall(collectionKey, collection, lockfile, requestedFormat);
19577
+ return;
19578
+ }
19440
19579
  const matchingKeys = [];
19441
19580
  for (const key of Object.keys(lockfile.packages)) {
19442
19581
  const parsed = parseLockfileKey(key);
@@ -19559,8 +19698,8 @@ async function handleUninstall(name, options = {}) {
19559
19698
  throw new Error(`Failed to remove hooks from settings: ${error}`);
19560
19699
  }
19561
19700
  }
19562
- console.log(`\u2705 Successfully uninstalled ${name}`);
19563
- return;
19701
+ console.log(`\u2705 Successfully uninstalled ${name}${formatDisplay}`);
19702
+ continue;
19564
19703
  }
19565
19704
  const packageName = stripAuthorNamespace2(name);
19566
19705
  let targetPath;
@@ -19600,7 +19739,7 @@ async function handleUninstall(name, options = {}) {
19600
19739
  }
19601
19740
  function createUninstallCommand() {
19602
19741
  const command = new import_commander2.Command("uninstall");
19603
- command.description("Uninstall a prompt package").argument("<id>", "Package ID to uninstall").option("--format <format>", "Specific format to uninstall (if multiple formats installed)").option("--as <format>", "Alias for --format (use when multiple formats are installed)").alias("remove").action(handleUninstall);
19742
+ command.description("Uninstall a prompt package or collection").argument("<id>", "Package ID or collection name (e.g., collections/my-collection)").option("--format <format>", "Specific format to uninstall (if multiple formats installed)").option("--as <format>", "Alias for --format (use when multiple formats are installed)").alias("remove").action(handleUninstall);
19604
19743
  return command;
19605
19744
  }
19606
19745
 
@@ -20873,7 +21012,7 @@ async function validatePackageFiles(manifest) {
20873
21012
  warnings.push(...result.warnings);
20874
21013
  } else if (formatType === "kiro") {
20875
21014
  if (filePath.endsWith(".json")) {
20876
- const result = await validateStructuredFile(filePath, formatType, "hook");
21015
+ const result = await validateStructuredFile(filePath, formatType, manifest.subtype);
20877
21016
  errors.push(...result.errors);
20878
21017
  warnings.push(...result.warnings);
20879
21018
  } else {
@@ -21502,9 +21641,13 @@ async function handlePublish(options) {
21502
21641
  let version;
21503
21642
  try {
21504
21643
  const config = await getConfig();
21505
- if (!config.token) {
21644
+ const isCIMode = process.env.CI_MODE === "true";
21645
+ if (!config.token && !isCIMode) {
21506
21646
  throw new CLIError('\u274C Not logged in. Run "prpm login" first.', 1);
21507
21647
  }
21648
+ if (isCIMode && !config.token) {
21649
+ console.log("\u{1F916} CI Mode: Publishing without authentication\n");
21650
+ }
21508
21651
  console.log("\u{1F4E6} Publishing package...\n");
21509
21652
  const prpmJsonPath = (0, import_path22.join)(process.cwd(), "prpm.json");
21510
21653
  const marketplaceJsonPath = (0, import_path22.join)(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prpm",
3
- "version": "2.1.4",
3
+ "version": "2.1.5",
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.4",
49
- "@pr-pm/registry-client": "^2.3.4",
50
- "@pr-pm/types": "^2.1.4",
48
+ "@pr-pm/converters": "^2.1.5",
49
+ "@pr-pm/registry-client": "^2.3.5",
50
+ "@pr-pm/types": "^2.1.5",
51
51
  "ajv": "^8.17.1",
52
52
  "ajv-formats": "^3.0.1",
53
53
  "commander": "^11.1.0",