prpm 0.0.11 → 0.0.12
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/__tests__/e2e/test-helpers.js +1 -1
- package/dist/commands/list.js +14 -5
- package/dist/commands/login.js +15 -4
- package/dist/commands/publish.js +101 -6
- package/dist/core/filesystem.js +13 -1
- package/dist/core/user-config.js +88 -22
- package/package.json +3 -3
- package/schemas/prpm-manifest.schema.json +58 -0
|
@@ -77,7 +77,7 @@ async function createMockCollection(testDir, id, packages) {
|
|
|
77
77
|
async function createMockConfig(configPath, options) {
|
|
78
78
|
const config = {
|
|
79
79
|
token: options.token || 'test-token-123',
|
|
80
|
-
registryUrl: options.registryUrl || 'http://localhost:
|
|
80
|
+
registryUrl: options.registryUrl || 'http://localhost:3111',
|
|
81
81
|
};
|
|
82
82
|
await (0, promises_1.mkdir)((0, path_1.join)(configPath, '..'), { recursive: true });
|
|
83
83
|
await (0, promises_1.writeFile)(configPath, JSON.stringify(config, null, 2));
|
package/dist/commands/list.js
CHANGED
|
@@ -40,6 +40,13 @@ function getDestinationDir(type) {
|
|
|
40
40
|
return '.prompts';
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Strip author namespace from package ID
|
|
45
|
+
*/
|
|
46
|
+
function stripAuthorNamespace(packageId) {
|
|
47
|
+
const parts = packageId.split('/');
|
|
48
|
+
return parts[parts.length - 1];
|
|
49
|
+
}
|
|
43
50
|
/**
|
|
44
51
|
* Find the actual file location for a package
|
|
45
52
|
*/
|
|
@@ -47,11 +54,13 @@ async function findPackageLocation(id, format, subtype) {
|
|
|
47
54
|
if (!format)
|
|
48
55
|
return null;
|
|
49
56
|
const baseDir = getDestinationDir(format);
|
|
57
|
+
// Strip author namespace to get actual package name used in file system
|
|
58
|
+
const packageName = stripAuthorNamespace(id);
|
|
50
59
|
// Try different file extensions based on format
|
|
51
60
|
const extensions = format === 'cursor' ? ['.mdc', '.md'] : ['.md'];
|
|
52
|
-
// Try direct file: <dir>/<
|
|
61
|
+
// Try direct file: <dir>/<packageName>.ext
|
|
53
62
|
for (const ext of extensions) {
|
|
54
|
-
const directPath = path_1.default.join(baseDir, `${
|
|
63
|
+
const directPath = path_1.default.join(baseDir, `${packageName}${ext}`);
|
|
55
64
|
try {
|
|
56
65
|
await fs_1.promises.access(directPath);
|
|
57
66
|
return directPath;
|
|
@@ -60,9 +69,9 @@ async function findPackageLocation(id, format, subtype) {
|
|
|
60
69
|
// File doesn't exist, continue
|
|
61
70
|
}
|
|
62
71
|
}
|
|
63
|
-
// Try subdirectory: <dir>/<
|
|
72
|
+
// Try subdirectory: <dir>/<packageName>/SKILL.md or <dir>/<packageName>/AGENT.md
|
|
64
73
|
if (subtype === 'skill') {
|
|
65
|
-
const skillPath = path_1.default.join(baseDir,
|
|
74
|
+
const skillPath = path_1.default.join(baseDir, packageName, 'SKILL.md');
|
|
66
75
|
try {
|
|
67
76
|
await fs_1.promises.access(skillPath);
|
|
68
77
|
return skillPath;
|
|
@@ -72,7 +81,7 @@ async function findPackageLocation(id, format, subtype) {
|
|
|
72
81
|
}
|
|
73
82
|
}
|
|
74
83
|
if (subtype === 'agent' || format === 'claude') {
|
|
75
|
-
const agentPath = path_1.default.join(baseDir,
|
|
84
|
+
const agentPath = path_1.default.join(baseDir, packageName, 'AGENT.md');
|
|
76
85
|
try {
|
|
77
86
|
await fs_1.promises.access(agentPath);
|
|
78
87
|
return agentPath;
|
package/dist/commands/login.js
CHANGED
|
@@ -140,10 +140,21 @@ async function loginWithOAuth(registryUrl) {
|
|
|
140
140
|
}
|
|
141
141
|
// Create the CLI auth URL with session token, callback, and userId
|
|
142
142
|
const callbackUrl = 'http://localhost:8765/callback';
|
|
143
|
-
// Determine webapp URL
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
:
|
|
143
|
+
// Determine webapp URL based on registry URL
|
|
144
|
+
let webappUrl;
|
|
145
|
+
if (registryUrl.includes('localhost') || registryUrl.includes('127.0.0.1')) {
|
|
146
|
+
// Local development: registry on port 3111, webapp on port 5173
|
|
147
|
+
webappUrl = registryUrl.replace(':3111', ':5173');
|
|
148
|
+
}
|
|
149
|
+
else if (registryUrl.includes('registry.prpm.dev')) {
|
|
150
|
+
// Production: always use prpm.dev webapp
|
|
151
|
+
webappUrl = 'https://prpm.dev';
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
// Custom registry: assume webapp is on same host without port
|
|
155
|
+
const url = new URL(registryUrl);
|
|
156
|
+
webappUrl = `${url.protocol}//${url.hostname}`;
|
|
157
|
+
}
|
|
147
158
|
const authUrl = `${webappUrl}/cli-auth?sessionToken=${encodeURIComponent(connectSessionToken)}&cliCallback=${encodeURIComponent(callbackUrl)}&userId=${encodeURIComponent(userId)}`;
|
|
148
159
|
console.log(` Please open this link in your browser to authenticate:`);
|
|
149
160
|
console.log(` ${authUrl}\n`);
|
package/dist/commands/publish.js
CHANGED
|
@@ -54,27 +54,88 @@ const snippet_extractor_1 = require("../utils/snippet-extractor");
|
|
|
54
54
|
/**
|
|
55
55
|
* Try to find and load manifest files
|
|
56
56
|
* Checks for:
|
|
57
|
-
* 1. prpm.json (native format) - returns single manifest
|
|
57
|
+
* 1. prpm.json (native format) - returns single manifest or array of packages
|
|
58
58
|
* 2. .claude/marketplace.json (Claude format) - returns all plugins as separate manifests
|
|
59
59
|
* 3. .claude-plugin/marketplace.json (Claude format - alternative location) - returns all plugins
|
|
60
60
|
*/
|
|
61
61
|
async function findAndLoadManifests() {
|
|
62
62
|
// Try prpm.json first (native format)
|
|
63
63
|
const prpmJsonPath = (0, path_1.join)(process.cwd(), 'prpm.json');
|
|
64
|
+
let prpmJsonExists = false;
|
|
65
|
+
let prpmJsonError = null;
|
|
64
66
|
try {
|
|
65
67
|
const content = await (0, promises_1.readFile)(prpmJsonPath, 'utf-8');
|
|
66
|
-
|
|
68
|
+
prpmJsonExists = true;
|
|
69
|
+
// Try to parse JSON
|
|
70
|
+
let manifest;
|
|
71
|
+
try {
|
|
72
|
+
manifest = JSON.parse(content);
|
|
73
|
+
}
|
|
74
|
+
catch (parseError) {
|
|
75
|
+
// JSON parse error - provide specific error message
|
|
76
|
+
const error = parseError;
|
|
77
|
+
throw new Error(`Invalid JSON in prpm.json:\n\n` +
|
|
78
|
+
`${error.message}\n\n` +
|
|
79
|
+
`Please check your prpm.json file for syntax errors:\n` +
|
|
80
|
+
` - Missing or extra commas\n` +
|
|
81
|
+
` - Unclosed quotes or brackets\n` +
|
|
82
|
+
` - Invalid JSON syntax\n\n` +
|
|
83
|
+
`You can validate your JSON at https://jsonlint.com/`);
|
|
84
|
+
}
|
|
85
|
+
// Check if this is a multi-package manifest
|
|
86
|
+
if ('packages' in manifest && Array.isArray(manifest.packages)) {
|
|
87
|
+
const multiManifest = manifest;
|
|
88
|
+
// Validate each package in the array
|
|
89
|
+
const validatedManifests = multiManifest.packages.map((pkg, idx) => {
|
|
90
|
+
// Inherit top-level fields if not specified in package - using explicit undefined checks
|
|
91
|
+
const packageWithDefaults = {
|
|
92
|
+
name: pkg.name,
|
|
93
|
+
version: pkg.version,
|
|
94
|
+
description: pkg.description,
|
|
95
|
+
format: pkg.format,
|
|
96
|
+
files: pkg.files,
|
|
97
|
+
author: pkg.author !== undefined ? pkg.author : multiManifest.author,
|
|
98
|
+
license: pkg.license !== undefined ? pkg.license : multiManifest.license,
|
|
99
|
+
repository: pkg.repository !== undefined ? pkg.repository : multiManifest.repository,
|
|
100
|
+
homepage: pkg.homepage !== undefined ? pkg.homepage : multiManifest.homepage,
|
|
101
|
+
documentation: pkg.documentation !== undefined ? pkg.documentation : multiManifest.documentation,
|
|
102
|
+
organization: pkg.organization !== undefined ? pkg.organization : multiManifest.organization,
|
|
103
|
+
private: pkg.private !== undefined ? pkg.private : multiManifest.private,
|
|
104
|
+
tags: pkg.tags !== undefined ? pkg.tags : multiManifest.tags,
|
|
105
|
+
keywords: pkg.keywords !== undefined ? pkg.keywords : multiManifest.keywords,
|
|
106
|
+
subtype: pkg.subtype,
|
|
107
|
+
dependencies: pkg.dependencies,
|
|
108
|
+
peerDependencies: pkg.peerDependencies,
|
|
109
|
+
engines: pkg.engines,
|
|
110
|
+
main: pkg.main,
|
|
111
|
+
};
|
|
112
|
+
// Debug: Log inheritance only if DEBUG env var is set
|
|
113
|
+
if (process.env.DEBUG) {
|
|
114
|
+
console.log(`\n🔍 Package ${pkg.name} inheritance:`);
|
|
115
|
+
console.log(` - Package-level private: ${pkg.private}`);
|
|
116
|
+
console.log(` - Top-level private: ${multiManifest.private}`);
|
|
117
|
+
console.log(` - Inherited private: ${packageWithDefaults.private}`);
|
|
118
|
+
console.log('');
|
|
119
|
+
}
|
|
120
|
+
return validateManifest(packageWithDefaults);
|
|
121
|
+
});
|
|
122
|
+
return { manifests: validatedManifests, source: 'prpm.json (multi-package)' };
|
|
123
|
+
}
|
|
124
|
+
// Single package manifest
|
|
67
125
|
const validated = validateManifest(manifest);
|
|
68
126
|
return { manifests: [validated], source: 'prpm.json' };
|
|
69
127
|
}
|
|
70
128
|
catch (error) {
|
|
71
|
-
//
|
|
72
|
-
|
|
129
|
+
// Store error for later
|
|
130
|
+
prpmJsonError = error;
|
|
131
|
+
// If it's a validation or parsing error, throw it immediately (don't try marketplace.json)
|
|
132
|
+
if (prpmJsonExists && error instanceof Error && (error.message.includes('Invalid JSON') ||
|
|
133
|
+
error.message.includes('Manifest validation failed') ||
|
|
73
134
|
error.message.includes('Claude skill') ||
|
|
74
135
|
error.message.includes('SKILL.md'))) {
|
|
75
136
|
throw error;
|
|
76
137
|
}
|
|
77
|
-
// Otherwise, prpm.json not found or
|
|
138
|
+
// Otherwise, prpm.json not found or other error, try marketplace.json
|
|
78
139
|
}
|
|
79
140
|
// Try .claude/marketplace.json (Claude format)
|
|
80
141
|
const marketplaceJsonPath = (0, path_1.join)(process.cwd(), '.claude', 'marketplace.json');
|
|
@@ -316,6 +377,39 @@ async function handlePublish(options) {
|
|
|
316
377
|
console.log(`${'='.repeat(60)}\n`);
|
|
317
378
|
}
|
|
318
379
|
try {
|
|
380
|
+
// Debug: Log access override logic only if DEBUG env var is set
|
|
381
|
+
if (process.env.DEBUG) {
|
|
382
|
+
console.log(`\n🔍 Before access override:`);
|
|
383
|
+
console.log(` - manifest.private: ${manifest.private}`);
|
|
384
|
+
console.log(` - options.access: ${options.access}`);
|
|
385
|
+
}
|
|
386
|
+
// Determine access level:
|
|
387
|
+
// 1. If --access flag is provided, it overrides manifest setting
|
|
388
|
+
// 2. Otherwise, use manifest setting (defaults to false/public if not specified)
|
|
389
|
+
let isPrivate;
|
|
390
|
+
if (options.access !== undefined) {
|
|
391
|
+
// CLI flag explicitly provided - use it
|
|
392
|
+
isPrivate = options.access === 'private';
|
|
393
|
+
if (process.env.DEBUG) {
|
|
394
|
+
console.log(` - Using CLI flag override: ${options.access}`);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
else {
|
|
398
|
+
// No CLI flag - use manifest setting
|
|
399
|
+
isPrivate = manifest.private || false;
|
|
400
|
+
if (process.env.DEBUG) {
|
|
401
|
+
console.log(` - Using manifest setting: ${isPrivate}`);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
if (process.env.DEBUG) {
|
|
405
|
+
console.log(` - calculated isPrivate: ${isPrivate}`);
|
|
406
|
+
}
|
|
407
|
+
// Update manifest with final private setting
|
|
408
|
+
manifest.private = isPrivate;
|
|
409
|
+
if (process.env.DEBUG) {
|
|
410
|
+
console.log(` - final manifest.private: ${manifest.private}`);
|
|
411
|
+
console.log('');
|
|
412
|
+
}
|
|
319
413
|
let selectedOrgId;
|
|
320
414
|
// Check if organization is specified in manifest
|
|
321
415
|
if (manifest.organization && userInfo) {
|
|
@@ -334,6 +428,7 @@ async function handlePublish(options) {
|
|
|
334
428
|
console.log(` Package: ${manifest.name}@${manifest.version}`);
|
|
335
429
|
console.log(` Format: ${manifest.format} | Subtype: ${manifest.subtype}`);
|
|
336
430
|
console.log(` Description: ${manifest.description}`);
|
|
431
|
+
console.log(` Access: ${manifest.private ? 'private' : 'public'}`);
|
|
337
432
|
if (selectedOrgId && userInfo) {
|
|
338
433
|
const selectedOrg = userInfo.organizations.find((org) => org.id === selectedOrgId);
|
|
339
434
|
console.log(` Publishing to: ${selectedOrg?.name || 'organization'}`);
|
|
@@ -512,7 +607,7 @@ async function handlePublish(options) {
|
|
|
512
607
|
function createPublishCommand() {
|
|
513
608
|
return new commander_1.Command('publish')
|
|
514
609
|
.description('Publish a package to the registry')
|
|
515
|
-
.option('--access <type>', 'Package access (public or private)
|
|
610
|
+
.option('--access <type>', 'Package access (public or private) - overrides manifest setting')
|
|
516
611
|
.option('--tag <tag>', 'NPM-style tag (e.g., latest, beta)', 'latest')
|
|
517
612
|
.option('--dry-run', 'Validate package without publishing')
|
|
518
613
|
.action(async (options) => {
|
package/dist/core/filesystem.js
CHANGED
|
@@ -17,8 +17,13 @@ const fs_1 = require("fs");
|
|
|
17
17
|
const path_1 = __importDefault(require("path"));
|
|
18
18
|
/**
|
|
19
19
|
* Get the destination directory for a package based on format and subtype
|
|
20
|
+
* @param format - Package format (cursor, claude, etc.)
|
|
21
|
+
* @param subtype - Package subtype (skill, agent, rule, etc.)
|
|
22
|
+
* @param name - Package name (optional, only needed for Claude skills which create subdirectories)
|
|
20
23
|
*/
|
|
21
24
|
function getDestinationDir(format, subtype, name) {
|
|
25
|
+
// Strip author namespace from package name to avoid nested directories
|
|
26
|
+
const packageName = stripAuthorNamespace(name);
|
|
22
27
|
switch (format) {
|
|
23
28
|
case 'cursor':
|
|
24
29
|
if (subtype === 'agent')
|
|
@@ -27,8 +32,11 @@ function getDestinationDir(format, subtype, name) {
|
|
|
27
32
|
return '.cursor/commands';
|
|
28
33
|
return '.cursor/rules';
|
|
29
34
|
case 'claude':
|
|
35
|
+
// Only create subdirectory for skills if name is provided
|
|
36
|
+
if (subtype === 'skill' && packageName)
|
|
37
|
+
return `.claude/skills/${packageName}`;
|
|
30
38
|
if (subtype === 'skill')
|
|
31
|
-
return
|
|
39
|
+
return '.claude/skills';
|
|
32
40
|
if (subtype === 'slash-command')
|
|
33
41
|
return '.claude/commands';
|
|
34
42
|
if (subtype === 'agent')
|
|
@@ -124,6 +132,10 @@ function generateId(filename) {
|
|
|
124
132
|
* stripAuthorNamespace('git-workflow-manager') // 'git-workflow-manager'
|
|
125
133
|
*/
|
|
126
134
|
function stripAuthorNamespace(packageId) {
|
|
135
|
+
// Handle undefined or empty string
|
|
136
|
+
if (!packageId) {
|
|
137
|
+
return '';
|
|
138
|
+
}
|
|
127
139
|
// Split by '/' and get the last segment (the actual package name)
|
|
128
140
|
const parts = packageId.split('/');
|
|
129
141
|
return parts[parts.length - 1];
|
package/dist/core/user-config.js
CHANGED
|
@@ -1,58 +1,124 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* User configuration management for ~/.prpmrc
|
|
3
|
+
* User configuration management for ~/.prpmrc and .prpmrc
|
|
4
4
|
* Stores global settings like registry URL and authentication token
|
|
5
|
+
* Supports both user-level (~/.prpmrc) and repository-level (.prpmrc) config
|
|
5
6
|
*/
|
|
6
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
8
|
exports.getConfig = getConfig;
|
|
8
9
|
exports.saveConfig = saveConfig;
|
|
10
|
+
exports.saveRepoConfig = saveRepoConfig;
|
|
11
|
+
exports.getRepoConfig = getRepoConfig;
|
|
12
|
+
exports.getUserConfig = getUserConfig;
|
|
9
13
|
exports.updateConfig = updateConfig;
|
|
10
14
|
exports.clearAuth = clearAuth;
|
|
11
15
|
exports.getRegistryUrl = getRegistryUrl;
|
|
12
16
|
const fs_1 = require("fs");
|
|
13
17
|
const path_1 = require("path");
|
|
14
18
|
const os_1 = require("os");
|
|
15
|
-
const
|
|
19
|
+
const USER_CONFIG_FILE = (0, path_1.join)((0, os_1.homedir)(), '.prpmrc');
|
|
20
|
+
const REPO_CONFIG_FILE = '.prpmrc';
|
|
16
21
|
const DEFAULT_REGISTRY_URL = 'https://registry.prpm.dev';
|
|
17
22
|
/**
|
|
18
|
-
*
|
|
23
|
+
* Load configuration from a file
|
|
19
24
|
*/
|
|
20
|
-
async function
|
|
25
|
+
async function loadConfigFile(filePath) {
|
|
21
26
|
try {
|
|
22
|
-
const data = await fs_1.promises.readFile(
|
|
23
|
-
|
|
24
|
-
// Allow environment variable to override registry URL
|
|
25
|
-
if (process.env.PRPM_REGISTRY_URL) {
|
|
26
|
-
config.registryUrl = process.env.PRPM_REGISTRY_URL;
|
|
27
|
-
}
|
|
28
|
-
else if (!config.registryUrl) {
|
|
29
|
-
config.registryUrl = DEFAULT_REGISTRY_URL;
|
|
30
|
-
}
|
|
31
|
-
return config;
|
|
27
|
+
const data = await fs_1.promises.readFile(filePath, 'utf-8');
|
|
28
|
+
return JSON.parse(data);
|
|
32
29
|
}
|
|
33
30
|
catch (error) {
|
|
34
|
-
// If file doesn't exist, return default config
|
|
35
31
|
if (error.code === 'ENOENT') {
|
|
36
|
-
return
|
|
37
|
-
registryUrl: process.env.PRPM_REGISTRY_URL || DEFAULT_REGISTRY_URL,
|
|
38
|
-
telemetryEnabled: true,
|
|
39
|
-
};
|
|
32
|
+
return null;
|
|
40
33
|
}
|
|
41
|
-
throw new Error(`Failed to read
|
|
34
|
+
throw new Error(`Failed to read config from ${filePath}: ${error}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Get merged configuration from user and repository levels
|
|
39
|
+
* Priority: CLI flags > environment > repo config > user config > defaults
|
|
40
|
+
*/
|
|
41
|
+
async function getConfig() {
|
|
42
|
+
// Load user-level config (~/.prpmrc)
|
|
43
|
+
const userConfig = await loadConfigFile(USER_CONFIG_FILE);
|
|
44
|
+
// Load repository-level config (./prpmrc)
|
|
45
|
+
const repoConfigPath = (0, path_1.join)(process.cwd(), REPO_CONFIG_FILE);
|
|
46
|
+
const repoConfig = await loadConfigFile(repoConfigPath);
|
|
47
|
+
// Merge configs (repo overrides user)
|
|
48
|
+
const config = {
|
|
49
|
+
...userConfig,
|
|
50
|
+
...repoConfig,
|
|
51
|
+
};
|
|
52
|
+
// Deep merge nested objects
|
|
53
|
+
if (userConfig?.cursor || repoConfig?.cursor) {
|
|
54
|
+
config.cursor = {
|
|
55
|
+
...userConfig?.cursor,
|
|
56
|
+
...repoConfig?.cursor,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (userConfig?.claude || repoConfig?.claude) {
|
|
60
|
+
config.claude = {
|
|
61
|
+
...userConfig?.claude,
|
|
62
|
+
...repoConfig?.claude,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (userConfig?.collections || repoConfig?.collections) {
|
|
66
|
+
config.collections = {
|
|
67
|
+
...userConfig?.collections,
|
|
68
|
+
...repoConfig?.collections,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// Allow environment variable to override registry URL
|
|
72
|
+
if (process.env.PRPM_REGISTRY_URL) {
|
|
73
|
+
config.registryUrl = process.env.PRPM_REGISTRY_URL;
|
|
42
74
|
}
|
|
75
|
+
else if (!config.registryUrl) {
|
|
76
|
+
config.registryUrl = DEFAULT_REGISTRY_URL;
|
|
77
|
+
}
|
|
78
|
+
// Set defaults
|
|
79
|
+
if (config.telemetryEnabled === undefined) {
|
|
80
|
+
config.telemetryEnabled = true;
|
|
81
|
+
}
|
|
82
|
+
return config;
|
|
43
83
|
}
|
|
44
84
|
/**
|
|
45
|
-
* Save user configuration
|
|
85
|
+
* Save user configuration to ~/.prpmrc
|
|
46
86
|
*/
|
|
47
87
|
async function saveConfig(config) {
|
|
48
88
|
try {
|
|
49
89
|
const data = JSON.stringify(config, null, 2);
|
|
50
|
-
await fs_1.promises.writeFile(
|
|
90
|
+
await fs_1.promises.writeFile(USER_CONFIG_FILE, data, 'utf-8');
|
|
51
91
|
}
|
|
52
92
|
catch (error) {
|
|
53
93
|
throw new Error(`Failed to save user config: ${error}`);
|
|
54
94
|
}
|
|
55
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Save repository configuration to ./.prpmrc
|
|
98
|
+
*/
|
|
99
|
+
async function saveRepoConfig(config) {
|
|
100
|
+
try {
|
|
101
|
+
const repoConfigPath = (0, path_1.join)(process.cwd(), REPO_CONFIG_FILE);
|
|
102
|
+
const data = JSON.stringify(config, null, 2);
|
|
103
|
+
await fs_1.promises.writeFile(repoConfigPath, data, 'utf-8');
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
throw new Error(`Failed to save repository config: ${error}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Get repository-level configuration only
|
|
111
|
+
*/
|
|
112
|
+
async function getRepoConfig() {
|
|
113
|
+
const repoConfigPath = (0, path_1.join)(process.cwd(), REPO_CONFIG_FILE);
|
|
114
|
+
return await loadConfigFile(repoConfigPath);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Get user-level configuration only
|
|
118
|
+
*/
|
|
119
|
+
async function getUserConfig() {
|
|
120
|
+
return await loadConfigFile(USER_CONFIG_FILE);
|
|
121
|
+
}
|
|
56
122
|
/**
|
|
57
123
|
* Update specific config values
|
|
58
124
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prpm",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12",
|
|
4
4
|
"description": "Prompt Package Manager CLI - Install and manage prompt-based files",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"license": "MIT",
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@octokit/rest": "^22.0.0",
|
|
48
|
-
"@pr-pm/registry-client": "^1.2.
|
|
49
|
-
"@pr-pm/types": "^0.1.
|
|
48
|
+
"@pr-pm/registry-client": "^1.2.6",
|
|
49
|
+
"@pr-pm/types": "^0.1.6",
|
|
50
50
|
"ajv": "^8.17.1",
|
|
51
51
|
"ajv-formats": "^3.0.1",
|
|
52
52
|
"commander": "^11.1.0",
|
|
@@ -148,6 +148,11 @@
|
|
|
148
148
|
"my-company"
|
|
149
149
|
]
|
|
150
150
|
},
|
|
151
|
+
"private": {
|
|
152
|
+
"type": "boolean",
|
|
153
|
+
"description": "Whether the package is private. Private packages are only accessible to the owner/organization members. Defaults to false (public).",
|
|
154
|
+
"default": false
|
|
155
|
+
},
|
|
151
156
|
"tags": {
|
|
152
157
|
"type": "array",
|
|
153
158
|
"description": "Package tags for categorization",
|
|
@@ -354,6 +359,14 @@
|
|
|
354
359
|
"node": ">=18.0.0"
|
|
355
360
|
}
|
|
356
361
|
]
|
|
362
|
+
},
|
|
363
|
+
"packages": {
|
|
364
|
+
"type": "array",
|
|
365
|
+
"description": "Array of packages to publish from a single manifest (multi-package publishing). Packages inherit top-level fields unless overridden.",
|
|
366
|
+
"items": {
|
|
367
|
+
"$ref": "#"
|
|
368
|
+
},
|
|
369
|
+
"minItems": 1
|
|
357
370
|
}
|
|
358
371
|
},
|
|
359
372
|
"additionalProperties": false,
|
|
@@ -491,6 +504,51 @@
|
|
|
491
504
|
"files": [
|
|
492
505
|
".windsurfrules"
|
|
493
506
|
]
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
"name": "@company/private-package",
|
|
510
|
+
"version": "1.0.0",
|
|
511
|
+
"description": "A private package only accessible to organization members",
|
|
512
|
+
"format": "claude",
|
|
513
|
+
"subtype": "skill",
|
|
514
|
+
"author": "Company Team",
|
|
515
|
+
"organization": "my-company",
|
|
516
|
+
"private": true,
|
|
517
|
+
"license": "Proprietary",
|
|
518
|
+
"files": [
|
|
519
|
+
"internal-skill.md",
|
|
520
|
+
"README.md"
|
|
521
|
+
]
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
"name": "@username/multi-package-example",
|
|
525
|
+
"version": "1.0.0",
|
|
526
|
+
"description": "Multi-package manifest example",
|
|
527
|
+
"author": "Your Name",
|
|
528
|
+
"license": "MIT",
|
|
529
|
+
"repository": "https://github.com/username/multi-package",
|
|
530
|
+
"packages": [
|
|
531
|
+
{
|
|
532
|
+
"name": "@username/package-one",
|
|
533
|
+
"version": "1.0.0",
|
|
534
|
+
"description": "First package in the multi-package manifest",
|
|
535
|
+
"format": "claude",
|
|
536
|
+
"subtype": "skill",
|
|
537
|
+
"files": [
|
|
538
|
+
"package-one/SKILL.md"
|
|
539
|
+
]
|
|
540
|
+
},
|
|
541
|
+
{
|
|
542
|
+
"name": "@username/package-two",
|
|
543
|
+
"version": "1.0.0",
|
|
544
|
+
"description": "Second package with different settings",
|
|
545
|
+
"format": "cursor",
|
|
546
|
+
"private": true,
|
|
547
|
+
"files": [
|
|
548
|
+
"package-two/.cursor/rules/main.mdc"
|
|
549
|
+
]
|
|
550
|
+
}
|
|
551
|
+
]
|
|
494
552
|
}
|
|
495
553
|
]
|
|
496
554
|
}
|