prpm 1.0.1 → 1.0.3

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,8 @@ function loadSchema(format, subtype) {
4633
4633
  };
4634
4634
  schemaFilename = schemaMap[format] || `${format}.schema.json`;
4635
4635
  }
4636
- const schemaPath2 = (0, import_path7.join)(currentDirname, "..", "schemas", schemaFilename);
4637
- const schemaContent = (0, import_fs8.readFileSync)(schemaPath2, "utf-8");
4636
+ const schemaPath = (0, import_path7.join)(currentDirname, "..", "schemas", schemaFilename);
4637
+ const schemaContent = (0, import_fs8.readFileSync)(schemaPath, "utf-8");
4638
4638
  const schema3 = JSON.parse(schemaContent);
4639
4639
  const compiled = ajv.compile(schema3);
4640
4640
  schemaCache.set(cacheKey, compiled);
@@ -6730,6 +6730,7 @@ async function handleInstall(packageSpec, options) {
6730
6730
  packageId = parts[0];
6731
6731
  specVersion = parts[1];
6732
6732
  }
6733
+ const config = await getConfig();
6733
6734
  const lockfile = await readLockfile();
6734
6735
  const lockedVersion = getLockedVersion(lockfile, packageId);
6735
6736
  let version;
@@ -6741,10 +6742,15 @@ async function handleInstall(packageSpec, options) {
6741
6742
  } else {
6742
6743
  version = options.version || specVersion || lockedVersion || "latest";
6743
6744
  }
