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 +167 -114
- package/dist/schemas/prpm-manifest.schema.json +727 -0
- package/package.json +4 -4
- package/schemas/prpm-manifest.schema.json +6 -2
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
|
|
4637
|
-
const schemaContent = (0, import_fs8.readFileSync)(
|
|
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
|
-
|
|
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
|
-
|
|
7218
|
-
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
|
|
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
|
-
|
|
7224
|
-
|
|
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
|
-
|
|
7233
|
-
|
|
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", "
|
|
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
|
|
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
|
-
|
|
10122
|
-
|
|
10123
|
-
|
|
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
|
|
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,
|
|
10225
|
-
const text = await (0,
|
|
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
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
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,
|
|
14193
|
+
await (0, import_promises8.mkdir)(outputDir, { recursive: true });
|
|
14141
14194
|
console.log(import_chalk.default.dim("Writing converted file..."));
|
|
14142
|
-
await (0,
|
|
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") {
|