prpm 0.0.1 → 0.0.2

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.
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ /**
3
+ * Claude agent configuration utilities
4
+ * Handles applying user config to Claude agent YAML frontmatter
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.hasClaudeHeader = hasClaudeHeader;
8
+ exports.applyClaudeConfig = applyClaudeConfig;
9
+ exports.parseClaudeFrontmatter = parseClaudeFrontmatter;
10
+ /**
11
+ * Check if content has Claude agent YAML frontmatter
12
+ */
13
+ function hasClaudeHeader(content) {
14
+ return content.startsWith('---\n') && content.includes('name:');
15
+ }
16
+ /**
17
+ * Apply user's Claude agent config to agent file
18
+ * Merges user config with existing frontmatter, with user config taking precedence
19
+ */
20
+ function applyClaudeConfig(content, config) {
21
+ if (!hasClaudeHeader(content)) {
22
+ return content;
23
+ }
24
+ const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
25
+ if (!match) {
26
+ return content;
27
+ }
28
+ const [, frontmatterText, body] = match;
29
+ // Parse existing frontmatter
30
+ const frontmatter = {};
31
+ frontmatterText.split('\n').forEach(line => {
32
+ const colonIndex = line.indexOf(':');
33
+ if (colonIndex > 0) {
34
+ const key = line.substring(0, colonIndex).trim();
35
+ const value = line.substring(colonIndex + 1).trim();
36
+ frontmatter[key] = value;
37
+ }
38
+ });
39
+ // Apply user config overrides
40
+ if (config.tools !== undefined) {
41
+ frontmatter.tools = config.tools;
42
+ }
43
+ if (config.model !== undefined) {
44
+ frontmatter.model = config.model;
45
+ }
46
+ // Rebuild frontmatter
47
+ const lines = ['---'];
48
+ // Ensure required fields come first
49
+ if (frontmatter.name) {
50
+ lines.push(`name: ${frontmatter.name}`);
51
+ }
52
+ if (frontmatter.description) {
53
+ lines.push(`description: ${frontmatter.description}`);
54
+ }
55
+ // Add optional fields
56
+ const optionalFields = ['icon', 'tools', 'model'];
57
+ for (const field of optionalFields) {
58
+ if (frontmatter[field] && field !== 'name' && field !== 'description') {
59
+ lines.push(`${field}: ${frontmatter[field]}`);
60
+ }
61
+ }
62
+ // Add any other fields that might exist
63
+ for (const [key, value] of Object.entries(frontmatter)) {
64
+ if (!['name', 'description', 'icon', 'tools', 'model'].includes(key)) {
65
+ lines.push(`${key}: ${value}`);
66
+ }
67
+ }
68
+ lines.push('---');
69
+ return lines.join('\n') + '\n' + body;
70
+ }
71
+ /**
72
+ * Parse Claude agent frontmatter
73
+ */
74
+ function parseClaudeFrontmatter(content) {
75
+ const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
76
+ if (!match) {
77
+ return { frontmatter: {}, body: content };
78
+ }
79
+ const [, frontmatterText, body] = match;
80
+ // Simple YAML parsing (for basic key: value pairs)
81
+ const frontmatter = {};
82
+ frontmatterText.split('\n').forEach(line => {
83
+ const colonIndex = line.indexOf(':');
84
+ if (colonIndex > 0) {
85
+ const key = line.substring(0, colonIndex).trim();
86
+ const value = line.substring(colonIndex + 1).trim();
87
+ frontmatter[key] = value;
88
+ }
89
+ });
90
+ return { frontmatter, body };
91
+ }
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ /**
3
+ * Cursor MDC header configuration utilities
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.applyCursorConfig = applyCursorConfig;
7
+ exports.hasMDCHeader = hasMDCHeader;
8
+ exports.addMDCHeader = addMDCHeader;
9
+ /**
10
+ * Apply cursor config to MDC header in content
11
+ * Replaces configurable fields in the YAML frontmatter
12
+ */
13
+ function applyCursorConfig(content, config) {
14
+ // Check if content has MDC header (YAML frontmatter)
15
+ if (!content.startsWith('---')) {
16
+ return content;
17
+ }
18
+ const lines = content.split('\n');
19
+ const headerEndIndex = lines.findIndex((line, index) => index > 0 && line === '---');
20
+ if (headerEndIndex === -1) {
21
+ // Malformed header, return as-is
22
+ return content;
23
+ }
24
+ // Extract header lines (excluding the --- markers)
25
+ const headerLines = lines.slice(1, headerEndIndex);
26
+ const bodyLines = lines.slice(headerEndIndex + 1);
27
+ // Parse and update header
28
+ const updatedHeaderLines = [];
29
+ let i = 0;
30
+ while (i < headerLines.length) {
31
+ const line = headerLines[i];
32
+ // Check for fields that should be replaced by config
33
+ if (line.startsWith('version:') && config.version) {
34
+ updatedHeaderLines.push(`version: "${config.version}"`);
35
+ i++;
36
+ }
37
+ else if (line.startsWith('globs:') && config.globs) {
38
+ // Replace globs array
39
+ updatedHeaderLines.push('globs:');
40
+ config.globs.forEach((glob) => {
41
+ updatedHeaderLines.push(` - "${glob}"`);
42
+ });
43
+ // Skip existing globs in the original header
44
+ i++;
45
+ while (i < headerLines.length && headerLines[i].startsWith(' - ')) {
46
+ i++;
47
+ }
48
+ }
49
+ else if (line.startsWith('alwaysApply:') && config.alwaysApply !== undefined) {
50
+ updatedHeaderLines.push(`alwaysApply: ${config.alwaysApply}`);
51
+ i++;
52
+ }
53
+ else if (line.startsWith('author:') && config.author) {
54
+ // Replace existing author
55
+ updatedHeaderLines.push(`author: "${config.author}"`);
56
+ i++;
57
+ }
58
+ else if (line.startsWith('tags:') && config.tags) {
59
+ // Replace tags array
60
+ updatedHeaderLines.push('tags:');
61
+ config.tags.forEach((tag) => {
62
+ updatedHeaderLines.push(` - "${tag}"`);
63
+ });
64
+ // Skip existing tags in the original header
65
+ i++;
66
+ while (i < headerLines.length && headerLines[i].startsWith(' - ')) {
67
+ i++;
68
+ }
69
+ }
70
+ else {
71
+ // Keep existing line
72
+ updatedHeaderLines.push(line);
73
+ i++;
74
+ }
75
+ }
76
+ // Add new fields if they don't exist
77
+ const hasAuthor = updatedHeaderLines.some(line => line.startsWith('author:'));
78
+ const hasTags = updatedHeaderLines.some(line => line.startsWith('tags:'));
79
+ if (config.author && !hasAuthor) {
80
+ updatedHeaderLines.push(`author: "${config.author}"`);
81
+ }
82
+ if (config.tags && !hasTags) {
83
+ updatedHeaderLines.push('tags:');
84
+ config.tags.forEach((tag) => {
85
+ updatedHeaderLines.push(` - "${tag}"`);
86
+ });
87
+ }
88
+ // Reconstruct content
89
+ return ['---', ...updatedHeaderLines, '---', ...bodyLines].join('\n');
90
+ }
91
+ /**
92
+ * Check if content has valid MDC header (YAML frontmatter)
93
+ * A valid MDC header must:
94
+ * 1. Start with ---
95
+ * 2. Have a closing --- on its own line
96
+ * 3. Have at least a description field
97
+ */
98
+ function hasMDCHeader(content) {
99
+ if (!content.startsWith('---\n')) {
100
+ return false;
101
+ }
102
+ const lines = content.split('\n');
103
+ const headerEndIndex = lines.findIndex((line, index) => index > 0 && line === '---');
104
+ // Must have closing ---
105
+ if (headerEndIndex === -1) {
106
+ return false;
107
+ }
108
+ // Extract header lines (excluding the --- markers)
109
+ const headerLines = lines.slice(1, headerEndIndex);
110
+ // Must have at least one valid YAML field (typically description)
111
+ const hasValidField = headerLines.some(line => {
112
+ const trimmed = line.trim();
113
+ return trimmed.length > 0 && trimmed.includes(':') && !trimmed.startsWith('#');
114
+ });
115
+ return hasValidField;
116
+ }
117
+ /**
118
+ * Add MDC header to content if missing
119
+ * Creates a basic YAML frontmatter with description
120
+ */
121
+ function addMDCHeader(content, packageDescription) {
122
+ const description = packageDescription || 'Cursor rule for coding standards and best practices';
123
+ const header = [
124
+ '---',
125
+ `description: "${description}"`,
126
+ '---',
127
+ '',
128
+ ].join('\n');
129
+ return header + content;
130
+ }
@@ -12,6 +12,7 @@ exports.saveFile = saveFile;
12
12
  exports.deleteFile = deleteFile;