6745
+ let targetFormat = options.as;
6746
+ if (!targetFormat) {
6747
+ targetFormat = config.defaultFormat || await autoDetectFormat() || void 0;
6748
+ }
6744
6749
  if (!options.force && lockfile && lockfile.packages[packageId]) {
6745
6750
  const installedPkg = lockfile.packages[packageId];
6746
6751
  const requestedVersion = options.version || specVersion;
6747
- if (!requestedVersion || requestedVersion === "latest" || requestedVersion === installedPkg.version) {
6752
+ const sameFormat = !targetFormat || installedPkg.format === targetFormat;
6753
+ if (sameFormat && (!requestedVersion || requestedVersion === "latest" || requestedVersion === installedPkg.version)) {
6748
6754
  console.log(`
6749
6755
  \u2728 Package already installed!`);
6750
6756
  console.log(` \u{1F4E6} ${packageId}@${installedPkg.version}`);
@@ -6753,14 +6759,16 @@ async function handleInstall(packageSpec, options) {
6753
6759
  \u{1F4A1} To reinstall or upgrade:`);
6754
6760
  console.log(` prpm upgrade ${packageId} # Upgrade to latest version`);
6755
6761
  console.log(` prpm uninstall ${packageId} # Uninstall first, then install`);
6762
+ console.log(` prpm install ${packageId} --as <format> # Install in different format`);
6756
6763
  success = true;
6757
6764
  return;
6765
+ } else if (!sameFormat) {
6766
+ console.log(`\u{1F4E6} Installing ${packageId} in ${targetFormat} format (already have ${installedPkg.format} version)`);
6758
6767
  } else if (requestedVersion !== installedPkg.version) {
6759
6768
  console.log(`\u{1F4E6} Upgrading ${packageId}: ${installedPkg.version} \u2192 ${requestedVersion}`);
6760
6769
  }
6761
6770
  }
6762
6771
  console.log(`\u{1F4E5} Installing ${packageId}@${version}...`);
6763
- const config = await getConfig();
6764
6772
  const client = (0, import_registry_client5.getRegistryClient)(config);
6765
6773
  let isCollection = false;
6766
6774
  try {
@@ -7210,65 +7218,90 @@ ${afterFrontmatter}`;
7210
7218
  }
7211
7219
  }
7212
7220
  async function extractTarball(tarball, packageId) {
7213
- const files = [];
7214
7221
  const zlib = await import("zlib");
7215
- const fs9 = await import("fs");
7222
+ const fs9 = await import("fs/promises");
7216
7223
  const os2 = await import("os");
7217
- return new Promise((resolve2, reject) => {
7218
- zlib.gunzip(tarball, async (err, result) => {
7219
- if (err) {
7220
- reject(err);
7221
- return;
7224
+ const fallback = (buffer) => [
7225
+ {
7226
+ name: `${packageId}.md`,
7227
+ content: buffer.toString("utf-8")
7228
+ }
7229
+ ];
7230
+ let decompressed;
7231
+ try {
7232
+ decompressed = await new Promise((resolve2, reject) => {
7233
+ zlib.gunzip(tarball, (err, result) => {
7234
+ if (err) {
7235
+ reject(err);
7236
+ return;
7237
+ }
7238
+ resolve2(result);
7239
+ });
7240
+ });
7241
+ } catch (error) {
7242
+ throw error;
7243
+ }
7244
+ const tmpDir = await fs9.mkdtemp(import_path8.default.join(os2.tmpdir(), "prpm-"));
7245
+ const cleanup = async () => {
7246
+ try {
7247
+ await fs9.rm(tmpDir, { recursive: true, force: true });
7248
+ } catch {
7249
+ }
7250
+ };
7251
+ const excludedNames = /* @__PURE__ */ new Set([
7252
+ "prpm.json",
7253
+ "README",
7254
+ "README.md",
7255
+ "README.txt",
7256
+ "LICENSE",
7257
+ "LICENSE.txt",
7258
+ "LICENSE.md"
7259
+ ]);
7260
+ try {
7261
+ const extract2 = tar.extract({
7262
+ cwd: tmpDir,
7263
+ strict: false
7264
+ });
7265
+ await (0, import_promises.pipeline)(import_stream.Readable.from(decompressed), extract2);
7266
+ const extractedFiles = await collectExtractedFiles(tmpDir, excludedNames, fs9);
7267
+ if (extractedFiles.length === 0) {
7268
+ return fallback(decompressed);
7269
+ }
7270
+ return extractedFiles;
7271
+ } catch {
7272
+ return fallback(decompressed);
7273
+ } finally {
7274
+ await cleanup();
7275
+ }
7276
+ }
7277
+ async function collectExtractedFiles(rootDir, excludedNames, fs9) {
7278
+ const files = [];
7279
+ const dirs = [rootDir];
7280
+ while (dirs.length > 0) {
7281
+ const currentDir = dirs.pop();
7282
+ if (!currentDir) continue;
7283
+ const entries = await fs9.readdir(currentDir, { withFileTypes: true });
7284
+ for (const entry of entries) {
7285
+ const fullPath = import_path8.default.join(currentDir, entry.name);
7286
+ if (entry.isDirectory()) {
7287
+ dirs.push(fullPath);
7288
+ continue;
7222
7289
  }
7223
- const isTar = result.length > 257 && result.toString("utf-8", 257, 262) === "ustar";
7224
- if (!isTar) {
7225
- files.push({
7226
- name: `${packageId}.md`,
7227
- content: result.toString("utf-8")
7228
- });
7229
- resolve2(files);
7230
- return;
7290
+ if (!entry.isFile()) {
7291
+ continue;
7231
7292
  }
7232
- const tmpDir = await fs9.promises.mkdtemp(import_path8.default.join(os2.tmpdir(), "prpm-"));
7233
- try {
7234
- const tarPath = import_path8.default.join(tmpDir, "package.tar");
7235
- await fs9.promises.writeFile(tarPath, result);
7236
- await tar.extract({
7237
- file: tarPath,
7238
- cwd: tmpDir
7239
- });
7240
- const extractedFiles = await fs9.promises.readdir(tmpDir, { withFileTypes: true, recursive: true });
7241
- const excludeFiles = ["package.tar", "prpm.json", "README.md", "LICENSE", "LICENSE.txt", "LICENSE.md"];
7242
- for (const entry of extractedFiles) {
7243
- if (entry.isFile() && !excludeFiles.includes(entry.name)) {
7244
- const filePath = import_path8.default.join(entry.path || tmpDir, entry.name);
7245
- const content = await fs9.promises.readFile(filePath, "utf-8");
7246
- const relativePath = import_path8.default.relative(tmpDir, filePath);
7247
- files.push({
7248
- name: relativePath,
7249
- content
7250
- });
7251
- }
7252
- }
7253
- if (files.length === 0) {
7254
- files.push({
7255
- name: `${packageId}.md`,
7256
- content: result.toString("utf-8")
7257
- });
7258
- }
7259
- await fs9.promises.rm(tmpDir, { recursive: true, force: true });
7260
- resolve2(files);
7261
- } catch (tarErr) {
7262
- await fs9.promises.rm(tmpDir, { recursive: true, force: true }).catch(() => {
7263
- });
7264
- files.push({
7265
- name: `${packageId}.md`,
7266
- content: result.toString("utf-8")
7267
- });
7268
- resolve2(files);
7293
+ if (excludedNames.has(entry.name)) {
7294
+ continue;
7269
7295
  }
7270
- });
7271
- });
7296
+ const content = await fs9.readFile(fullPath, "utf-8");
7297
+ const relativePath = import_path8.default.relative(rootDir, fullPath).split(import_path8.default.sep).join("/");
7298
+ files.push({
7299
+ name: relativePath,
7300
+ content
7301
+ });
7302
+ }
7303
+ }
7304
+ return files;
7272
7305
  }
7273
7306
  async function installFromLockfile(options) {
7274
7307
  var _a;
@@ -7362,7 +7395,7 @@ function createInstallCommand() {
7362
7395
  });
7363
7396
  return command;
7364
7397
  }
7365
- var import_commander10, import_registry_client5, tar, import_path8;
7398
+ var import_commander10, import_registry_client5, import_stream, import_promises, tar, import_path8;
7366
7399
  var init_install = __esm({
7367
7400
  "src/commands/install.ts"() {
7368
7401
  "use strict";
@@ -7372,6 +7405,8 @@ var init_install = __esm({
7372
7405
  init_user_config();
7373
7406
  init_filesystem();
7374
7407
  init_telemetry();
7408
+ import_stream = require("stream");
7409
+ import_promises = require("stream/promises");
7375
7410
  tar = __toESM(require("tar"));
7376
7411
  init_errors();
7377
7412
  init_prompts();
@@ -9485,12 +9520,12 @@ async function handleTrending(options) {
9485
9520
  }
9486
9521
  function createTrendingCommand() {
9487
9522
  const command = new import_commander5.Command("trending");
9488
- 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) => {
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, chatmode, hook)").option("--limit <number>", "Number of packages to show", "10").action(async (options) => {
9489
9524
  const format = options.format;
9490
9525
  const subtype = options.subtype;
9491
9526
  const limit = options.limit ? parseInt(options.limit, 10) : 10;
9492
9527
  const validFormats = ["cursor", "claude", "continue", "windsurf", "copilot", "kiro", "agents.md", "generic", "mcp"];
9493
- const validSubtypes = ["rule", "agent", "skill", "slash-command", "prompt", "workflow", "tool", "template", "collection"];
9528
+ const validSubtypes = ["rule", "agent", "skill", "slash-command", "prompt", "workflow", "tool", "template", "collection", "chatmode", "hook"];
9494
9529
  if (options.format && !validFormats.includes(format)) {
9495
9530
  console.error(`\u274C Format must be one of: ${validFormats.join(", ")}`);
9496
9531
  throw new CLIError(`\u274C Format must be one of: ${validFormats.join(", ")}`, 1);
@@ -9513,7 +9548,7 @@ async function handlePopular(options) {
9513
9548
  });
9514
9549
  }
9515
9550
  function createPopularCommand() {
9516
- 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) => {
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, chatmode, hook)").action(async (options) => {
9517
9552
  await handlePopular(options);
9518
9553
  });
9519
9554
  }
@@ -9836,7 +9871,7 @@ function createSearchCommand() {
9836
9871
  const limit = options.limit ? parseInt(options.limit, 10) : 20;
9837
9872
  const page = options.page ? parseInt(options.page, 10) : 1;
9838
9873
  const validFormats = ["cursor", "claude", "continue", "windsurf", "copilot", "kiro", "agents.md", "generic", "mcp"];
9839
- const validSubtypes = ["rule", "agent", "skill", "slash-command", "prompt", "collection", "chatmode", "tool", "hook"];
9874
+ const validSubtypes = ["rule", "agent", "skill", "slash-command", "prompt", "workflow", "tool", "template", "collection", "chatmode", "hook"];
9840
9875
  if (options.format && !validFormats.includes(format)) {
9841
9876
  console.error(`\u274C Format must be one of: ${validFormats.join(", ")}`);
9842
9877
  throw new CLIError(`\u274C Format must be one of: ${validFormats.join(", ")}`, 1);
@@ -9940,7 +9975,7 @@ init_install();
9940
9975
  // src/commands/publish.ts
9941
9976
  init_cjs_shims();
9942
9977
  var import_commander11 = require("commander");
9943
- var import_promises4 = require("fs/promises");
9978
+ var import_promises5 = require("fs/promises");
9944
9979
  var import_path12 = require("path");
9945
9980
  var tar2 = __toESM(require("tar"));
9946
9981
  var import_os3 = require("os");
@@ -10116,11 +10151,23 @@ var import_ajv2 = __toESM(require("ajv"));
10116
10151
  var import_ajv_formats2 = __toESM(require("ajv-formats"));
10117
10152
  var import_fs9 = require("fs");
10118
10153
  var import_path9 = require("path");
10119
- var schemaPath = (0, import_path9.join)(__dirname, "../../schemas/prpm-manifest.schema.json");
10120
10154
  var schema2;
10121
- try {
10122
- schema2 = JSON.parse((0, import_fs9.readFileSync)(schemaPath, "utf-8"));
10123
- } catch (error) {
10155
+ var schemaCandidates = [
10156
+ // Source file layout (src/core → ../../schemas)
10157
+ (0, import_path9.join)(__dirname, "../../schemas/prpm-manifest.schema.json"),
10158
+ // Bundled layout (dist/index.js → ../schemas)
10159
+ (0, import_path9.join)(__dirname, "../schemas/prpm-manifest.schema.json")
10160
+ ];
10161
+ for (const candidate of schemaCandidates) {
10162
+ try {
10163
+ if ((0, import_fs9.existsSync)(candidate)) {
10164
+ schema2 = JSON.parse((0, import_fs9.readFileSync)(candidate, "utf-8"));
10165
+ break;
10166
+ }
10167
+ } catch {
10168
+ }
10169
+ }
10170
+ if (!schema2) {
10124
10171
  console.warn("\u26A0\uFE0F Could not load manifest schema, skipping schema validation");
10125
10172
  }
10126
10173
  function validateManifestSchema(manifest) {
@@ -10168,7 +10215,7 @@ function getManifestSchema() {
10168
10215
 
10169
10216
  // src/utils/license-extractor.ts
10170
10217
  init_cjs_shims();
10171
- var import_promises = require("fs/promises");
10218
+ var import_promises2 = require("fs/promises");
10172
10219
  var import_path10 = require("path");
10173
10220
  var import_fs10 = require("fs");
10174
10221
  var LICENSE_FILE_PATTERNS = [
@@ -10221,8 +10268,8 @@ async function extractLicenseInfo(repositoryUrl) {
10221
10268
  for (const fileName of LICENSE_FILE_PATTERNS) {
10222
10269
  const filePath = (0, import_path10.join)(cwd, fileName);
10223
10270
  try {
10224
- await (0, import_promises.access)(filePath, import_fs10.constants.R_OK);
10225
- const text = await (0, import_promises.readFile)(filePath, "utf-8");
10271
+ await (0, import_promises2.access)(filePath, import_fs10.constants.R_OK);
10272
+ const text = await (0, import_promises2.readFile)(filePath, "utf-8");
10226
10273
  const type2 = detectLicenseType(text);
10227
10274
  const url = generateLicenseUrl(repositoryUrl, fileName);
10228
10275
  return {
@@ -10254,7 +10301,7 @@ function validateLicenseInfo(licenseInfo, packageName) {
10254
10301
 
10255
10302
  // src/utils/snippet-extractor.ts
10256
10303
  init_cjs_shims();
10257
- var import_promises2 = require("fs/promises");
10304
+ var import_promises3 = require("fs/promises");
10258
10305
  var import_path11 = require("path");
10259
10306
  var MAX_SNIPPET_LENGTH = 2e3;
10260
10307
  async function extractSnippet(manifest) {
@@ -10272,12 +10319,12 @@ async function extractSnippet(manifest) {
10272
10319
  fileName = typeof firstFile === "string" ? firstFile : firstFile.path;
10273
10320
  }
10274
10321
  const fullPath = (0, import_path11.join)(cwd, fileName);
10275
- const stats = await (0, import_promises2.stat)(fullPath);
10322
+ const stats = await (0, import_promises3.stat)(fullPath);
10276
10323
  if (stats.isDirectory()) {
10277
10324
  console.warn(`\u26A0\uFE0F Skipping snippet extraction: "${fullPath}" is a directory`);
10278
10325
  return null;
10279
10326
  }
10280
- const content = await (0, import_promises2.readFile)(fullPath, "utf-8");
10327
+ const content = await (0, import_promises3.readFile)(fullPath, "utf-8");
10281
10328
  if (content.length <= MAX_SNIPPET_LENGTH) {
10282
10329
  return content.trim();
10283
10330
  }
@@ -10360,7 +10407,7 @@ async function executePrepublishOnly(scripts, options = {}) {
10360
10407
 
10361
10408
  // src/utils/format-file-validator.ts
10362
10409
  init_cjs_shims();
10363
- var import_promises3 = require("fs/promises");
10410
+ var import_promises4 = require("fs/promises");
10364
10411
  function normalizeFilePaths(files) {
10365
10412
  return files.map((file) => {
10366
10413
  if (typeof file === "string") {
@@ -10388,7 +10435,7 @@ function getFormatType(format, subtype) {
10388
10435
  async function validateMarkdownFile(filePath, formatType) {
10389
10436
  try {
10390
10437
  const { validateMarkdown: validateMarkdown2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
10391
- const content = await (0, import_promises3.readFile)(filePath, "utf-8");
10438
+ const content = await (0, import_promises4.readFile)(filePath, "utf-8");
10392
10439
  const result = validateMarkdown2(formatType, content);
10393
10440
  return {
10394
10441
  valid: result.valid,
@@ -10494,7 +10541,7 @@ async function findAndLoadManifests() {
10494
10541
  let prpmJsonExists = false;
10495
10542
  let prpmJsonError = null;
10496
10543
  try {
10497
- const content = await (0, import_promises4.readFile)(prpmJsonPath, "utf-8");
10544
+ const content = await (0, import_promises5.readFile)(prpmJsonPath, "utf-8");
10498
10545
  prpmJsonExists = true;
10499
10546
  const manifest = JSON.parse(content);
10500
10547
  const collections = [];
@@ -10526,14 +10573,15 @@ async function findAndLoadManifests() {
10526
10573
  engines: pkg.engines,
10527
10574
  main: pkg.main
10528
10575
  };
10529
- return validateManifest(packageWithDefaults);
10576
+ const label = pkg.name || `package #${idx + 1}`;
10577
+ return validateManifest(packageWithDefaults, label);
10530
10578
  });
10531
10579
  return { manifests: validatedManifests, collections, source: "prpm.json (multi-package)" };
10532
10580
  }
