prpm 0.2.0 ā 1.0.0
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 +14257 -109
- package/package.json +11 -9
- package/dist/__tests__/e2e/test-helpers.js +0 -153
- package/dist/commands/buy-credits.js +0 -224
- package/dist/commands/catalog.js +0 -365
- package/dist/commands/collections.js +0 -655
- package/dist/commands/config.js +0 -161
- package/dist/commands/credits.js +0 -186
- package/dist/commands/index.js +0 -184
- package/dist/commands/info.js +0 -78
- package/dist/commands/init.js +0 -684
- package/dist/commands/install.js +0 -829
- package/dist/commands/list.js +0 -198
- package/dist/commands/login.js +0 -316
- package/dist/commands/outdated.js +0 -130
- package/dist/commands/playground.js +0 -637
- package/dist/commands/popular.js +0 -33
- package/dist/commands/publish.js +0 -803
- package/dist/commands/schema.js +0 -41
- package/dist/commands/search.js +0 -446
- package/dist/commands/starred.js +0 -147
- package/dist/commands/subscribe.js +0 -211
- package/dist/commands/telemetry.js +0 -104
- package/dist/commands/trending.js +0 -86
- package/dist/commands/uninstall.js +0 -120
- package/dist/commands/update.js +0 -121
- package/dist/commands/upgrade.js +0 -121
- package/dist/commands/whoami.js +0 -83
- package/dist/core/claude-config.js +0 -91
- package/dist/core/cursor-config.js +0 -130
- package/dist/core/downloader.js +0 -64
- package/dist/core/errors.js +0 -29
- package/dist/core/filesystem.js +0 -246
- package/dist/core/lockfile.js +0 -292
- package/dist/core/marketplace-converter.js +0 -224
- package/dist/core/prompts.js +0 -62
- package/dist/core/registry-client.js +0 -305
- package/dist/core/schema-validator.js +0 -74
- package/dist/core/telemetry.js +0 -253
- package/dist/core/user-config.js +0 -147
- package/dist/types/registry.js +0 -12
- package/dist/types.js +0 -9
- package/dist/utils/license-extractor.js +0 -122
- package/dist/utils/multi-package.js +0 -117
- package/dist/utils/parallel-publisher.js +0 -144
- package/dist/utils/script-executor.js +0 -72
- package/dist/utils/snippet-extractor.js +0 -77
- package/dist/utils/webapp-url.js +0 -44
package/dist/commands/publish.js
DELETED
|
@@ -1,803 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Publish command implementation
|
|
4
|
-
*/
|
|
5
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
-
if (k2 === undefined) k2 = k;
|
|
7
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
-
}
|
|
11
|
-
Object.defineProperty(o, k2, desc);
|
|
12
|
-
}) : (function(o, m, k, k2) {
|
|
13
|
-
if (k2 === undefined) k2 = k;
|
|
14
|
-
o[k2] = m[k];
|
|
15
|
-
}));
|
|
16
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
-
}) : function(o, v) {
|
|
19
|
-
o["default"] = v;
|
|
20
|
-
});
|
|
21
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
-
var ownKeys = function(o) {
|
|
23
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
-
var ar = [];
|
|
25
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
-
return ar;
|
|
27
|
-
};
|
|
28
|
-
return ownKeys(o);
|
|
29
|
-
};
|
|
30
|
-
return function (mod) {
|
|
31
|
-
if (mod && mod.__esModule) return mod;
|
|
32
|
-
var result = {};
|
|
33
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
-
__setModuleDefault(result, mod);
|
|
35
|
-
return result;
|
|
36
|
-
};
|
|
37
|
-
})();
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.handlePublish = handlePublish;
|
|
40
|
-
exports.createPublishCommand = createPublishCommand;
|
|
41
|
-
const commander_1 = require("commander");
|
|
42
|
-
const promises_1 = require("fs/promises");
|
|
43
|
-
const path_1 = require("path");
|
|
44
|
-
const tar = __importStar(require("tar"));
|
|
45
|
-
const os_1 = require("os");
|
|
46
|
-
const crypto_1 = require("crypto");
|
|
47
|
-
const registry_client_1 = require("@pr-pm/registry-client");
|
|
48
|
-
const user_config_1 = require("../core/user-config");
|
|
49
|
-
const telemetry_1 = require("../core/telemetry");
|
|
50
|
-
const errors_1 = require("../core/errors");
|
|
51
|
-
const marketplace_converter_1 = require("../core/marketplace-converter");
|
|
52
|
-
const schema_validator_1 = require("../core/schema-validator");
|
|
53
|
-
const license_extractor_1 = require("../utils/license-extractor");
|
|
54
|
-
const snippet_extractor_1 = require("../utils/snippet-extractor");
|
|
55
|
-
const script_executor_1 = require("../utils/script-executor");
|
|
56
|
-
/**
|
|
57
|
-
* Try to find and load manifest files
|
|
58
|
-
* Checks for:
|
|
59
|
-
* 1. prpm.json (native format) - returns single manifest or array of packages and collections
|
|
60
|
-
* 2. .claude/marketplace.json (Claude format) - returns all plugins as separate manifests
|
|
61
|
-
* 3. .claude-plugin/marketplace.json (Claude format - alternative location) - returns all plugins
|
|
62
|
-
*/
|
|
63
|
-
async function findAndLoadManifests() {
|
|
64
|
-
// Try prpm.json first (native format)
|
|
65
|
-
const prpmJsonPath = (0, path_1.join)(process.cwd(), 'prpm.json');
|
|
66
|
-
let prpmJsonExists = false;
|
|
67
|
-
let prpmJsonError = null;
|
|
68
|
-
try {
|
|
69
|
-
const content = await (0, promises_1.readFile)(prpmJsonPath, 'utf-8');
|
|
70
|
-
prpmJsonExists = true; // Mark file as found after successful read
|
|
71
|
-
const manifest = JSON.parse(content);
|
|
72
|
-
// Extract collections if present
|
|
73
|
-
const collections = [];
|
|
74
|
-
if ('collections' in manifest && Array.isArray(manifest.collections)) {
|
|
75
|
-
const rawCollections = manifest.collections;
|
|
76
|
-
collections.push(...rawCollections);
|
|
77
|
-
}
|
|
78
|
-
// Check if this is a multi-package manifest
|
|
79
|
-
if ('packages' in manifest && Array.isArray(manifest.packages)) {
|
|
80
|
-
const multiManifest = manifest;
|
|
81
|
-
// Validate each package in the array
|
|
82
|
-
const validatedManifests = multiManifest.packages.map((pkg, idx) => {
|
|
83
|
-
// Inherit top-level fields if not specified in package - using explicit undefined checks
|
|
84
|
-
const packageWithDefaults = {
|
|
85
|
-
name: pkg.name,
|
|
86
|
-
version: pkg.version,
|
|
87
|
-
description: pkg.description,
|
|
88
|
-
format: pkg.format,
|
|
89
|
-
files: pkg.files,
|
|
90
|
-
author: pkg.author ?? multiManifest.author,
|
|
91
|
-
license: pkg.license ?? multiManifest.license,
|
|
92
|
-
repository: pkg.repository ?? multiManifest.repository,
|
|
93
|
-
homepage: pkg.homepage ?? multiManifest.homepage,
|
|
94
|
-
documentation: pkg.documentation ?? multiManifest.documentation,
|
|
95
|
-
organization: pkg.organization ?? multiManifest.organization,
|
|
96
|
-
private: pkg.private ?? multiManifest.private,
|
|
97
|
-
tags: pkg.tags ?? multiManifest.tags,
|
|
98
|
-
keywords: pkg.keywords ?? multiManifest.keywords,
|
|
99
|
-
subtype: pkg.subtype,
|
|
100
|
-
dependencies: pkg.dependencies,
|
|
101
|
-
peerDependencies: pkg.peerDependencies,
|
|
102
|
-
engines: pkg.engines,
|
|
103
|
-
main: pkg.main,
|
|
104
|
-
};
|
|
105
|
-
return validateManifest(packageWithDefaults);
|
|
106
|
-
});
|
|
107
|
-
return { manifests: validatedManifests, collections, source: 'prpm.json (multi-package)' };
|
|
108
|
-
}
|
|
109
|
-
// Collections-only manifest (no packages)
|
|
110
|
-
if (collections.length > 0) {
|
|
111
|
-
return { manifests: [], collections, source: 'prpm.json (collections-only)' };
|
|
112
|
-
}
|
|
113
|
-
// Single package manifest
|
|
114
|
-
const validated = validateManifest(manifest);
|
|
115
|
-
return { manifests: [validated], collections, source: 'prpm.json' };
|
|
116
|
-
}
|
|
117
|
-
catch (error) {
|
|
118
|
-
// Store error for later
|
|
119
|
-
prpmJsonError = error;
|
|
120
|
-
// If it's a validation or parsing error, throw it immediately (don't try marketplace.json)
|
|
121
|
-
if (prpmJsonExists && error instanceof Error && (error.message.includes('Invalid JSON') ||
|
|
122
|
-
error.message.includes('Manifest validation failed') ||
|
|
123
|
-
error.message.includes('Claude skill') ||
|
|
124
|
-
error.message.includes('SKILL.md'))) {
|
|
125
|
-
throw error;
|
|
126
|
-
}
|
|
127
|
-
// Otherwise, prpm.json not found or other error, try marketplace.json
|
|
128
|
-
}
|
|
129
|
-
// Try .claude/marketplace.json (Claude format)
|
|
130
|
-
const marketplaceJsonPath = (0, path_1.join)(process.cwd(), '.claude', 'marketplace.json');
|
|
131
|
-
try {
|
|
132
|
-
const content = await (0, promises_1.readFile)(marketplaceJsonPath, 'utf-8');
|
|
133
|
-
const marketplaceData = JSON.parse(content);
|
|
134
|
-
if (!(0, marketplace_converter_1.validateMarketplaceJson)(marketplaceData)) {
|
|
135
|
-
throw new Error('Invalid marketplace.json format');
|
|
136
|
-
}
|
|
137
|
-
// Convert each plugin in marketplace.json to a separate PRPM manifest
|
|
138
|
-
const manifests = [];
|
|
139
|
-
for (let i = 0; i < marketplaceData.plugins.length; i++) {
|
|
140
|
-
const manifest = (0, marketplace_converter_1.marketplaceToManifest)(marketplaceData, i);
|
|
141
|
-
const validated = validateManifest(manifest);
|
|
142
|
-
manifests.push(validated);
|
|
143
|
-
}
|
|
144
|
-
return { manifests, collections: [], source: '.claude/marketplace.json' };
|
|
145
|
-
}
|
|
146
|
-
catch (error) {
|
|
147
|
-
// marketplace.json not found or invalid at .claude path, try .claude-plugin
|
|
148
|
-
}
|
|
149
|
-
// Try .claude-plugin/marketplace.json (alternative Claude format)
|
|
150
|
-
const marketplaceJsonPluginPath = (0, path_1.join)(process.cwd(), '.claude-plugin', 'marketplace.json');
|
|
151
|
-
try {
|
|
152
|
-
const content = await (0, promises_1.readFile)(marketplaceJsonPluginPath, 'utf-8');
|
|
153
|
-
const marketplaceData = JSON.parse(content);
|
|
154
|
-
if (!(0, marketplace_converter_1.validateMarketplaceJson)(marketplaceData)) {
|
|
155
|
-
throw new Error('Invalid marketplace.json format');
|
|
156
|
-
}
|
|
157
|
-
// Convert each plugin in marketplace.json to a separate PRPM manifest
|
|
158
|
-
const manifests = [];
|
|
159
|
-
for (let i = 0; i < marketplaceData.plugins.length; i++) {
|
|
160
|
-
const manifest = (0, marketplace_converter_1.marketplaceToManifest)(marketplaceData, i);
|
|
161
|
-
const validated = validateManifest(manifest);
|
|
162
|
-
manifests.push(validated);
|
|
163
|
-
}
|
|
164
|
-
return { manifests, collections: [], source: '.claude-plugin/marketplace.json' };
|
|
165
|
-
}
|
|
166
|
-
catch (error) {
|
|
167
|
-
// marketplace.json not found or invalid
|
|
168
|
-
}
|
|
169
|
-
// No manifest file found
|
|
170
|
-
throw new Error('No manifest file found. Expected either:\n' +
|
|
171
|
-
' - prpm.json in the current directory, or\n' +
|
|
172
|
-
' - .claude/marketplace.json (Claude format), or\n' +
|
|
173
|
-
' - .claude-plugin/marketplace.json (Claude format)');
|
|
174
|
-
}
|
|
175
|
-
/**
|
|
176
|
-
* Validate package manifest
|
|
177
|
-
*/
|
|
178
|
-
function validateManifest(manifest) {
|
|
179
|
-
// Set default subtype to 'rule' if not provided
|
|
180
|
-
if (!manifest.subtype) {
|
|
181
|
-
manifest.subtype = 'rule';
|
|
182
|
-
}
|
|
183
|
-
// First, validate against JSON schema
|
|
184
|
-
const schemaValidation = (0, schema_validator_1.validateManifestSchema)(manifest);
|
|
185
|
-
if (!schemaValidation.valid) {
|
|
186
|
-
const errorMessages = schemaValidation.errors?.join('\n - ') || 'Unknown validation error';
|
|
187
|
-
throw new Error(`Manifest validation failed:\n - ${errorMessages}`);
|
|
188
|
-
}
|
|
189
|
-
// Additional custom validations (beyond what JSON schema can express)
|
|
190
|
-
// Check if using enhanced format (file objects)
|
|
191
|
-
const hasEnhancedFormat = manifest.files.some(f => typeof f === 'object');
|
|
192
|
-
if (hasEnhancedFormat) {
|
|
193
|
-
// Check if files have multiple distinct formats
|
|
194
|
-
const fileFormats = new Set(manifest.files
|
|
195
|
-
.filter(f => typeof f === 'object')
|
|
196
|
-
.map(f => f.format));
|
|
197
|
-
// Only suggest "collection" if there are multiple distinct formats
|
|
198
|
-
if (fileFormats.size > 1 && manifest.subtype !== 'collection') {
|
|
199
|
-
console.warn('ā ļø Package contains multiple file formats. Consider setting subtype to "collection" for clarity.');
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
// Enforce SKILL.md filename for Claude skills
|
|
203
|
-
if (manifest.format === 'claude' && manifest.subtype === 'skill') {
|
|
204
|
-
const filePaths = normalizeFilePaths(manifest.files);
|
|
205
|
-
const hasSkillMd = filePaths.some(path => path.endsWith('/SKILL.md') || path === 'SKILL.md');
|
|
206
|
-
if (!hasSkillMd) {
|
|
207
|
-
throw new Error('Claude skills must contain a SKILL.md file.\n' +
|
|
208
|
-
'According to Claude documentation at https://docs.claude.com/en/docs/claude-code/skills,\n' +
|
|
209
|
-
'skills must have a file named SKILL.md in their directory.\n' +
|
|
210
|
-
'Please rename your skill file to SKILL.md (all caps) and update your prpm.json files array.');
|
|
211
|
-
}
|
|
212
|
-
// Validate skill name length (max 64 characters)
|
|
213
|
-
if (manifest.name.length > 64) {
|
|
214
|
-
throw new Error(`Claude skill name "${manifest.name}" exceeds 64 character limit (${manifest.name.length} characters).\n` +
|
|
215
|
-
'According to Claude documentation, skill names must be max 64 characters.\n' +
|
|
216
|
-
'Please shorten your package name.');
|
|
217
|
-
}
|
|
218
|
-
// Validate skill name format (lowercase, numbers, hyphens only)
|
|
219
|
-
if (!/^[a-z0-9-]+$/.test(manifest.name)) {
|
|
220
|
-
throw new Error(`Claude skill name "${manifest.name}" contains invalid characters.\n` +
|
|
221
|
-
'According to Claude documentation, skill names must use lowercase letters, numbers, and hyphens only.\n' +
|
|
222
|
-
'Please update your package name.');
|
|
223
|
-
}
|
|
224
|
-
// Validate description length (max 1024 characters)
|
|
225
|
-
if (manifest.description.length > 1024) {
|
|
226
|
-
throw new Error(`Claude skill description exceeds 1024 character limit (${manifest.description.length} characters).\n` +
|
|
227
|
-
'According to Claude documentation, skill descriptions must be max 1024 characters.\n' +
|
|
228
|
-
'Please shorten your description.');
|
|
229
|
-
}
|
|
230
|
-
// Warn if description is approaching the limit (80% = 819 chars)
|
|
231
|
-
if (manifest.description.length > 819) {
|
|
232
|
-
console.warn(`ā ļø Warning: Skill description is ${manifest.description.length}/1024 characters (${Math.round(manifest.description.length / 1024 * 100)}% of limit).\n` +
|
|
233
|
-
' Consider keeping it concise for better discoverability.');
|
|
234
|
-
}
|
|
235
|
-
// Warn if description is too short (less than 100 chars)
|
|
236
|
-
if (manifest.description.length < 100) {
|
|
237
|
-
console.warn(`ā ļø Warning: Skill description is only ${manifest.description.length} characters.\n` +
|
|
238
|
-
' Claude uses descriptions for skill discovery - consider adding more detail about:\n' +
|
|
239
|
-
' - What the skill does\n' +
|
|
240
|
-
' - When Claude should use it\n' +
|
|
241
|
-
' - What problems it solves');
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
return manifest;
|
|
245
|
-
}
|
|
246
|
-
/**
|
|
247
|
-
* Normalize files array to string paths
|
|
248
|
-
* Converts both simple and enhanced formats to string array
|
|
249
|
-
*/
|
|
250
|
-
function normalizeFilePaths(files) {
|
|
251
|
-
return files.map(file => {
|
|
252
|
-
if (typeof file === 'string') {
|
|
253
|
-
return file;
|
|
254
|
-
}
|
|
255
|
-
else {
|
|
256
|
-
return file.path;
|
|
257
|
-
}
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Predict what the scoped package name will be after publishing
|
|
262
|
-
* This matches the server-side logic in packages.ts
|
|
263
|
-
*/
|
|
264
|
-
function predictScopedPackageName(manifestName, username, organization) {
|
|
265
|
-
const usernameLowercase = username.toLowerCase();
|
|
266
|
-
// If organization is specified, use @org-name/
|
|
267
|
-
if (organization) {
|
|
268
|
-
const orgNameLowercase = organization.toLowerCase();
|
|
269
|
-
const expectedPrefix = `@${orgNameLowercase}/`;
|
|
270
|
-
if (!manifestName.startsWith(expectedPrefix)) {
|
|
271
|
-
return `${expectedPrefix}${manifestName}`;
|
|
272
|
-
}
|
|
273
|
-
return manifestName;
|
|
274
|
-
}
|
|
275
|
-
// If package name doesn't already have a scope, add @username/
|
|
276
|
-
if (!manifestName.startsWith('@')) {
|
|
277
|
-
return `@${usernameLowercase}/${manifestName}`;
|
|
278
|
-
}
|
|
279
|
-
// Package already has a scope, return as-is
|
|
280
|
-
return manifestName;
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* Create tarball from current directory
|
|
284
|
-
*/
|
|
285
|
-
async function createTarball(manifest) {
|
|
286
|
-
const tmpDir = (0, path_1.join)((0, os_1.tmpdir)(), `prpm-${(0, crypto_1.randomBytes)(8).toString('hex')}`);
|
|
287
|
-
const tarballPath = (0, path_1.join)(tmpDir, 'package.tar.gz');
|
|
288
|
-
try {
|
|
289
|
-
// Create temp directory
|
|
290
|
-
await (0, promises_1.mkdir)(tmpDir, { recursive: true });
|
|
291
|
-
// Get files to include - normalize to string paths
|
|
292
|
-
const filePaths = normalizeFilePaths(manifest.files);
|
|
293
|
-
// Add standard files if not already included
|
|
294
|
-
const standardFiles = ['prpm.json', 'README.md', 'LICENSE'];
|
|
295
|
-
for (const file of standardFiles) {
|
|
296
|
-
if (!filePaths.includes(file)) {
|
|
297
|
-
filePaths.push(file);
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
// Check which files exist
|
|
301
|
-
const existingFiles = [];
|
|
302
|
-
for (const file of filePaths) {
|
|
303
|
-
try {
|
|
304
|
-
await (0, promises_1.stat)(file);
|
|
305
|
-
existingFiles.push(file);
|
|
306
|
-
}
|
|
307
|
-
catch {
|
|
308
|
-
// File doesn't exist, skip
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
if (existingFiles.length === 0) {
|
|
312
|
-
throw new Error('No package files found to include in tarball');
|
|
313
|
-
}
|
|
314
|
-
// Create tarball
|
|
315
|
-
await tar.create({
|
|
316
|
-
gzip: true,
|
|
317
|
-
file: tarballPath,
|
|
318
|
-
cwd: process.cwd(),
|
|
319
|
-
}, existingFiles);
|
|
320
|
-
// Read tarball into buffer
|
|
321
|
-
const tarballBuffer = await (0, promises_1.readFile)(tarballPath);
|
|
322
|
-
// Check size (max 10MB)
|
|
323
|
-
const sizeMB = tarballBuffer.length / (1024 * 1024);
|
|
324
|
-
if (sizeMB > 10) {
|
|
325
|
-
throw new Error(`Package size (${sizeMB.toFixed(2)}MB) exceeds 10MB limit`);
|
|
326
|
-
}
|
|
327
|
-
return tarballBuffer;
|
|
328
|
-
}
|
|
329
|
-
catch (error) {
|
|
330
|
-
throw error;
|
|
331
|
-
}
|
|
332
|
-
finally {
|
|
333
|
-
// Clean up temp directory
|
|
334
|
-
try {
|
|
335
|
-
await (0, promises_1.rm)(tmpDir, { recursive: true, force: true });
|
|
336
|
-
}
|
|
337
|
-
catch {
|
|
338
|
-
// Ignore cleanup errors
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
/**
|
|
343
|
-
* Publish a package to the registry
|
|
344
|
-
*/
|
|
345
|
-
async function handlePublish(options) {
|
|
346
|
-
const startTime = Date.now();
|
|
347
|
-
let success = false;
|
|
348
|
-
let error;
|
|
349
|
-
let packageName;
|
|
350
|
-
let version;
|
|
351
|
-
try {
|
|
352
|
-
const config = await (0, user_config_1.getConfig)();
|
|
353
|
-
// Check if logged in
|
|
354
|
-
if (!config.token) {
|
|
355
|
-
throw new errors_1.CLIError('ā Not logged in. Run "prpm login" first.', 1);
|
|
356
|
-
}
|
|
357
|
-
console.log('š¦ Publishing package...\n');
|
|
358
|
-
// Read and validate manifests
|
|
359
|
-
console.log('š Validating package manifest(s)...');
|
|
360
|
-
const { manifests, collections, source } = await findAndLoadManifests();
|
|
361
|
-
// Execute prepublishOnly script if defined (for multi-package manifests)
|
|
362
|
-
// This runs before any packages are published
|
|
363
|
-
if (source === 'prpm.json (multi-package)' || source === 'prpm.json') {
|
|
364
|
-
try {
|
|
365
|
-
// Re-read the raw prpm.json to check for scripts
|
|
366
|
-
const prpmJsonPath = (0, path_1.join)(process.cwd(), 'prpm.json');
|
|
367
|
-
const prpmContent = await (0, promises_1.readFile)(prpmJsonPath, 'utf-8');
|
|
368
|
-
const prpmManifest = JSON.parse(prpmContent);
|
|
369
|
-
if (prpmManifest.scripts) {
|
|
370
|
-
await (0, script_executor_1.executePrepublishOnly)(prpmManifest.scripts);
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
catch (error) {
|
|
374
|
-
// If script execution fails, abort publish
|
|
375
|
-
if (error instanceof Error && error.message.includes('script')) {
|
|
376
|
-
throw error;
|
|
377
|
-
}
|
|
378
|
-
// Ignore other errors (e.g., file not found - shouldn't happen at this point)
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
if (manifests.length > 1 || collections.length > 0) {
|
|
382
|
-
if (manifests.length > 0) {
|
|
383
|
-
console.log(` Found ${manifests.length} package(s) in ${source}`);
|
|
384
|
-
if (options.package) {
|
|
385
|
-
console.log(` Filtering to package: ${options.package}`);
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
if (collections.length > 0) {
|
|
389
|
-
console.log(` Found ${collections.length} collection(s) in ${source}`);
|
|
390
|
-
if (options.collection) {
|
|
391
|
-
console.log(` Filtering to collection: ${options.collection}`);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
console.log(' Will publish each separately\n');
|
|
395
|
-
}
|
|
396
|
-
// Filter to specific package if requested
|
|
397
|
-
let filteredManifests = manifests;
|
|
398
|
-
if (options.package) {
|
|
399
|
-
filteredManifests = manifests.filter(m => m.name === options.package);
|
|
400
|
-
if (filteredManifests.length === 0) {
|
|
401
|
-
throw new Error(`Package "${options.package}" not found in manifest. Available packages: ${manifests.map(m => m.name).join(', ')}`);
|
|
402
|
-
}
|
|
403
|
-
console.log(` ā Found package "${options.package}"\n`);
|
|
404
|
-
}
|
|
405
|
-
// Get user info to check for organizations (once for all packages)
|
|
406
|
-
console.log('š Checking authentication...');
|
|
407
|
-
const client = (0, registry_client_1.getRegistryClient)(config);
|
|
408
|
-
let userInfo;
|
|
409
|
-
try {
|
|
410
|
-
userInfo = await client.whoami();
|
|
411
|
-
}
|
|
412
|
-
catch (err) {
|
|
413
|
-
console.log(' Could not fetch user organizations, publishing as personal packages');
|
|
414
|
-
}
|
|
415
|
-
console.log('');
|
|
416
|
-
// Check for duplicate package names (only in filtered set)
|
|
417
|
-
if (filteredManifests.length > 1) {
|
|
418
|
-
const nameMap = new Map();
|
|
419
|
-
const duplicates = [];
|
|
420
|
-
filteredManifests.forEach((manifest, index) => {
|
|
421
|
-
const existingIndex = nameMap.get(manifest.name);
|
|
422
|
-
if (existingIndex !== undefined) {
|
|
423
|
-
duplicates.push(` - "${manifest.name}" appears in positions ${existingIndex + 1} and ${index + 1}`);
|
|
424
|
-
}
|
|
425
|
-
else {
|
|
426
|
-
nameMap.set(manifest.name, index);
|
|
427
|
-
}
|
|
428
|
-
});
|
|
429
|
-
if (duplicates.length > 0) {
|
|
430
|
-
console.error('ā Duplicate package names detected:\n');
|
|
431
|
-
duplicates.forEach(dup => console.error(dup));
|
|
432
|
-
console.error('\nā ļø Each package must have a unique name.');
|
|
433
|
-
console.error(' Package names are globally unique per author/organization.');
|
|
434
|
-
console.error(' If you want to publish the same package for different formats,');
|
|
435
|
-
console.error(' use different names (e.g., "react-rules-cursor" vs "react-rules-claude").\n');
|
|
436
|
-
throw new Error('Cannot publish packages with duplicate names');
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
// Track published packages and collections
|
|
440
|
-
const publishedPackages = [];
|
|
441
|
-
const failedPackages = [];
|
|
442
|
-
const publishedCollections = [];
|
|
443
|
-
const failedCollections = [];
|
|
444
|
-
// Publish each manifest (filtered set)
|
|
445
|
-
for (let i = 0; i < filteredManifests.length; i++) {
|
|
446
|
-
const manifest = filteredManifests[i];
|
|
447
|
-
packageName = manifest.name;
|
|
448
|
-
version = manifest.version;
|
|
449
|
-
if (filteredManifests.length > 1) {
|
|
450
|
-
console.log(`\n${'='.repeat(60)}`);
|
|
451
|
-
console.log(`š¦ Publishing plugin ${i + 1} of ${filteredManifests.length}`);
|
|
452
|
-
console.log(`${'='.repeat(60)}\n`);
|
|
453
|
-
}
|
|
454
|
-
try {
|
|
455
|
-
// Debug: Log access override logic only if DEBUG env var is set
|
|
456
|
-
if (process.env.DEBUG) {
|
|
457
|
-
console.log(`\nš Before access override:`);
|
|
458
|
-
console.log(` - manifest.private: ${manifest.private}`);
|
|
459
|
-
console.log(` - options.access: ${options.access}`);
|
|
460
|
-
}
|
|
461
|
-
// Determine access level:
|
|
462
|
-
// 1. If --access flag is provided, it overrides manifest setting
|
|
463
|
-
// 2. Otherwise, use manifest setting (defaults to false/public if not specified)
|
|
464
|
-
let isPrivate;
|
|
465
|
-
if (options.access !== undefined) {
|
|
466
|
-
// CLI flag explicitly provided - use it
|
|
467
|
-
isPrivate = options.access === 'private';
|
|
468
|
-
if (process.env.DEBUG) {
|
|
469
|
-
console.log(` - Using CLI flag override: ${options.access}`);
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
else {
|
|
473
|
-
// No CLI flag - use manifest setting
|
|
474
|
-
isPrivate = manifest.private || false;
|
|
475
|
-
if (process.env.DEBUG) {
|
|
476
|
-
console.log(` - Using manifest setting: ${isPrivate}`);
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
if (process.env.DEBUG) {
|
|
480
|
-
console.log(` - calculated isPrivate: ${isPrivate}`);
|
|
481
|
-
}
|
|
482
|
-
// Update manifest with final private setting
|
|
483
|
-
manifest.private = isPrivate;
|
|
484
|
-
if (process.env.DEBUG) {
|
|
485
|
-
console.log(` - final manifest.private: ${manifest.private}`);
|
|
486
|
-
console.log('');
|
|
487
|
-
}
|
|
488
|
-
let selectedOrgId;
|
|
489
|
-
let selectedOrgName;
|
|
490
|
-
// Check if organization is specified in manifest
|
|
491
|
-
if (manifest.organization && userInfo) {
|
|
492
|
-
const orgFromManifest = userInfo.organizations?.find((org) => org.name === manifest.organization || org.id === manifest.organization);
|
|
493
|
-
if (!orgFromManifest) {
|
|
494
|
-
throw new Error(`Organization "${manifest.organization}" not found or you are not a member`);
|
|
495
|
-
}
|
|
496
|
-
// Check if user has publishing rights
|
|
497
|
-
if (!['owner', 'admin', 'maintainer'].includes(orgFromManifest.role)) {
|
|
498
|
-
throw new Error(`You do not have permission to publish to organization "${orgFromManifest.name}". ` +
|
|
499
|
-
`Your role: ${orgFromManifest.role}. Required: owner, admin, or maintainer`);
|
|
500
|
-
}
|
|
501
|
-
selectedOrgId = orgFromManifest.id;
|
|
502
|
-
selectedOrgName = orgFromManifest.name;
|
|
503
|
-
}
|
|
504
|
-
// Predict what the scoped package name will be
|
|
505
|
-
const scopedPackageName = predictScopedPackageName(manifest.name, userInfo?.username || config.username || 'unknown', selectedOrgName || manifest.organization);
|
|
506
|
-
console.log(` Source: ${source}`);
|
|
507
|
-
console.log(` Package: ${scopedPackageName}@${manifest.version}`);
|
|
508
|
-
console.log(` Format: ${manifest.format} | Subtype: ${manifest.subtype}`);
|
|
509
|
-
console.log(` Description: ${manifest.description}`);
|
|
510
|
-
console.log(` Access: ${manifest.private ? 'private' : 'public'}`);
|
|
511
|
-
if (selectedOrgId && userInfo) {
|
|
512
|
-
const selectedOrg = userInfo.organizations.find((org) => org.id === selectedOrgId);
|
|
513
|
-
console.log(` Publishing to: ${selectedOrg?.name || 'organization'}`);
|
|
514
|
-
}
|
|
515
|
-
console.log('');
|
|
516
|
-
// Extract license information
|
|
517
|
-
console.log('š Extracting license information...');
|
|
518
|
-
const licenseInfo = await (0, license_extractor_1.extractLicenseInfo)(manifest.repository);
|
|
519
|
-
// Update manifest with license information from LICENSE file if found
|
|
520
|
-
// Only set fields that aren't already manually specified in prpm.json
|
|
521
|
-
if (licenseInfo.type && !manifest.license) {
|
|
522
|
-
manifest.license = licenseInfo.type;
|
|
523
|
-
}
|
|
524
|
-
if (licenseInfo.text && !manifest.license_text) {
|
|
525
|
-
manifest.license_text = licenseInfo.text;
|
|
526
|
-
}
|
|
527
|
-
if (licenseInfo.url && !manifest.license_url) {
|
|
528
|
-
manifest.license_url = licenseInfo.url || undefined;
|
|
529
|
-
}
|
|
530
|
-
// Validate and warn about license (optional - will extract if present)
|
|
531
|
-
(0, license_extractor_1.validateLicenseInfo)(licenseInfo, scopedPackageName);
|
|
532
|
-
console.log('');
|
|
533
|
-
// Extract content snippet
|
|
534
|
-
console.log('š Extracting content snippet...');
|
|
535
|
-
const snippet = await (0, snippet_extractor_1.extractSnippet)(manifest);
|
|
536
|
-
if (snippet) {
|
|
537
|
-
manifest.snippet = snippet;
|
|
538
|
-
}
|
|
539
|
-
(0, snippet_extractor_1.validateSnippet)(snippet, scopedPackageName);
|
|
540
|
-
console.log('');
|
|
541
|
-
// Create tarball
|
|
542
|
-
console.log('š¦ Creating package tarball...');
|
|
543
|
-
const tarball = await createTarball(manifest);
|
|
544
|
-
// Display size in KB or MB depending on size
|
|
545
|
-
const sizeInBytes = tarball.length;
|
|
546
|
-
const sizeInKB = sizeInBytes / 1024;
|
|
547
|
-
const sizeInMB = sizeInBytes / (1024 * 1024);
|
|
548
|
-
let sizeDisplay;
|
|
549
|
-
if (sizeInMB >= 1) {
|
|
550
|
-
sizeDisplay = `${sizeInMB.toFixed(2)}MB`;
|
|
551
|
-
}
|
|
552
|
-
else {
|
|
553
|
-
sizeDisplay = `${sizeInKB.toFixed(2)}KB`;
|
|
554
|
-
}
|
|
555
|
-
console.log(` Size: ${sizeDisplay}`);
|
|
556
|
-
console.log('');
|
|
557
|
-
if (options.dryRun) {
|
|
558
|
-
console.log('ā
Dry run successful! Package is ready to publish.');
|
|
559
|
-
publishedPackages.push({
|
|
560
|
-
name: scopedPackageName,
|
|
561
|
-
version: manifest.version,
|
|
562
|
-
url: ''
|
|
563
|
-
});
|
|
564
|
-
continue;
|
|
565
|
-
}
|
|
566
|
-
// Publish to registry
|
|
567
|
-
console.log('š Publishing to registry...');
|
|
568
|
-
if (selectedOrgId) {
|
|
569
|
-
console.log(` Publishing as organization: ${userInfo.organizations.find((org) => org.id === selectedOrgId)?.name}`);
|
|
570
|
-
console.log(` Organization ID: ${selectedOrgId}`);
|
|
571
|
-
}
|
|
572
|
-
const result = await client.publish(manifest, tarball, selectedOrgId ? { orgId: selectedOrgId } : undefined);
|
|
573
|
-
// Determine the webapp URL based on registry URL
|
|
574
|
-
let webappUrl;
|
|
575
|
-
const registryUrl = config.registryUrl || 'https://registry.prpm.dev';
|
|
576
|
-
if (registryUrl.includes('localhost') || registryUrl.includes('127.0.0.1')) {
|
|
577
|
-
// Local development - webapp is on port 5173
|
|
578
|
-
webappUrl = 'http://localhost:5173';
|
|
579
|
-
}
|
|
580
|
-
else if (registryUrl.includes('registry.prpm.dev')) {
|
|
581
|
-
// Production - webapp is on prpm.dev
|
|
582
|
-
webappUrl = 'https://prpm.dev';
|
|
583
|
-
}
|
|
584
|
-
else {
|
|
585
|
-
// Default to registry URL for unknown environments
|
|
586
|
-
webappUrl = registryUrl;
|
|
587
|
-
}
|
|
588
|
-
// Use the name returned from the API (which includes auto-prefixed scope)
|
|
589
|
-
const packageUrl = `${webappUrl}/packages/${encodeURIComponent(result.name)}`;
|
|
590
|
-
console.log('');
|
|
591
|
-
console.log('ā
Package published successfully!');
|
|
592
|
-
console.log('');
|
|
593
|
-
console.log(` Package: ${result.name}@${result.version}`);
|
|
594
|
-
console.log(` Install: prpm install ${result.name}`);
|
|
595
|
-
console.log('');
|
|
596
|
-
publishedPackages.push({
|
|
597
|
-
name: result.name, // Use scoped name from server
|
|
598
|
-
version: result.version,
|
|
599
|
-
url: packageUrl
|
|
600
|
-
});
|
|
601
|
-
}
|
|
602
|
-
catch (err) {
|
|
603
|
-
const pkgError = err instanceof Error ? err.message : String(err);
|
|
604
|
-
// Try to use scoped name if we have user info, otherwise fall back to manifest name
|
|
605
|
-
const displayName = userInfo
|
|
606
|
-
? predictScopedPackageName(manifest.name, userInfo.username, manifest.organization)
|
|
607
|
-
: manifest.name;
|
|
608
|
-
console.error(`\nā Failed to publish ${displayName}: ${pkgError}\n`);
|
|
609
|
-
failedPackages.push({
|
|
610
|
-
name: displayName,
|
|
611
|
-
error: pkgError
|
|
612
|
-
});
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
// Publish collections if present
|
|
616
|
-
if (collections.length > 0) {
|
|
617
|
-
// Filter to specific collection if requested
|
|
618
|
-
let filteredCollections = collections;
|
|
619
|
-
if (options.collection) {
|
|
620
|
-
filteredCollections = collections.filter(c => c.id === options.collection);
|
|
621
|
-
if (filteredCollections.length === 0) {
|
|
622
|
-
throw new Error(`Collection "${options.collection}" not found in manifest. Available collections: ${collections.map(c => c.id).join(', ')}`);
|
|
623
|
-
}
|
|
624
|
-
console.log(` ā Found collection "${options.collection}"\n`);
|
|
625
|
-
}
|
|
626
|
-
for (const collection of filteredCollections) {
|
|
627
|
-
if (filteredCollections.length > 1) {
|
|
628
|
-
console.log(`\n${'='.repeat(60)}`);
|
|
629
|
-
console.log(`š Publishing collection`);
|
|
630
|
-
console.log(`${'='.repeat(60)}\n`);
|
|
631
|
-
}
|
|
632
|
-
try {
|
|
633
|
-
console.log(`š Publishing collection "${collection.name}"...`);
|
|
634
|
-
console.log(` ID: ${collection.id}`);
|
|
635
|
-
console.log(` Packages: ${collection.packages.length}`);
|
|
636
|
-
console.log('');
|
|
637
|
-
if (options.dryRun) {
|
|
638
|
-
console.log('ā
Dry run successful! Collection is ready to publish.');
|
|
639
|
-
publishedCollections.push({
|
|
640
|
-
id: collection.id,
|
|
641
|
-
name: collection.name,
|
|
642
|
-
version: collection.version || '1.0.0'
|
|
643
|
-
});
|
|
644
|
-
continue;
|
|
645
|
-
}
|
|
646
|
-
// Import and call the collection publish logic
|
|
647
|
-
const { handleCollectionPublish } = await Promise.resolve().then(() => __importStar(require('./collections.js')));
|
|
648
|
-
// Create a temporary manifest object for the collection
|
|
649
|
-
const collectionData = {
|
|
650
|
-
id: collection.id,
|
|
651
|
-
name: collection.name,
|
|
652
|
-
description: collection.description,
|
|
653
|
-
version: collection.version,
|
|
654
|
-
category: collection.category,
|
|
655
|
-
tags: collection.tags,
|
|
656
|
-
icon: collection.icon,
|
|
657
|
-
packages: collection.packages.map(pkg => ({
|
|
658
|
-
packageId: pkg.packageId,
|
|
659
|
-
version: pkg.version,
|
|
660
|
-
required: pkg.required !== false,
|
|
661
|
-
reason: pkg.reason,
|
|
662
|
-
})),
|
|
663
|
-
};
|
|
664
|
-
const result = await client.createCollection(collectionData);
|
|
665
|
-
console.log(`ā
Collection published successfully!`);
|
|
666
|
-
console.log(` Scope: ${result.scope}`);
|
|
667
|
-
console.log(` Name: ${result.name_slug}`);
|
|
668
|
-
console.log(` Version: ${result.version || '1.0.0'}`);
|
|
669
|
-
console.log('');
|
|
670
|
-
console.log(`š” Install: prpm install collections/${result.name_slug}`);
|
|
671
|
-
console.log('');
|
|
672
|
-
publishedCollections.push({
|
|
673
|
-
id: collection.id,
|
|
674
|
-
name: collection.name,
|
|
675
|
-
version: result.version || '1.0.0'
|
|
676
|
-
});
|
|
677
|
-
}
|
|
678
|
-
catch (err) {
|
|
679
|
-
const collError = err instanceof Error ? err.message : String(err);
|
|
680
|
-
console.error(`\nā Failed to publish collection ${collection.id}: ${collError}\n`);
|
|
681
|
-
failedCollections.push({
|
|
682
|
-
id: collection.id,
|
|
683
|
-
error: collError
|
|
684
|
-
});
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
// Add collection results to summary
|
|
688
|
-
if (publishedCollections.length > 0) {
|
|
689
|
-
console.log(`ā
Successfully published ${publishedCollections.length} collection(s):`);
|
|
690
|
-
publishedCollections.forEach(coll => {
|
|
691
|
-
console.log(` - ${coll.name} (${coll.id}) v${coll.version}`);
|
|
692
|
-
});
|
|
693
|
-
console.log('');
|
|
694
|
-
}
|
|
695
|
-
if (failedCollections.length > 0) {
|
|
696
|
-
console.log(`ā Failed to publish ${failedCollections.length} collection(s):`);
|
|
697
|
-
failedCollections.forEach(coll => {
|
|
698
|
-
console.log(` - ${coll.id}: ${coll.error}`);
|
|
699
|
-
});
|
|
700
|
-
console.log('');
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
// Print summary if multiple packages
|
|
704
|
-
if (manifests.length > 1) {
|
|
705
|
-
console.log(`\n${'='.repeat(60)}`);
|
|
706
|
-
console.log(`š Publishing Summary`);
|
|
707
|
-
console.log(`${'='.repeat(60)}\n`);
|
|
708
|
-
if (publishedPackages.length > 0) {
|
|
709
|
-
console.log(`ā
Successfully published ${publishedPackages.length} package(s):`);
|
|
710
|
-
publishedPackages.forEach(pkg => {
|
|
711
|
-
console.log(` - ${pkg.name}@${pkg.version}`);
|
|
712
|
-
if (pkg.url) {
|
|
713
|
-
console.log(` ${pkg.url}`);
|
|
714
|
-
}
|
|
715
|
-
});
|
|
716
|
-
console.log('');
|
|
717
|
-
}
|
|
718
|
-
if (failedPackages.length > 0) {
|
|
719
|
-
console.log(`ā Failed to publish ${failedPackages.length} package(s):`);
|
|
720
|
-
failedPackages.forEach(pkg => {
|
|
721
|
-
console.log(` - ${pkg.name}: ${pkg.error}`);
|
|
722
|
-
});
|
|
723
|
-
console.log('');
|
|
724
|
-
// Provide hints for common permission errors
|
|
725
|
-
if (failedPackages.some(pkg => pkg.error.includes('Forbidden'))) {
|
|
726
|
-
console.log('š” Forbidden errors usually mean:');
|
|
727
|
-
console.log(' - The package already exists and you don\'t have permission to update it');
|
|
728
|
-
console.log(' - The package belongs to an organization and you\'re not a member with publish rights');
|
|
729
|
-
console.log(' - Try: prpm whoami (to check your organization memberships)');
|
|
730
|
-
console.log('');
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
// Success if we published any packages OR collections
|
|
735
|
-
success = publishedPackages.length > 0 || publishedCollections.length > 0;
|
|
736
|
-
if (failedPackages.length > 0 && publishedPackages.length === 0 && publishedCollections.length === 0) {
|
|
737
|
-
// Use the first failed package's error for telemetry
|
|
738
|
-
const firstError = failedPackages[0]?.error || 'Unknown error';
|
|
739
|
-
throw new errors_1.CLIError(firstError, 1);
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
catch (err) {
|
|
743
|
-
error = err instanceof Error ? err.message : String(err);
|
|
744
|
-
if (err instanceof errors_1.CLIError) {
|
|
745
|
-
throw err;
|
|
746
|
-
}
|
|
747
|
-
let errorMsg = `\nā Failed to publish package: ${error}\n`;
|
|
748
|
-
// Provide helpful hints based on error type
|
|
749
|
-
if (error.includes('Manifest validation failed')) {
|
|
750
|
-
errorMsg += '\nš” Common validation issues:\n';
|
|
751
|
-
errorMsg += ' - Missing required fields (name, version, description, format)\n';
|
|
752
|
-
errorMsg += ' - Invalid format or subtype values\n';
|
|
753
|
-
errorMsg += ' - Description too short (min 10 chars) or too long (max 500 chars)\n';
|
|
754
|
-
errorMsg += ' - Package name must be lowercase with hyphens only\n';
|
|
755
|
-
errorMsg += '\nš” For Claude skills specifically:\n';
|
|
756
|
-
errorMsg += ' - Add "subtype": "skill" to your prpm.json\n';
|
|
757
|
-
errorMsg += ' - Ensure files include a SKILL.md file\n';
|
|
758
|
-
errorMsg += ' - Package name must be max 64 characters\n';
|
|
759
|
-
errorMsg += '\nš” View the schema: prpm schema\n';
|
|
760
|
-
}
|
|
761
|
-
else if (error.includes('SKILL.md')) {
|
|
762
|
-
errorMsg += '\nš” Claude skills require:\n';
|
|
763
|
-
errorMsg += ' - A file named SKILL.md (all caps) in your package\n';
|
|
764
|
-
errorMsg += ' - "format": "claude" and "subtype": "skill" in prpm.json\n';
|
|
765
|
-
}
|
|
766
|
-
else if (error.includes('No manifest file found')) {
|
|
767
|
-
errorMsg += '\nš” Create a manifest file:\n';
|
|
768
|
-
errorMsg += ' - Run: prpm init\n';
|
|
769
|
-
errorMsg += ' - Or create prpm.json manually\n';
|
|
770
|
-
}
|
|
771
|
-
throw new errors_1.CLIError(errorMsg, 1);
|
|
772
|
-
}
|
|
773
|
-
finally {
|
|
774
|
-
// Track telemetry
|
|
775
|
-
await telemetry_1.telemetry.track({
|
|
776
|
-
command: 'publish',
|
|
777
|
-
success,
|
|
778
|
-
error,
|
|
779
|
-
duration: Date.now() - startTime,
|
|
780
|
-
data: {
|
|
781
|
-
packageName,
|
|
782
|
-
version,
|
|
783
|
-
dryRun: options.dryRun,
|
|
784
|
-
},
|
|
785
|
-
});
|
|
786
|
-
await telemetry_1.telemetry.shutdown();
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
/**
|
|
790
|
-
* Create the publish command
|
|
791
|
-
*/
|
|
792
|
-
function createPublishCommand() {
|
|
793
|
-
return new commander_1.Command('publish')
|
|
794
|
-
.description('Publish packages and collections to the registry')
|
|
795
|
-
.option('--access <type>', 'Package access (public or private) - overrides manifest setting')
|
|
796
|
-
.option('--tag <tag>', 'NPM-style tag (e.g., latest, beta)', 'latest')
|
|
797
|
-
.option('--dry-run', 'Validate package without publishing')
|
|
798
|
-
.option('--package <name>', 'Publish only a specific package from multi-package manifest')
|
|
799
|
-
.option('--collection <id>', 'Publish only a specific collection from manifest')
|
|
800
|
-
.action(async (options) => {
|
|
801
|
-
await handlePublish(options);
|
|
802
|
-
});
|
|
803
|
-
}
|