13
13
  exports.fileExists = fileExists;
14
14
  exports.generateId = generateId;
15
+ exports.stripAuthorNamespace = stripAuthorNamespace;
15
16
  const fs_1 = require("fs");
16
17
  const path_1 = __importDefault(require("path"));
17
18
  /**
@@ -21,8 +22,24 @@ function getDestinationDir(type) {
21
22
  switch (type) {
22
23
  case 'cursor':
23
24
  return '.cursor/rules';
25
+ case 'cursor-agent':
26
+ return '.cursor/agents';
27
+ case 'cursor-slash-command':
28
+ return '.cursor/commands';
24
29
  case 'claude':
25
30
  return '.claude/agents';
31
+ case 'claude-agent':
32
+ return '.claude/agents';
33
+ case 'claude-skill':
34
+ return '.claude/skills';
35
+ case 'claude-slash-command':
36
+ return '.claude/commands';
37
+ case 'continue':
38
+ return '.continue/rules';
39
+ case 'windsurf':
40
+ return '.windsurf/rules';
41
+ case 'generic':
42
+ return '.prompts';
26
43
  default:
27
44
  throw new Error(`Unknown package type: ${type}`);
28
45
  }
@@ -92,3 +109,16 @@ function generateId(filename) {
92
109
  .replace(/[^a-z0-9]+/g, '-')
93
110
  .replace(/^-+|-+$/g, '');
94
111
  }
112
+ /**
113
+ * Strip author namespace from package ID and return just the package name
114
+ * @example
115
+ * stripAuthorNamespace('@community/git-workflow-manager') // 'git-workflow-manager'
116
+ * stripAuthorNamespace('community/git-workflow-manager') // 'git-workflow-manager'
117
+ * stripAuthorNamespace('@wshobson/commands/agent-orchestration/improve-agent') // 'improve-agent'
118
+ * stripAuthorNamespace('git-workflow-manager') // 'git-workflow-manager'
119
+ */
120
+ function stripAuthorNamespace(packageId) {
121
+ // Split by '/' and get the last segment (the actual package name)
122
+ const parts = packageId.split('/');
123
+ return parts[parts.length - 1];
124
+ }
@@ -14,6 +14,10 @@ exports.getLockedVersion = getLockedVersion;
14
14
  exports.isLockfileOutOfSync = isLockfileOutOfSync;