10533
10581
  if (collections.length > 0) {
10534
10582
  return { manifests: [], collections, source: "prpm.json (collections-only)" };
10535
10583
  }
10536
- const validated = validateManifest(manifest);
10584
+ const validated = validateManifest(manifest, manifest.name);
10537
10585
  return { manifests: [validated], collections, source: "prpm.json" };
10538
10586
  } catch (error) {
10539
10587
  prpmJsonError = error;
@@ -10543,7 +10591,7 @@ async function findAndLoadManifests() {
10543
10591
  }
10544
10592
  const marketplaceJsonPath = (0, import_path12.join)(process.cwd(), ".claude", "marketplace.json");
10545
10593
  try {
10546
- const content = await (0, import_promises4.readFile)(marketplaceJsonPath, "utf-8");
10594
+ const content = await (0, import_promises5.readFile)(marketplaceJsonPath, "utf-8");
10547
10595
  const marketplaceData = JSON.parse(content);
10548
10596
  if (!validateMarketplaceJson(marketplaceData)) {
10549
10597
  throw new Error("Invalid marketplace.json format");
@@ -10551,7 +10599,7 @@ async function findAndLoadManifests() {
10551
10599
  const manifests = [];
10552
10600
  for (let i = 0; i < marketplaceData.plugins.length; i++) {
10553
10601
  const manifest = marketplaceToManifest(marketplaceData, i);
10554
- const validated = validateManifest(manifest);
10602
+ const validated = validateManifest(manifest, manifest.name);
10555
10603
  manifests.push(validated);
10556
10604
  }
10557
10605
  return { manifests, collections: [], source: ".claude/marketplace.json" };
@@ -10559,7 +10607,7 @@ async function findAndLoadManifests() {
10559
10607
  }
10560
10608
  const marketplaceJsonPluginPath = (0, import_path12.join)(process.cwd(), ".claude-plugin", "marketplace.json");
10561
10609
  try {
10562
- const content = await (0, import_promises4.readFile)(marketplaceJsonPluginPath, "utf-8");
10610
+ const content = await (0, import_promises5.readFile)(marketplaceJsonPluginPath, "utf-8");
10563
10611
  const marketplaceData = JSON.parse(content);
10564
10612
  if (!validateMarketplaceJson(marketplaceData)) {
10565
10613
  throw new Error("Invalid marketplace.json format");
@@ -10567,7 +10615,7 @@ async function findAndLoadManifests() {
10567
10615
  const manifests = [];
10568
10616
  for (let i = 0; i < marketplaceData.plugins.length; i++) {
10569
10617
  const manifest = marketplaceToManifest(marketplaceData, i);
10570
- const validated = validateManifest(manifest);
10618
+ const validated = validateManifest(manifest, manifest.name);
10571
10619
  manifests.push(validated);
10572
10620
  }
10573
10621
  return { manifests, collections: [], source: ".claude-plugin/marketplace.json" };
@@ -10577,15 +10625,17 @@ async function findAndLoadManifests() {
10577
10625
  "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)"
10578
10626
  );
10579
10627
  }
10580
- function validateManifest(manifest) {
10628
+ function validateManifest(manifest, contextLabel) {
10581
10629
  var _a;
10630
+ const context = contextLabel || manifest.name || "manifest";
10631
+ const prefix = `[${context}] `;
10582
10632
  if (!manifest.subtype) {
10583
10633
  manifest.subtype = "rule";
10584
10634
  }
10585
10635
  const schemaValidation = validateManifestSchema(manifest);
10586
10636
  if (!schemaValidation.valid) {
10587
10637
  const errorMessages = ((_a = schemaValidation.errors) == null ? void 0 : _a.join("\n - ")) || "Unknown validation error";
10588
- throw new Error(`Manifest validation failed:
10638
+ throw new Error(`${prefix}Manifest validation failed:
10589
10639
  - ${errorMessages}`);
10590
10640
  }
10591
10641
  const hasEnhancedFormat = manifest.files.some((f) => typeof f === "object");
@@ -10594,7 +10644,7 @@ function validateManifest(manifest) {
10594
10644
  manifest.files.filter((f) => typeof f === "object").map((f) => f.format)
10595
10645
  );
10596
10646
  if (fileFormats.size > 1 && manifest.subtype !== "collection") {
10597
- console.warn('\u26A0\uFE0F Package contains multiple file formats. Consider setting subtype to "collection" for clarity.');
10647
+ console.warn(`${prefix}\u26A0\uFE0F Package contains multiple file formats. Consider setting subtype to "collection" for clarity.`);
10598
10648
  }
10599
10649
  }
10600
10650
  if (manifest.format === "claude" && manifest.subtype === "skill") {
@@ -10602,39 +10652,42 @@ function validateManifest(manifest) {
10602
10652
  const hasSkillMd = filePaths.some((path7) => path7.endsWith("/SKILL.md") || path7 === "SKILL.md");
10603
10653
  if (!hasSkillMd) {
10604
10654
  throw new Error(
10605
- "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."
10655
+ `${prefix}Claude skills must contain a SKILL.md file.
10656
+ According to Claude documentation at https://docs.claude.com/en/docs/claude-code/skills,
10657
+ skills must have a file named SKILL.md in their directory.
10658
+ Please rename your skill file to SKILL.md (all caps) and update your prpm.json files array.`
10606
10659
  );
10607
10660
  }
10608
10661
  if (manifest.name.length > 64) {
10609
10662
  throw new Error(
10610
- `Claude skill name "${manifest.name}" exceeds 64 character limit (${manifest.name.length} characters).
10663
+ `${prefix}Claude skill name "${manifest.name}" exceeds 64 character limit (${manifest.name.length} characters).
10611
10664
  According to Claude documentation, skill names must be max 64 characters.
10612
10665
  Please shorten your package name.`
10613
10666
  );
10614
10667
  }
10615
10668
  if (!/^[a-z0-9-]+$/.test(manifest.name)) {
10616
10669
  throw new Error(
10617
- `Claude skill name "${manifest.name}" contains invalid characters.
10670
+ `${prefix}Claude skill name "${manifest.name}" contains invalid characters.
10618
10671
  According to Claude documentation, skill names must use lowercase letters, numbers, and hyphens only.
10619
10672
  Please update your package name.`
10620
10673
  );
10621
10674
  }
10622
10675
  if (manifest.description.length > 1024) {
10623
10676
  throw new Error(
10624
- `Claude skill description exceeds 1024 character limit (${manifest.description.length} characters).
10677
+ `${prefix}Claude skill description exceeds 1024 character limit (${manifest.description.length} characters).
10625
10678
  According to Claude documentation, skill descriptions must be max 1024 characters.
10626
10679
  Please shorten your description.`
10627
10680
  );
10628
10681
  }
10629
10682
  if (manifest.description.length > 819) {
10630
10683
  console.warn(
10631
- `\u26A0\uFE0F Warning: Skill description is ${manifest.description.length}/1024 characters (${Math.round(manifest.description.length / 1024 * 100)}% of limit).
10684
+ `${prefix}\u26A0\uFE0F Warning: Skill description is ${manifest.description.length}/1024 characters (${Math.round(manifest.description.length / 1024 * 100)}% of limit).
10632
10685
  Consider keeping it concise for better discoverability.`
10633
10686
  );
10634
10687
  }
10635
10688
  if (manifest.description.length < 100) {
10636
10689
  console.warn(
10637
- `\u26A0\uFE0F Warning: Skill description is only ${manifest.description.length} characters.
10690
+ `${prefix}\u26A0\uFE0F Warning: Skill description is only ${manifest.description.length} characters.
10638
10691
  Claude uses descriptions for skill discovery - consider adding more detail about:
10639
10692
  - What the skill does
10640
10693
  - When Claude should use it
@@ -10672,7 +10725,7 @@ async function createTarball(manifest) {
10672
10725
  const tmpDir = (0, import_path12.join)((0, import_os3.tmpdir)(), `prpm-${(0, import_crypto2.randomBytes)(8).toString("hex")}`);
10673
10726
  const tarballPath = (0, import_path12.join)(tmpDir, "package.tar.gz");
10674
10727
  try {
10675
- await (0, import_promises4.mkdir)(tmpDir, { recursive: true });
10728
+ await (0, import_promises5.mkdir)(tmpDir, { recursive: true });
10676
10729
  const filePaths = normalizeFilePaths2(manifest.files);
10677
10730
  const standardFiles = ["prpm.json", "README.md", "LICENSE"];
10678
10731
  for (const file of standardFiles) {
@@ -10683,7 +10736,7 @@ async function createTarball(manifest) {
10683
10736
  const existingFiles = [];
10684
10737
  for (const file of filePaths) {
10685
10738
  try {
10686
- await (0, import_promises4.stat)(file);
10739
+ await (0, import_promises5.stat)(file);
10687
10740
  existingFiles.push(file);
10688
10741
  } catch {
10689
10742
  }
@@ -10699,7 +10752,7 @@ async function createTarball(manifest) {
10699
10752
  },
10700
10753
  existingFiles
10701
10754
  );
10702
- const tarballBuffer = await (0, import_promises4.readFile)(tarballPath);
10755
+ const tarballBuffer = await (0, import_promises5.readFile)(tarballPath);
10703
10756
  const sizeMB = tarballBuffer.length / (1024 * 1024);
10704
10757
  if (sizeMB > 10) {
10705
10758
  throw new Error(`Package size (${sizeMB.toFixed(2)}MB) exceeds 10MB limit`);
@@ -10709,7 +10762,7 @@ async function createTarball(manifest) {
10709
10762
  throw error;
10710
10763
  } finally {
10711
10764
  try {
10712
- await (0, import_promises4.rm)(tmpDir, { recursive: true, force: true });
10765
+ await (0, import_promises5.rm)(tmpDir, { recursive: true, force: true });
10713
10766
  } catch {
10714
10767
  }
10715
10768
  }
@@ -10732,7 +10785,7 @@ async function handlePublish(options) {
10732
10785
  if (source === "prpm.json (multi-package)" || source === "prpm.json") {
10733
10786
  try {
10734
10787
  const prpmJsonPath = (0, import_path12.join)(process.cwd(), "prpm.json");
10735
- const prpmContent = await (0, import_promises4.readFile)(prpmJsonPath, "utf-8");
10788
+ const prpmContent = await (0, import_promises5.readFile)(prpmJsonPath, "utf-8");
10736
10789
  const prpmManifest = JSON.parse(prpmContent);
10737
10790
  if (prpmManifest.scripts) {
10738
10791
  await executePrepublishOnly(prpmManifest.scripts);
@@ -11722,7 +11775,7 @@ function createSchemaCommand() {
11722
11775
  // src/commands/init.ts
11723
11776
  init_cjs_shims();
11724
11777
  var import_commander18 = require("commander");
11725
- var import_promises5 = require("fs/promises");
11778
+ var import_promises6 = require("fs/promises");
11726
11779
  var import_path13 = require("path");
11727
11780
  var import_fs11 = require("fs");
11728
11781
  var readline3 = __toESM(require("readline/promises"));
@@ -12029,7 +12082,7 @@ ${question}`);
12029
12082
  }
12030
12083
  async function extractMetadataFromFile(filePath) {
12031
12084
  try {
12032
- const content = await (0, import_promises5.readFile)(filePath, "utf-8");
12085
+ const content = await (0, import_promises6.readFile)(filePath, "utf-8");
12033
12086
  const metadata = {};
12034
12087
  const frontmatterMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
12035
12088
  if (frontmatterMatch) {
@@ -12094,7 +12147,7 @@ async function createExampleFiles(format, files, packageName) {
12094
12147
  const filePath = (0, import_path13.join)(process.cwd(), file);
12095
12148
  const dirPath = (0, import_path13.join)(filePath, "..");
12096
12149
  if (!(0, import_fs11.existsSync)(dirPath)) {
12097
- await (0, import_promises5.mkdir)(dirPath, { recursive: true });
12150
+ await (0, import_promises6.mkdir)(dirPath, { recursive: true });
12098
12151
  }
12099
12152
  if ((0, import_fs11.existsSync)(filePath)) {
12100
12153
  console.log(` Skipping ${file} (already exists)`);
@@ -12105,7 +12158,7 @@ async function createExampleFiles(format, files, packageName) {
12105
12158
  Add your content here.
12106
12159
  `;
12107
12160
  content = content.replace(/example-skill/g, packageName);
12108
- await (0, import_promises5.writeFile)(filePath, content, "utf-8");
12161
+ await (0, import_promises6.writeFile)(filePath, content, "utf-8");
12109
12162
  console.log(` Created ${file}`);
12110
12163
  }
12111
12164
  }
@@ -12141,7 +12194,7 @@ ${config.author}
12141
12194
 
12142
12195
  ${config.license}
12143
12196
  `;
12144
- await (0, import_promises5.writeFile)(readmePath, content, "utf-8");
12197
+ await (0, import_promises6.writeFile)(readmePath, content, "utf-8");
12145
12198
  console.log(" Created README.md");
12146
12199
  }
12147
12200
  async function initPackage(options) {
@@ -12298,7 +12351,7 @@ Current files (${config.files.length}):`);
12298
12351
  manifest.tags = config.tags;
12299
12352
  }
12300
12353
  manifest.files = config.files;
12301
- await (0, import_promises5.writeFile)(
12354
+ await (0, import_promises6.writeFile)(
12302
12355
  manifestPath,
12303
12356
  JSON.stringify(manifest, null, 2) + "\n",
12304
12357
  "utf-8"
@@ -12444,7 +12497,7 @@ function createConfigCommand() {
12444
12497
  // src/commands/catalog.ts
12445
12498
  init_cjs_shims();
12446
12499
  var import_commander20 = require("commander");
12447
- var import_promises6 = require("fs/promises");
12500
+ var import_promises7 = require("fs/promises");
12448
12501
  var import_path14 = require("path");
12449
12502
  init_telemetry();
12450
12503
  init_lockfile();
@@ -12503,7 +12556,7 @@ async function scanDirectory2(dirPath, baseDir, scanDir, maxDepth = 5, currentDe
12503
12556
  }
12504
12557
  const discovered = [];
12505
12558
  try {
12506
- const entries = await (0, import_promises6.readdir)(dirPath, { withFileTypes: true });
12559
+ const entries = await (0, import_promises7.readdir)(dirPath, { withFileTypes: true });
12507
12560
  for (const entry of entries) {
12508
12561
  const fullPath = (0, import_path14.join)(dirPath, entry.name);
12509
12562
  const relativePath = (0, import_path14.relative)(baseDir, fullPath);
@@ -12515,7 +12568,7 @@ async function scanDirectory2(dirPath, baseDir, scanDir, maxDepth = 5, currentDe
12515
12568
  discovered.push(...subDirPackages);
12516
12569
  } else if (entry.isFile() && (entry.name.endsWith(".md") || entry.name.endsWith(".mdc") || entry.name.endsWith(".txt"))) {
12517
12570
  try {
12518
- const content = await (0, import_promises6.readFile)(fullPath, "utf-8");
12571
+ const content = await (0, import_promises7.readFile)(fullPath, "utf-8");
12519
12572
  const packageInfo = detectPackageInfo(fullPath, content);
12520
12573
  if (packageInfo) {
12521
12574
  discovered.push({
@@ -12594,7 +12647,7 @@ async function handleCatalog(directories, options) {
12594
12647
  for (const dir of directories) {
12595
12648
  console.log(` Scanning ${dir}...`);
12596
12649
  try {
12597
- const dirStat = await (0, import_promises6.stat)(dir);
12650
+ const dirStat = await (0, import_promises7.stat)(dir);
12598
12651
  if (!dirStat.isDirectory()) {
12599
12652
  console.log(` \u26A0\uFE0F Skipping ${dir} (not a directory)`);
12600
12653
  continue;
@@ -12647,7 +12700,7 @@ async function handleCatalog(directories, options) {
12647
12700
  let manifest;
12648
12701
  if (options.append) {
12649
12702
  try {
12650
- const existingContent = await (0, import_promises6.readFile)(prpmJsonPath, "utf-8");
12703
+ const existingContent = await (0, import_promises7.readFile)(prpmJsonPath, "utf-8");
12651
12704
  const existing = JSON.parse(existingContent);
12652
12705
  if ("packages" in existing && Array.isArray(existing.packages)) {
12653
12706
  manifest = existing;
@@ -12682,7 +12735,7 @@ async function handleCatalog(directories, options) {
12682
12735
  let description = `${discovered.format} ${discovered.subtype}`;
12683
12736
  try {
12684
12737
  const firstFilePath = (0, import_path14.join)(process.cwd(), discovered.scanDir, discovered.files[0]);
12685
- const content = await (0, import_promises6.readFile)(firstFilePath, "utf-8");
12738
+ const content = await (0, import_promises7.readFile)(firstFilePath, "utf-8");
12686
12739
  const extractedDesc = extractDescription2(content);
12687
12740
  if (extractedDesc) {
12688
12741
  description = extractedDesc;
@@ -12702,7 +12755,7 @@ async function handleCatalog(directories, options) {
12702
12755
  manifest.packages.push(packageManifest);
12703
12756
  addedCount++;
12704
12757
  }
12705
- await (0, import_promises6.writeFile)(prpmJsonPath, JSON.stringify(manifest, null, 2) + "\n", "utf-8");
12758
+ await (0, import_promises7.writeFile)(prpmJsonPath, JSON.stringify(manifest, null, 2) + "\n", "utf-8");
12706
12759
  console.log(`
12707
12760
  \u2705 Updated ${prpmJsonPath}`);
12708
12761
  console.log(` Added ${addedCount} new package(s)`);
@@ -13931,7 +13984,7 @@ function createStarredCommand() {
13931
13984
  // src/commands/convert.ts
13932
13985
  init_cjs_shims();
13933
13986
  var import_commander26 = require("commander");
13934
- var import_promises7 = require("fs/promises");
13987
+ var import_promises8 = require("fs/promises");
13935
13988
  var import_path15 = require("path");
13936
13989
  var import_fs12 = require("fs");
13937
13990
  var import_readline = require("readline");
@@ -14037,7 +14090,7 @@ async function handleConvert(sourcePath, options) {
14037
14090
  console.log(import_chalk.default.dim("Reading source file..."));
14038
14091
  let content;
14039
14092
  try {
14040
- content = await (0, import_promises7.readFile)(sourcePath, "utf-8");
14093
+ content = await (0, import_promises8.readFile)(sourcePath, "utf-8");
14041
14094
  } catch (error) {
14042
14095
  throw new CLIError(`Failed to read source file: ${error.message}`);
14043
14096
  }
@@ -14137,9 +14190,9 @@ async function handleConvert(sourcePath, options) {
14137
14190
  }
14138
14191
  }
14139
14192
  const outputDir = (0, import_path15.dirname)(outputPath);
14140
- await (0, import_promises7.mkdir)(outputDir, { recursive: true });
14193
+ await (0, import_promises8.mkdir)(outputDir, { recursive: true });
14141
14194
  console.log(import_chalk.default.dim("Writing converted file..."));
14142
- await (0, import_promises7.writeFile)(outputPath, result.content, "utf-8");
14195
+ await (0, import_promises8.writeFile)(outputPath, result.content, "utf-8");
14143
14196
  console.log(import_chalk.default.green(`\u2713 Converted file written to ${outputPath}`));
14144
14197
  console.log();
14145
14198
  if (options.to === "cursor") {