prpm 1.2.1 → 2.0.1
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/README.md +90 -862
- package/dist/index.js +23233 -65
- package/dist/schemas/agents-md.schema.json +24 -0
- package/dist/schemas/aider.schema.json +24 -0
- package/dist/schemas/canonical.schema.json +435 -0
- package/dist/schemas/claude-agent.schema.json +62 -0
- package/dist/schemas/claude-hook.schema.json +70 -0
- package/dist/schemas/claude-plugin.schema.json +122 -0
- package/dist/schemas/claude-skill.schema.json +51 -0
- package/dist/schemas/claude-slash-command.schema.json +77 -0
- package/dist/schemas/claude.schema.json +52 -0
- package/dist/schemas/continue.schema.json +98 -0
- package/dist/schemas/copilot.schema.json +76 -0
- package/dist/schemas/cursor-command.schema.json +27 -0
- package/dist/schemas/cursor-hooks.schema.json +59 -0
- package/dist/schemas/cursor.schema.json +74 -0
- package/dist/schemas/droid-hook.schema.json +103 -0
- package/dist/schemas/droid-skill.schema.json +46 -0
- package/dist/schemas/droid-slash-command.schema.json +53 -0
- package/dist/schemas/droid.schema.json +46 -0
- package/dist/schemas/format-registry.schema.json +99 -0
- package/dist/schemas/gemini-md.schema.json +24 -0
- package/dist/schemas/gemini.schema.json +30 -0
- package/dist/schemas/kiro-agent.schema.json +146 -0
- package/dist/schemas/kiro-hook.schema.json +120 -0
- package/dist/schemas/kiro-steering.schema.json +74 -0
- package/dist/schemas/mcp-server.schema.json +130 -0
- package/dist/schemas/opencode-slash-command.schema.json +60 -0
- package/dist/schemas/opencode.schema.json +111 -0
- package/dist/schemas/prpm-manifest.schema.json +733 -0
- package/dist/schemas/replit.schema.json +21 -0
- package/dist/schemas/ruler.schema.json +22 -0
- package/dist/schemas/trae.schema.json +24 -0
- package/dist/schemas/windsurf.schema.json +22 -0
- package/dist/schemas/zencoder.schema.json +51 -0
- package/package.json +20 -14
- package/schemas/prpm-manifest.schema.json +465 -39
- package/dist/__tests__/e2e/test-helpers.js +0 -150
- package/dist/commands/collections.js +0 -606
- package/dist/commands/index.js +0 -186
- package/dist/commands/info.js +0 -82
- package/dist/commands/install.js +0 -477
- package/dist/commands/list.js +0 -166
- package/dist/commands/login.js +0 -281
- package/dist/commands/outdated.js +0 -128
- package/dist/commands/popular.js +0 -27
- package/dist/commands/publish.js +0 -274
- package/dist/commands/schema.js +0 -37
- package/dist/commands/search.js +0 -404
- package/dist/commands/telemetry.js +0 -103
- package/dist/commands/trending.js +0 -76
- package/dist/commands/uninstall.js +0 -77
- package/dist/commands/update.js +0 -121
- package/dist/commands/upgrade.js +0 -121
- package/dist/commands/whoami.js +0 -75
- 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/filesystem.js +0 -124
- package/dist/core/lockfile.js +0 -239
- package/dist/core/marketplace-converter.js +0 -198
- package/dist/core/registry-client.js +0 -265
- package/dist/core/schema-validator.js +0 -74
- package/dist/core/telemetry.js +0 -175
- package/dist/core/user-config.js +0 -79
- package/dist/types/registry.js +0 -5
- package/dist/types.js +0 -5
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Registry API Client
|
|
4
|
-
* Handles all communication with the PRMP Registry
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.RegistryClient = void 0;
|
|
8
|
-
exports.getRegistryClient = getRegistryClient;
|
|
9
|
-
class RegistryClient {
|
|
10
|
-
constructor(config) {
|
|
11
|
-
this.baseUrl = config.url.replace(/\/$/, ''); // Remove trailing slash
|
|
12
|
-
this.token = config.token;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Search for packages in the registry
|
|
16
|
-
*/
|
|
17
|
-
async search(query, options) {
|
|
18
|
-
const params = new URLSearchParams({ q: query });
|
|
19
|
-
if (options?.type)
|
|
20
|
-
params.append('type', options.type);
|
|
21
|
-
if (options?.tags)
|
|
22
|
-
options.tags.forEach(tag => params.append('tags', tag));
|
|
23
|
-
if (options?.limit)
|
|
24
|
-
params.append('limit', options.limit.toString());
|
|
25
|
-
if (options?.offset)
|
|
26
|
-
params.append('offset', options.offset.toString());
|
|
27
|
-
const response = await this.fetch(`/api/v1/search?${params}`);
|
|
28
|
-
return response.json();
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Get package information
|
|
32
|
-
*/
|
|
33
|
-
async getPackage(packageId) {
|
|
34
|
-
const response = await this.fetch(`/api/v1/packages/${packageId}`);
|
|
35
|
-
return response.json();
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Get specific package version
|
|
39
|
-
*/
|
|
40
|
-
async getPackageVersion(packageId, version) {
|
|
41
|
-
const response = await this.fetch(`/api/v1/packages/${packageId}/${version}`);
|
|
42
|
-
return response.json();
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Get package dependencies
|
|
46
|
-
*/
|
|
47
|
-
async getPackageDependencies(packageId, version) {
|
|
48
|
-
const versionPath = version ? `/${version}` : '';
|
|
49
|
-
const response = await this.fetch(`/api/v1/packages/${packageId}${versionPath}/dependencies`);
|
|
50
|
-
return response.json();
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Get all versions for a package
|
|
54
|
-
*/
|
|
55
|
-
async getPackageVersions(packageId) {
|
|
56
|
-
const response = await this.fetch(`/api/v1/packages/${packageId}/versions`);
|
|
57
|
-
return response.json();
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Resolve dependency tree
|
|
61
|
-
*/
|
|
62
|
-
async resolveDependencies(packageId, version) {
|
|
63
|
-
const params = new URLSearchParams();
|
|
64
|
-
if (version)
|
|
65
|
-
params.append('version', version);
|
|
66
|
-
const response = await this.fetch(`/api/v1/packages/${packageId}/resolve?${params}`);
|
|
67
|
-
return response.json();
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Download package tarball
|
|
71
|
-
*/
|
|
72
|
-
async downloadPackage(tarballUrl, options = {}) {
|
|
73
|
-
// If format is specified and tarballUrl is from registry, append format param
|
|
74
|
-
let url = tarballUrl;
|
|
75
|
-
if (options.format && tarballUrl.includes(this.baseUrl)) {
|
|
76
|
-
const urlObj = new URL(tarballUrl);
|
|
77
|
-
urlObj.searchParams.set('format', options.format);
|
|
78
|
-
url = urlObj.toString();
|
|
79
|
-
}
|
|
80
|
-
const response = await fetch(url);
|
|
81
|
-
if (!response.ok) {
|
|
82
|
-
throw new Error(`Failed to download package: ${response.statusText}`);
|
|
83
|
-
}
|
|
84
|
-
const arrayBuffer = await response.arrayBuffer();
|
|
85
|
-
return Buffer.from(arrayBuffer);
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Get trending packages
|
|
89
|
-
*/
|
|
90
|
-
async getTrending(type, limit = 20) {
|
|
91
|
-
const params = new URLSearchParams({ limit: limit.toString() });
|
|
92
|
-
if (type)
|
|
93
|
-
params.append('type', type);
|
|
94
|
-
const response = await this.fetch(`/api/v1/search/trending?${params}`);
|
|
95
|
-
const data = await response.json();
|
|
96
|
-
return data.packages;
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Get featured packages
|
|
100
|
-
*/
|
|
101
|
-
async getFeatured(type, limit = 20) {
|
|
102
|
-
const params = new URLSearchParams({ limit: limit.toString() });
|
|
103
|
-
if (type)
|
|
104
|
-
params.append('type', type);
|
|
105
|
-
const response = await this.fetch(`/api/v1/search/featured?${params}`);
|
|
106
|
-
const data = await response.json();
|
|
107
|
-
return data.packages;
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Publish a package (requires authentication)
|
|
111
|
-
*/
|
|
112
|
-
async publish(manifest, tarball) {
|
|
113
|
-
if (!this.token) {
|
|
114
|
-
throw new Error('Authentication required. Run `prpm login` first.');
|
|
115
|
-
}
|
|
116
|
-
const formData = new FormData();
|
|
117
|
-
formData.append('manifest', JSON.stringify(manifest));
|
|
118
|
-
formData.append('tarball', new Blob([tarball]), 'package.tar.gz');
|
|
119
|
-
const response = await this.fetch('/api/v1/packages', {
|
|
120
|
-
method: 'POST',
|
|
121
|
-
body: formData,
|
|
122
|
-
});
|
|
123
|
-
return response.json();
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Login and get authentication token
|
|
127
|
-
*/
|
|
128
|
-
async login() {
|
|
129
|
-
// This will open browser for GitHub OAuth
|
|
130
|
-
// For now, return placeholder - will implement OAuth flow
|
|
131
|
-
throw new Error('Login not yet implemented. Coming soon!');
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Get current user info
|
|
135
|
-
*/
|
|
136
|
-
async whoami() {
|
|
137
|
-
if (!this.token) {
|
|
138
|
-
throw new Error('Not authenticated. Run `prpm login` first.');
|
|
139
|
-
}
|
|
140
|
-
const response = await this.fetch('/api/v1/auth/me');
|
|
141
|
-
return response.json();
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* Get collections
|
|
145
|
-
*/
|
|
146
|
-
async getCollections(options) {
|
|
147
|
-
const params = new URLSearchParams();
|
|
148
|
-
if (options?.category)
|
|
149
|
-
params.append('category', options.category);
|
|
150
|
-
if (options?.tag)
|
|
151
|
-
params.append('tag', options.tag);
|
|
152
|
-
if (options?.official)
|
|
153
|
-
params.append('official', 'true');
|
|
154
|
-
if (options?.scope)
|
|
155
|
-
params.append('scope', options.scope);
|
|
156
|
-
if (options?.limit)
|
|
157
|
-
params.append('limit', options.limit.toString());
|
|
158
|
-
if (options?.offset)
|
|
159
|
-
params.append('offset', options.offset.toString());
|
|
160
|
-
const response = await this.fetch(`/api/v1/collections?${params}`);
|
|
161
|
-
return response.json();
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Get collection details
|
|
165
|
-
*/
|
|
166
|
-
async getCollection(scope, id, version) {
|
|
167
|
-
const versionPath = version ? `/${version}` : '/1.0.0';
|
|
168
|
-
const response = await this.fetch(`/api/v1/collections/${scope}/${id}${versionPath}`);
|
|
169
|
-
return response.json();
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* Install collection (get installation plan)
|
|
173
|
-
*/
|
|
174
|
-
async installCollection(options) {
|
|
175
|
-
const params = new URLSearchParams();
|
|
176
|
-
if (options.format)
|
|
177
|
-
params.append('format', options.format);
|
|
178
|
-
if (options.skipOptional)
|
|
179
|
-
params.append('skipOptional', 'true');
|
|
180
|
-
const versionPath = options.version ? `@${options.version}` : '';
|
|
181
|
-
const response = await this.fetch(`/api/v1/collections/${options.scope}/${options.id}${versionPath}/install?${params}`, { method: 'POST' });
|
|
182
|
-
return response.json();
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* Create a collection (requires authentication)
|
|
186
|
-
*/
|
|
187
|
-
async createCollection(data) {
|
|
188
|
-
if (!this.token) {
|
|
189
|
-
throw new Error('Authentication required. Run `prpm login` first.');
|
|
190
|
-
}
|
|
191
|
-
const response = await this.fetch('/api/v1/collections', {
|
|
192
|
-
method: 'POST',
|
|
193
|
-
body: JSON.stringify(data),
|
|
194
|
-
});
|
|
195
|
-
return response.json();
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Helper method for making authenticated requests with retry logic
|
|
199
|
-
*/
|
|
200
|
-
async fetch(path, options = {}, retries = 3) {
|
|
201
|
-
const url = `${this.baseUrl}${path}`;
|
|
202
|
-
const headers = {
|
|
203
|
-
'Content-Type': 'application/json',
|
|
204
|
-
...options.headers,
|
|
205
|
-
};
|
|
206
|
-
if (this.token) {
|
|
207
|
-
headers['Authorization'] = `Bearer ${this.token}`;
|
|
208
|
-
}
|
|
209
|
-
let lastError = null;
|
|
210
|
-
for (let attempt = 0; attempt < retries; attempt++) {
|
|
211
|
-
try {
|
|
212
|
-
const response = await fetch(url, {
|
|
213
|
-
...options,
|
|
214
|
-
headers,
|
|
215
|
-
});
|
|
216
|
-
// Handle rate limiting with retry
|
|
217
|
-
if (response.status === 429) {
|
|
218
|
-
const retryAfter = response.headers.get('Retry-After');
|
|
219
|
-
const waitTime = retryAfter ? parseInt(retryAfter) * 1000 : Math.pow(2, attempt) * 1000;
|
|
220
|
-
if (attempt < retries - 1) {
|
|
221
|
-
await new Promise(resolve => setTimeout(resolve, waitTime));
|
|
222
|
-
continue;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
// Handle server errors with retry
|
|
226
|
-
if (response.status >= 500 && response.status < 600 && attempt < retries - 1) {
|
|
227
|
-
const waitTime = Math.pow(2, attempt) * 1000;
|
|
228
|
-
await new Promise(resolve => setTimeout(resolve, waitTime));
|
|
229
|
-
continue;
|
|
230
|
-
}
|
|
231
|
-
if (!response.ok) {
|
|
232
|
-
const error = await response.json().catch(() => ({ error: response.statusText }));
|
|
233
|
-
throw new Error(error.error || error.message || `HTTP ${response.status}: ${response.statusText}`);
|
|
234
|
-
}
|
|
235
|
-
return response;
|
|
236
|
-
}
|
|
237
|
-
catch (error) {
|
|
238
|
-
lastError = error instanceof Error ? error : new Error(String(error));
|
|
239
|
-
// Network errors - retry with exponential backoff
|
|
240
|
-
if (attempt < retries - 1 && (lastError.message.includes('fetch failed') ||
|
|
241
|
-
lastError.message.includes('ECONNREFUSED') ||
|
|
242
|
-
lastError.message.includes('ETIMEDOUT'))) {
|
|
243
|
-
const waitTime = Math.pow(2, attempt) * 1000;
|
|
244
|
-
await new Promise(resolve => setTimeout(resolve, waitTime));
|
|
245
|
-
continue;
|
|
246
|
-
}
|
|
247
|
-
// If it's not a retryable error or we're out of retries, throw
|
|
248
|
-
if (attempt === retries - 1) {
|
|
249
|
-
throw lastError;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
throw lastError || new Error('Request failed after retries');
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
exports.RegistryClient = RegistryClient;
|
|
257
|
-
/**
|
|
258
|
-
* Get registry client with configuration
|
|
259
|
-
*/
|
|
260
|
-
function getRegistryClient(config) {
|
|
261
|
-
return new RegistryClient({
|
|
262
|
-
url: config.registryUrl || 'https://registry.prpm.dev',
|
|
263
|
-
token: config.token,
|
|
264
|
-
});
|
|
265
|
-
}
|
|
@@ -1,74 +0,0 @@
|
|
|
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
|
-
}
|
package/dist/core/telemetry.js
DELETED
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.telemetry = void 0;
|
|
7
|
-
const fs_1 = require("fs");
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const os_1 = __importDefault(require("os"));
|
|
10
|
-
const posthog_node_1 = require("posthog-node");
|
|
11
|
-
class Telemetry {
|
|
12
|
-
constructor() {
|
|
13
|
-
this.events = [];
|
|
14
|
-
this.maxEvents = 100; // Keep only last 100 events locally
|
|
15
|
-
this.posthog = null;
|
|
16
|
-
this.configPath = path_1.default.join(os_1.default.homedir(), '.prpm', 'telemetry.json');
|
|
17
|
-
this.config = this.loadConfig();
|
|
18
|
-
this.initializePostHog();
|
|
19
|
-
}
|
|
20
|
-
initializePostHog() {
|
|
21
|
-
try {
|
|
22
|
-
this.posthog = new posthog_node_1.PostHog('phc_aO5lXLILeylHfb1ynszVwKbQKSzO91UGdXNhN5Q0Snl', {
|
|
23
|
-
host: 'https://app.posthog.com',
|
|
24
|
-
flushAt: 1, // Send events immediately
|
|
25
|
-
flushInterval: 0, // No batching
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
catch (error) {
|
|
29
|
-
this.posthog = null;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
loadConfig() {
|
|
33
|
-
try {
|
|
34
|
-
const data = require(this.configPath);
|
|
35
|
-
return {
|
|
36
|
-
enabled: data.enabled ?? true, // Default to enabled
|
|
37
|
-
userId: data.userId,
|
|
38
|
-
sessionId: data.sessionId || this.generateSessionId(),
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
catch {
|
|
42
|
-
return {
|
|
43
|
-
enabled: true,
|
|
44
|
-
sessionId: this.generateSessionId(),
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
generateSessionId() {
|
|
49
|
-
return Math.random().toString(36).substring(2, 15) +
|
|
50
|
-
Math.random().toString(36).substring(2, 15);
|
|
51
|
-
}
|
|
52
|
-
async saveConfig() {
|
|
53
|
-
try {
|
|
54
|
-
await fs_1.promises.mkdir(path_1.default.dirname(this.configPath), { recursive: true });
|
|
55
|
-
await fs_1.promises.writeFile(this.configPath, JSON.stringify(this.config, null, 2));
|
|
56
|
-
}
|
|
57
|
-
catch (error) {
|
|
58
|
-
// Silently fail - telemetry shouldn't break the CLI
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
async track(event) {
|
|
62
|
-
if (!this.config.enabled)
|
|
63
|
-
return;
|
|
64
|
-
const fullEvent = {
|
|
65
|
-
...event,
|
|
66
|
-
timestamp: new Date().toISOString(),
|
|
67
|
-
version: process.env.npm_package_version || '0.1.0',
|
|
68
|
-
platform: os_1.default.platform(),
|
|
69
|
-
arch: os_1.default.arch(),
|
|
70
|
-
nodeVersion: process.version,
|
|
71
|
-
};
|
|
72
|
-
this.events.push(fullEvent);
|
|
73
|
-
// Keep only the last maxEvents
|
|
74
|
-
if (this.events.length > this.maxEvents) {
|
|
75
|
-
this.events = this.events.slice(-this.maxEvents);
|
|
76
|
-
}
|
|
77
|
-
// Save events locally
|
|
78
|
-
await this.saveEvents();
|
|
79
|
-
// Send to analytics service (async, non-blocking)
|
|
80
|
-
this.sendToAnalytics(fullEvent).catch(() => {
|
|
81
|
-
// Silently fail - don't break the CLI
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
async saveEvents() {
|
|
85
|
-
try {
|
|
86
|
-
const eventsPath = path_1.default.join(os_1.default.homedir(), '.prpm', 'events.json');
|
|
87
|
-
await fs_1.promises.mkdir(path_1.default.dirname(eventsPath), { recursive: true });
|
|
88
|
-
await fs_1.promises.writeFile(eventsPath, JSON.stringify(this.events, null, 2));
|
|
89
|
-
}
|
|
90
|
-
catch (error) {
|
|
91
|
-
// Silently fail
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
async sendToAnalytics(event) {
|
|
95
|
-
// Send to PostHog
|
|
96
|
-
await this.sendToPostHog(event);
|
|
97
|
-
}
|
|
98
|
-
async enable() {
|
|
99
|
-
this.config.enabled = true;
|
|
100
|
-
await this.saveConfig();
|
|
101
|
-
}
|
|
102
|
-
async disable() {
|
|
103
|
-
this.config.enabled = false;
|
|
104
|
-
await this.saveConfig();
|
|
105
|
-
}
|
|
106
|
-
isEnabled() {
|
|
107
|
-
return this.config.enabled;
|
|
108
|
-
}
|
|
109
|
-
async getStats() {
|
|
110
|
-
try {
|
|
111
|
-
const eventsPath = path_1.default.join(os_1.default.homedir(), '.prpm', 'events.json');
|
|
112
|
-
const data = await fs_1.promises.readFile(eventsPath, 'utf8');
|
|
113
|
-
const savedEvents = JSON.parse(data);
|
|
114
|
-
return {
|
|
115
|
-
totalEvents: savedEvents.length,
|
|
116
|
-
lastEvent: savedEvents[savedEvents.length - 1]?.timestamp,
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
catch (error) {
|
|
120
|
-
return {
|
|
121
|
-
totalEvents: this.events.length,
|
|
122
|
-
lastEvent: this.events[this.events.length - 1]?.timestamp,
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
async shutdown() {
|
|
127
|
-
if (this.posthog) {
|
|
128
|
-
try {
|
|
129
|
-
// Flush any pending events before shutdown
|
|
130
|
-
await this.posthog.flush();
|
|
131
|
-
await this.posthog.shutdown();
|
|
132
|
-
}
|
|
133
|
-
catch (error) {
|
|
134
|
-
// Silently fail
|
|
135
|
-
}
|
|
136
|
-
finally {
|
|
137
|
-
this.posthog = null;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
// Send to PostHog
|
|
142
|
-
async sendToPostHog(event) {
|
|
143
|
-
if (!this.posthog)
|
|
144
|
-
return;
|
|
145
|
-
try {
|
|
146
|
-
const distinctId = this.config.userId || this.config.sessionId || 'anonymous';
|
|
147
|
-
this.posthog.capture({
|
|
148
|
-
distinctId,
|
|
149
|
-
event: `prpm_${event.command}`,
|
|
150
|
-
properties: {
|
|
151
|
-
// Core event data
|
|
152
|
-
command: event.command,
|
|
153
|
-
success: event.success,
|
|
154
|
-
duration: event.duration,
|
|
155
|
-
error: event.error,
|
|
156
|
-
// System information
|
|
157
|
-
version: event.version,
|
|
158
|
-
platform: event.platform,
|
|
159
|
-
arch: event.arch,
|
|
160
|
-
nodeVersion: event.nodeVersion,
|
|
161
|
-
// Command-specific data
|
|
162
|
-
...event.data,
|
|
163
|
-
// Metadata
|
|
164
|
-
timestamp: event.timestamp,
|
|
165
|
-
sessionId: this.config.sessionId,
|
|
166
|
-
},
|
|
167
|
-
});
|
|
168
|
-
// Event sent to PostHog
|
|
169
|
-
}
|
|
170
|
-
catch (error) {
|
|
171
|
-
// Silently fail - don't break the CLI
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
exports.telemetry = new Telemetry();
|
package/dist/core/user-config.js
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* User configuration management for ~/.prpmrc
|
|
4
|
-
* Stores global settings like registry URL and authentication token
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.getConfig = getConfig;
|
|
8
|
-
exports.saveConfig = saveConfig;
|
|
9
|
-
exports.updateConfig = updateConfig;
|
|
10
|
-
exports.clearAuth = clearAuth;
|
|
11
|
-
exports.getRegistryUrl = getRegistryUrl;
|
|
12
|
-
const fs_1 = require("fs");
|
|
13
|
-
const path_1 = require("path");
|
|
14
|
-
const os_1 = require("os");
|
|
15
|
-
const CONFIG_FILE = (0, path_1.join)((0, os_1.homedir)(), '.prpmrc');
|
|
16
|
-
const DEFAULT_REGISTRY_URL = 'https://registry.prpm.dev';
|
|
17
|
-
/**
|
|
18
|
-
* Get user configuration
|
|
19
|
-
*/
|
|
20
|
-
async function getConfig() {
|
|
21
|
-
try {
|
|
22
|
-
const data = await fs_1.promises.readFile(CONFIG_FILE, 'utf-8');
|
|
23
|
-
const config = JSON.parse(data);
|
|
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;
|
|
32
|
-
}
|
|
33
|
-
catch (error) {
|
|
34
|
-
// If file doesn't exist, return default config
|
|
35
|
-
if (error.code === 'ENOENT') {
|
|
36
|
-
return {
|
|
37
|
-
registryUrl: process.env.PRPM_REGISTRY_URL || DEFAULT_REGISTRY_URL,
|
|
38
|
-
telemetryEnabled: true,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
throw new Error(`Failed to read user config: ${error}`);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Save user configuration
|
|
46
|
-
*/
|
|
47
|
-
async function saveConfig(config) {
|
|
48
|
-
try {
|
|
49
|
-
const data = JSON.stringify(config, null, 2);
|
|
50
|
-
await fs_1.promises.writeFile(CONFIG_FILE, data, 'utf-8');
|
|
51
|
-
}
|
|
52
|
-
catch (error) {
|
|
53
|
-
throw new Error(`Failed to save user config: ${error}`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Update specific config values
|
|
58
|
-
*/
|
|
59
|
-
async function updateConfig(updates) {
|
|
60
|
-
const config = await getConfig();
|
|
61
|
-
const newConfig = { ...config, ...updates };
|
|
62
|
-
await saveConfig(newConfig);
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Clear authentication (logout)
|
|
66
|
-
*/
|
|
67
|
-
async function clearAuth() {
|
|
68
|
-
const config = await getConfig();
|
|
69
|
-
delete config.token;
|
|
70
|
-
delete config.username;
|
|
71
|
-
await saveConfig(config);
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Get registry URL (with fallback to default)
|
|
75
|
-
*/
|
|
76
|
-
async function getRegistryUrl() {
|
|
77
|
-
const config = await getConfig();
|
|
78
|
-
return config.registryUrl || DEFAULT_REGISTRY_URL;
|
|
79
|
-
}
|
package/dist/types/registry.js
DELETED