15
15
  exports.mergeLockfiles = mergeLockfiles;
16
16
  exports.pruneLockfile = pruneLockfile;
17
+ exports.addPackage = addPackage;
18
+ exports.removePackage = removePackage;
19
+ exports.listPackages = listPackages;
20
+ exports.getPackage = getPackage;
17
21
  const fs_1 = require("fs");
18
22
  const path_1 = require("path");
19
23
  const crypto_1 = require("crypto");
@@ -70,6 +74,7 @@ function addToLockfile(lockfile, packageId, packageInfo) {
70
74
  dependencies: packageInfo.dependencies,
71
75
  type: packageInfo.type,
72
76
  format: packageInfo.format,
77
+ installedPath: packageInfo.installedPath,
73
78
  };
74
79
  lockfile.generated = new Date().toISOString();
75
80
  }
@@ -180,3 +185,55 @@ function pruneLockfile(lockfile, requiredPackages) {
180
185
  pruned.generated = new Date().toISOString();
181
186
  return pruned;
182
187
  }
188
+ /**
189
+ * Add package to lock file (convenience wrapper)
190
+ */
191
+ async function addPackage(packageInfo) {
192
+ const lockfile = (await readLockfile()) || createLockfile();
193
+ addToLockfile(lockfile, packageInfo.id, {
194
+ version: packageInfo.version,
195
+ tarballUrl: packageInfo.tarballUrl,
196
+ dependencies: packageInfo.dependencies,
197
+ type: packageInfo.type,
198
+ format: packageInfo.format,
199
+ installedPath: packageInfo.installedPath,
200
+ });
201
+ await writeLockfile(lockfile);
202
+ }
203
+ /**
204
+ * Remove package from lock file
205
+ */
206
+ async function removePackage(packageId) {
207
+ const lockfile = await readLockfile();
208
+ if (!lockfile || !lockfile.packages[packageId]) {
209
+ return null;
210
+ }
211
+ const removed = lockfile.packages[packageId];
212
+ delete lockfile.packages[packageId];
213
+ lockfile.generated = new Date().toISOString();
214
+ await writeLockfile(lockfile);
215
+ return removed;
216
+ }
217
+ /**
218
+ * List all packages in lock file
219
+ */
220
+ async function listPackages() {
221
+ const lockfile = await readLockfile();
222
+ if (!lockfile) {
223
+ return [];
224
+ }
225
+ return Object.entries(lockfile.packages).map(([id, pkg]) => ({
226
+ id,
227
+ ...pkg,
228
+ }));
229
+ }
230
+ /**
231
+ * Get a specific package from lock file
232
+ */
233
+ async function getPackage(packageId) {
234
+ const lockfile = await readLockfile();
235
+ if (!lockfile || !lockfile.packages[packageId]) {
236
+ return null;
237
+ }
238
+ return lockfile.packages[packageId];
239
+ }
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ /**
3
+ * Converter for Claude marketplace.json format to PRPM manifest
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.marketplaceToManifest = marketplaceToManifest;
7
+ exports.validateMarketplaceJson = validateMarketplaceJson;
8
+ /**
9
+ * Convert marketplace.json to PRPM manifest format
10
+ *
11
+ * Strategy:
12
+ * - If multiple plugins exist, create a manifest for the first plugin (user can publish others separately)
13
+ * - If the plugin has agents/skills/commands, prefer those over the root plugin info
14
+ * - Map marketplace fields to PRPM manifest fields
15
+ *
16
+ * @param marketplace - The marketplace.json content
17
+ * @param pluginIndex - Which plugin to convert (default: 0, for the first plugin)
18
+ * @returns PRPM manifest
19
+ */
20
+ function marketplaceToManifest(marketplace, pluginIndex = 0) {
21
+ if (!marketplace.plugins || marketplace.plugins.length === 0) {
22
+ throw new Error('marketplace.json must contain at least one plugin');
23
+ }
24
+ if (pluginIndex >= marketplace.plugins.length) {
25
+ throw new Error(`Plugin index ${pluginIndex} out of range. Found ${marketplace.plugins.length} plugins.`);
26
+ }
27
+ const plugin = marketplace.plugins[pluginIndex];
28
+ // Determine package type based on what the plugin contains
29
+ let type = 'claude';
30
+ if (plugin.agents && plugin.agents.length > 0) {
31
+ type = 'claude';
32
+ }
33
+ else if (plugin.skills && plugin.skills.length > 0) {
34
+ type = 'claude';
35
+ }
36
+ else if (plugin.commands && plugin.commands.length > 0) {
37
+ type = 'claude';
38
+ }
39
+ // Generate package name from plugin name
40
+ // Format: @owner/plugin-name
41
+ const packageName = generatePackageName(marketplace.owner, plugin.name);
42
+ // Collect all files that should be included
43
+ const files = collectFiles(plugin);
44
+ // Determine the main file
45
+ const main = determineMainFile(plugin);
46
+ // Collect keywords from both marketplace and plugin
47
+ const keywords = [
48
+ ...(marketplace.keywords || []),
49
+ ...(plugin.keywords || []),
50
+ ].slice(0, 20); // Max 20 keywords
51
+ // Extract tags from keywords (first 10)
52
+ const tags = keywords.slice(0, 10);
53
+ const manifest = {
54
+ name: packageName,
55
+ version: plugin.version || marketplace.version || '1.0.0',
56
+ description: plugin.description || marketplace.description,
57
+ type,
58
+ author: plugin.author || marketplace.owner,
59
+ files,
60
+ tags,
61
+ keywords,
62
+ };
63
+ // Add optional fields if available
64
+ if (marketplace.githubUrl) {
65
+ manifest.repository = marketplace.githubUrl;
66
+ }
67
+ if (marketplace.websiteUrl) {
68
+ manifest.homepage = marketplace.websiteUrl;
69
+ }
70
+ if (plugin.category) {
71
+ manifest.category = plugin.category;
72
+ }
73
+ if (main) {
74
+ manifest.main = main;
75
+ }
76
+ return manifest;
77
+ }
78
+ /**
79
+ * Generate PRPM-compatible package name from owner and plugin name
80
+ */
81
+ function generatePackageName(owner, pluginName) {
82
+ // Sanitize owner and plugin name
83
+ const sanitizedOwner = owner.toLowerCase().replace(/[^a-z0-9-]/g, '-');
84
+ const sanitizedName = pluginName.toLowerCase().replace(/[^a-z0-9-]/g, '-');
85
+ // Remove leading/trailing hyphens
86
+ const cleanOwner = sanitizedOwner.replace(/^-+|-+$/g, '');
87
+ const cleanName = sanitizedName.replace(/^-+|-+$/g, '');
88
+ return `@${cleanOwner}/${cleanName}`;
89
+ }
90
+ /**
91
+ * Collect all files referenced in the plugin
92
+ */
93
+ function collectFiles(plugin) {
94
+ const files = new Set();
95
+ // Add plugin source if it's a file path
96
+ if (plugin.source && !plugin.source.startsWith('http')) {
97
+ files.add(plugin.source);
98
+ }
99
+ // Add agent files
100
+ if (plugin.agents) {
101
+ for (const agent of plugin.agents) {
102
+ if (agent.source && !agent.source.startsWith('http')) {
103
+ files.add(agent.source);
104
+ }
105
+ }
106
+ }
107
+ // Add skill files
108
+ if (plugin.skills) {
109
+ for (const skill of plugin.skills) {
110
+ if (skill.source && !skill.source.startsWith('http')) {
111
+ files.add(skill.source);
112
+ }
113
+ }
114
+ }
115
+ // Add command files
116
+ if (plugin.commands) {
117
+ for (const command of plugin.commands) {
118
+ if (command.source && !command.source.startsWith('http')) {
119
+ files.add(command.source);
120
+ }
121
+ }
122
+ }
123
+ // Add standard files if they're not already included
124
+ const standardFiles = ['README.md', 'LICENSE', '.claude/marketplace.json'];
125
+ for (const file of standardFiles) {
126
+ files.add(file);
127
+ }
128
+ return Array.from(files);
129
+ }
130
+ /**
131
+ * Determine the main entry file for the package
132
+ * Only set main if there's a single clear entry point
133
+ */
134
+ function determineMainFile(plugin) {
135
+ const agentCount = plugin.agents?.length || 0;
136
+ const skillCount = plugin.skills?.length || 0;
137
+ const commandCount = plugin.commands?.length || 0;
138
+ // Only set main if there's exactly one item total
139
+ const totalCount = agentCount + skillCount + commandCount;
140
+ if (totalCount !== 1) {
141
+ // Multiple items or no items - no clear main file
142
+ return undefined;
143
+ }
144
+ // Single agent
145
+ if (agentCount === 1) {
146
+ const source = plugin.agents[0].source;
147
+ if (source && !source.startsWith('http')) {
148
+ return source;
149
+ }
150
+ }
151
+ // Single skill
152
+ if (skillCount === 1) {
153
+ const source = plugin.skills[0].source;
154
+ if (source && !source.startsWith('http')) {
155
+ return source;
156
+ }
157
+ }
158
+ // Single command
159
+ if (commandCount === 1) {
160
+ const source = plugin.commands[0].source;
161
+ if (source && !source.startsWith('http')) {
162
+ return source;
163
+ }
164
+ }
165
+ // Otherwise, use plugin source if available
166
+ if (plugin.source && !plugin.source.startsWith('http')) {
167
+ return plugin.source;
168
+ }
169
+ return undefined;
170
+ }
171
+ /**
172
+ * Validate marketplace.json structure
173
+ */
174
+ function validateMarketplaceJson(data) {
175
+ if (!data || typeof data !== 'object') {
176
+ return false;
177
+ }
178
+ const marketplace = data;
179
+ // Check required fields
180
+ if (!marketplace.name || typeof marketplace.name !== 'string') {
181
+ return false;
182
+ }
183
+ if (!marketplace.owner || typeof marketplace.owner !== 'string') {
184
+ return false;
185
+ }
186
+ if (!marketplace.description || typeof marketplace.description !== 'string') {
187
+ return false;
188
+ }
189
+ if (!Array.isArray(marketplace.plugins) || marketplace.plugins.length === 0) {
190
+ return false;
191
+ }
192
+ // Validate first plugin has required fields
193
+ const plugin = marketplace.plugins[0];
194
+ if (!plugin.name || !plugin.description || !plugin.version) {
195
+ return false;
196
+ }
197
+ return true;
198
+ }
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ /**
3
+ * JSON Schema validation for PRPM manifests
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.validateManifestSchema = validateManifestSchema;
10
+ exports.getManifestSchema = getManifestSchema;
11
+ const ajv_1 = __importDefault(require("ajv"));
12
+ const ajv_formats_1 = __importDefault(require("ajv-formats"));
13
+ const fs_1 = require("fs");
14
+ const path_1 = require("path");
15
+ // Load the JSON schema
16
+ const schemaPath = (0, path_1.join)(__dirname, '../../schemas/prpm-manifest.schema.json');
17
+ let schema;
18
+ try {
19
+ schema = JSON.parse((0, fs_1.readFileSync)(schemaPath, 'utf-8'));
20
+ }
21
+ catch (error) {
22
+ // Schema file not found, validation will be skipped
23
+ console.warn('⚠️ Could not load manifest schema, skipping schema validation');
24
+ }
25
+ /**
26
+ * Validate manifest against JSON schema
27
+ */
28
+ function validateManifestSchema(manifest) {
29
+ if (!schema) {
30
+ // Schema not loaded, skip validation
31
+ return { valid: true };
32
+ }
33
+ const ajv = new ajv_1.default({
34
+ allErrors: true,
35
+ verbose: true,
36
+ });
37
+ (0, ajv_formats_1.default)(ajv);
38
+ const validate = ajv.compile(schema);
39
+ const valid = validate(manifest);
40
+ if (!valid && validate.errors) {
41
+ const errors = validate.errors.map(err => {
42
+ const path = err.instancePath || 'manifest';
43
+ const message = err.message || 'validation failed';
44
+ // Format error messages to be more user-friendly
45
+ if (err.keyword === 'required') {
46
+ const missingProp = err.params.missingProperty;
47
+ return `Missing required field: ${missingProp}`;
48
+ }
49
+ if (err.keyword === 'pattern') {
50
+ return `${path}: ${message}. Value does not match required pattern.`;
51
+ }
52
+ if (err.keyword === 'enum') {
53
+ const allowedValues = err.params.allowedValues;
54
+ return `${path}: ${message}. Allowed values: ${allowedValues.join(', ')}`;
55
+ }
56
+ if (err.keyword === 'minLength' || err.keyword === 'maxLength') {
57
+ const limit = err.params.limit;
58
+ return `${path}: ${message} (${err.keyword}: ${limit})`;
59
+ }
60
+ if (err.keyword === 'oneOf') {
61
+ return `${path}: must match exactly one schema (check if files array uses either all strings or all objects, not mixed)`;
62
+ }
63
+ return `${path}: ${message}`;
64
+ });
65
+ return { valid: false, errors };
66
+ }
67
+ return { valid: true };
68
+ }
69
+ /**
70
+ * Get the JSON schema (for documentation/export purposes)
71
+ */
72
+ function getManifestSchema() {
73
+ return schema;
74
+ }
@@ -126,11 +126,16 @@ class Telemetry {
126
126
  async shutdown() {
127
127
  if (this.posthog) {
128
128
  try {
129
+ // Flush any pending events before shutdown
130
+ await this.posthog.flush();
129
131
  await this.posthog.shutdown();
130
132
  }
131
133
  catch (error) {
132
134
  // Silently fail
133
135
  }
136
+ finally {
137
+ this.posthog = null;
138
+ }
134
139
  }
135
140
  }
136
141
  // Send to PostHog
package/dist/index.js CHANGED
@@ -5,9 +5,8 @@
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const commander_1 = require("commander");
8
- const add_1 = require("./commands/add");
9
8
  const list_1 = require("./commands/list");
10
- const remove_1 = require("./commands/remove");
9
+ const uninstall_1 = require("./commands/uninstall");
11
10
  const index_1 = require("./commands/index");
12
11
  const telemetry_1 = require("./commands/telemetry");
13
12
  const search_1 = require("./commands/search");
@@ -18,16 +17,16 @@ const publish_1 = require("./commands/publish");
18
17
  const login_1 = require("./commands/login");
19
18
  const whoami_1 = require("./commands/whoami");
20
19
  const collections_1 = require("./commands/collections");
21
- const deps_1 = require("./commands/deps");
22
20
  const outdated_1 = require("./commands/outdated");
23
21
  const update_1 = require("./commands/update");
24
22
  const upgrade_1 = require("./commands/upgrade");
23
+ const schema_1 = require("./commands/schema");
25
24
  const telemetry_2 = require("./core/telemetry");
26
25
  const program = new commander_1.Command();
27
26
  program
28
27
  .name('prpm')
29
28
  .description('Prompt Package Manager - Install and manage prompt-based files')
30
- .version('1.2.0');
29
+ .version('0.0.1');
31
30
  // Registry commands (new)
32
31
  program.addCommand((0, search_1.createSearchCommand)());
33
32
  program.addCommand((0, install_1.createInstallCommand)());
@@ -37,16 +36,16 @@ program.addCommand((0, publish_1.createPublishCommand)());
37
36
  program.addCommand((0, login_1.createLoginCommand)());
38
37
  program.addCommand((0, whoami_1.createWhoamiCommand)());
39
38
  program.addCommand((0, collections_1.createCollectionsCommand)());
40
- program.addCommand((0, deps_1.createDepsCommand)());
41
39
  program.addCommand((0, outdated_1.createOutdatedCommand)());
42
40
  program.addCommand((0, update_1.createUpdateCommand)());
43
41
  program.addCommand((0, upgrade_1.createUpgradeCommand)());
44
42
  // Local file commands (existing)
45
- program.addCommand((0, add_1.createAddCommand)());
46
43
  program.addCommand((0, list_1.createListCommand)());
47
- program.addCommand((0, remove_1.createRemoveCommand)());
44
+ program.addCommand((0, uninstall_1.createUninstallCommand)());
48
45
  program.addCommand((0, index_1.createIndexCommand)());
49
46
  program.addCommand((0, telemetry_1.createTelemetryCommand)());
47
+ // Utility commands
48
+ program.addCommand((0, schema_1.createSchemaCommand)());
50
49
  // Parse command line arguments
51
50
  program.parse();
52
51
  // Cleanup telemetry on exit
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ /**
3
+ * Registry API types for CLI
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });