prpm 0.1.17 → 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 -107
- package/package.json +11 -9
- package/dist/__tests__/e2e/test-helpers.js +0 -151
- 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 -789
- package/dist/commands/list.js +0 -189
- package/dist/commands/login.js +0 -316
- package/dist/commands/outdated.js +0 -130
- package/dist/commands/playground.js +0 -570
- 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/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 -242
- package/dist/core/lockfile.js +0 -292
- package/dist/core/marketplace-converter.js +0 -224
- 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 -36
- 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/upgrade.js
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Upgrade command - Upgrade packages to latest versions (including major)
|
|
4
|
-
*/
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.handleUpgrade = handleUpgrade;
|
|
7
|
-
exports.createUpgradeCommand = createUpgradeCommand;
|
|
8
|
-
const commander_1 = require("commander");
|
|
9
|
-
const registry_client_1 = require("@pr-pm/registry-client");
|
|
10
|
-
const user_config_1 = require("../core/user-config");
|
|
11
|
-
const lockfile_1 = require("../core/lockfile");
|
|
12
|
-
const install_1 = require("./install");
|
|
13
|
-
const telemetry_1 = require("../core/telemetry");
|
|
14
|
-
const errors_1 = require("../core/errors");
|
|
15
|
-
/**
|
|
16
|
-
* Upgrade packages to latest versions (including major updates)
|
|
17
|
-
*/
|
|
18
|
-
async function handleUpgrade(packageName, options = {}) {
|
|
19
|
-
const startTime = Date.now();
|
|
20
|
-
let success = false;
|
|
21
|
-
let error;
|
|
22
|
-
let upgradedCount = 0;
|
|
23
|
-
try {
|
|
24
|
-
const config = await (0, user_config_1.getConfig)();
|
|
25
|
-
const client = (0, registry_client_1.getRegistryClient)(config);
|
|
26
|
-
const installedPackages = await (0, lockfile_1.listPackages)();
|
|
27
|
-
if (installedPackages.length === 0) {
|
|
28
|
-
console.log('No packages installed.');
|
|
29
|
-
success = true;
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
// Determine which packages to upgrade
|
|
33
|
-
let packagesToUpgrade = installedPackages;
|
|
34
|
-
if (packageName) {
|
|
35
|
-
// Upgrade specific package
|
|
36
|
-
packagesToUpgrade = installedPackages.filter(p => p.id === packageName);
|
|
37
|
-
if (packagesToUpgrade.length === 0) {
|
|
38
|
-
throw new Error(`Package ${packageName} is not installed`);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
console.log('🚀 Checking for upgrades...\n');
|
|
42
|
-
for (const pkg of packagesToUpgrade) {
|
|
43
|
-
try {
|
|
44
|
-
// Get package info from registry
|
|
45
|
-
const registryPkg = await client.getPackage(pkg.id);
|
|
46
|
-
if (!registryPkg.latest_version || !pkg.version) {
|
|
47
|
-
continue;
|
|
48
|
-
}
|
|
49
|
-
const currentVersion = pkg.version;
|
|
50
|
-
const latestVersion = registryPkg.latest_version.version;
|
|
51
|
-
if (currentVersion === latestVersion) {
|
|
52
|
-
console.log(`✅ ${pkg.id} is already at latest version (${currentVersion})`);
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
const updateType = getUpdateType(currentVersion, latestVersion);
|
|
56
|
-
const emoji = updateType === 'major' ? '🔴' : updateType === 'minor' ? '🟡' : '🟢';
|
|
57
|
-
console.log(`\n${emoji} Upgrading ${pkg.id}: ${currentVersion} → ${latestVersion} (${updateType})`);
|
|
58
|
-
if (updateType === 'major' && !options.force) {
|
|
59
|
-
console.log(` ⚠️ This is a major version upgrade and may contain breaking changes`);
|
|
60
|
-
}
|
|
61
|
-
// Install new version
|
|
62
|
-
await (0, install_1.handleInstall)(`${pkg.id}@${latestVersion}`, {});
|
|
63
|
-
upgradedCount++;
|
|
64
|
-
}
|
|
65
|
-
catch (err) {
|
|
66
|
-
console.error(` ❌ Failed to upgrade ${pkg.id}: ${err instanceof Error ? err.message : String(err)}`);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
if (upgradedCount === 0) {
|
|
70
|
-
console.log('\n✅ All packages are at the latest version!\n');
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
console.log(`\n✅ Upgraded ${upgradedCount} package(s)\n`);
|
|
74
|
-
}
|
|
75
|
-
success = true;
|
|
76
|
-
}
|
|
77
|
-
catch (err) {
|
|
78
|
-
error = err instanceof Error ? err.message : String(err);
|
|
79
|
-
throw new errors_1.CLIError(`\n❌ Upgrade failed: ${error}`, 1);
|
|
80
|
-
}
|
|
81
|
-
finally {
|
|
82
|
-
await telemetry_1.telemetry.track({
|
|
83
|
-
command: 'upgrade',
|
|
84
|
-
success,
|
|
85
|
-
error,
|
|
86
|
-
duration: Date.now() - startTime,
|
|
87
|
-
data: {
|
|
88
|
-
packageName,
|
|
89
|
-
upgradedCount,
|
|
90
|
-
},
|
|
91
|
-
});
|
|
92
|
-
await telemetry_1.telemetry.shutdown();
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Determine update type based on semver
|
|
97
|
-
*/
|
|
98
|
-
function getUpdateType(current, latest) {
|
|
99
|
-
const currentParts = current.split('.').map(Number);
|
|
100
|
-
const latestParts = latest.split('.').map(Number);
|
|
101
|
-
const [currMajor = 0, currMinor = 0, currPatch = 0] = currentParts;
|
|
102
|
-
const [latestMajor = 0, latestMinor = 0, latestPatch = 0] = latestParts;
|
|
103
|
-
if (latestMajor > currMajor)
|
|
104
|
-
return 'major';
|
|
105
|
-
if (latestMinor > currMinor)
|
|
106
|
-
return 'minor';
|
|
107
|
-
return 'patch';
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Create the upgrade command
|
|
111
|
-
*/
|
|
112
|
-
function createUpgradeCommand() {
|
|
113
|
-
return new commander_1.Command('upgrade')
|
|
114
|
-
.description('Upgrade packages to latest versions (including major updates)')
|
|
115
|
-
.argument('[package]', 'Specific package to upgrade (optional)')
|
|
116
|
-
.option('--all', 'Upgrade all packages')
|
|
117
|
-
.option('--force', 'Skip warning for major version upgrades')
|
|
118
|
-
.action(async (packageName, options) => {
|
|
119
|
-
await handleUpgrade(packageName, options);
|
|
120
|
-
});
|
|
121
|
-
}
|
package/dist/commands/whoami.js
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Whoami command implementation
|
|
4
|
-
*/
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.handleWhoami = handleWhoami;
|
|
7
|
-
exports.createWhoamiCommand = createWhoamiCommand;
|
|
8
|
-
const commander_1 = require("commander");
|
|
9
|
-
const user_config_1 = require("../core/user-config");
|
|
10
|
-
const registry_client_1 = require("@pr-pm/registry-client");
|
|
11
|
-
const telemetry_1 = require("../core/telemetry");
|
|
12
|
-
const errors_1 = require("../core/errors");
|
|
13
|
-
/**
|
|
14
|
-
* Show current logged-in user
|
|
15
|
-
*/
|
|
16
|
-
async function handleWhoami() {
|
|
17
|
-
const startTime = Date.now();
|
|
18
|
-
let success = false;
|
|
19
|
-
let error;
|
|
20
|
-
try {
|
|
21
|
-
const config = await (0, user_config_1.getConfig)();
|
|
22
|
-
if (!config.token || !config.username) {
|
|
23
|
-
console.log('Not logged in');
|
|
24
|
-
console.log('\n💡 Run "prpm login" to authenticate\n');
|
|
25
|
-
success = true;
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
// Fetch user profile from registry
|
|
29
|
-
try {
|
|
30
|
-
const client = (0, registry_client_1.getRegistryClient)(config);
|
|
31
|
-
const userProfile = await client.getUserProfile(config.username);
|
|
32
|
-
console.log(`\n👤 ${userProfile.username}${userProfile.verified_author ? ' ✓' : ''}`);
|
|
33
|
-
if (userProfile.stats) {
|
|
34
|
-
console.log(`\n📊 Stats:`);
|
|
35
|
-
console.log(` 📦 Packages: ${userProfile.stats.total_packages}`);
|
|
36
|
-
console.log(` ⬇️ Downloads: ${userProfile.stats.total_downloads.toLocaleString()}`);
|
|
37
|
-
}
|
|
38
|
-
// TODO: Add organizations when implemented in the database
|
|
39
|
-
if (userProfile.organizations && userProfile.organizations.length > 0) {
|
|
40
|
-
console.log(`\n🏢 Organizations:`);
|
|
41
|
-
userProfile.organizations.forEach((org) => {
|
|
42
|
-
console.log(` • ${org.name} (${org.role})`);
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
console.log('');
|
|
46
|
-
}
|
|
47
|
-
catch (apiError) {
|
|
48
|
-
// Fallback to simple username display if API call fails
|
|
49
|
-
// This can happen if the user's token is stale or the registry is unavailable
|
|
50
|
-
console.log(`${config.username}`);
|
|
51
|
-
// Show hint if it looks like an auth issue
|
|
52
|
-
const errorMessage = apiError instanceof Error ? apiError.message : String(apiError);
|
|
53
|
-
if (errorMessage.includes('User not found') || errorMessage.includes('Unauthorized')) {
|
|
54
|
-
console.log('💡 Tip: Your token may be outdated. Run "prpm login" to refresh.\n');
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
success = true;
|
|
58
|
-
}
|
|
59
|
-
catch (err) {
|
|
60
|
-
error = err instanceof Error ? err.message : String(err);
|
|
61
|
-
throw new errors_1.CLIError(`❌ Error: ${error}`, 1);
|
|
62
|
-
}
|
|
63
|
-
finally {
|
|
64
|
-
// Track telemetry
|
|
65
|
-
await telemetry_1.telemetry.track({
|
|
66
|
-
command: 'whoami',
|
|
67
|
-
success,
|
|
68
|
-
error,
|
|
69
|
-
duration: Date.now() - startTime,
|
|
70
|
-
});
|
|
71
|
-
await telemetry_1.telemetry.shutdown();
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Create the whoami command
|
|
76
|
-
*/
|
|
77
|
-
function createWhoamiCommand() {
|
|
78
|
-
return new commander_1.Command('whoami')
|
|
79
|
-
.description('Show current logged-in user')
|
|
80
|
-
.action(async () => {
|
|
81
|
-
await handleWhoami();
|
|
82
|
-
});
|
|
83
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,130 +0,0 @@
|
|
|
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
|
-
}
|
package/dist/core/downloader.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* HTTP file downloading functionality
|
|
4
|
-
*/
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.downloadFile = downloadFile;
|
|
7
|
-
exports.extractFilename = extractFilename;
|
|
8
|
-
// Use Node.js built-in fetch (available in Node 18+)
|
|
9
|
-
/**
|
|
10
|
-
* Download a file from a URL
|
|
11
|
-
*/
|
|
12
|
-
async function downloadFile(url) {
|
|
13
|
-
try {
|
|
14
|
-
// Validate URL format
|
|
15
|
-
if (!isValidUrl(url)) {
|
|
16
|
-
throw new Error('Invalid URL format');
|
|
17
|
-
}
|
|
18
|
-
const response = await fetch(url);
|
|
19
|
-
if (!response.ok) {
|
|
20
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
21
|
-
}
|
|
22
|
-
const content = await response.text();
|
|
23
|
-
return content;
|
|
24
|
-
}
|
|
25
|
-
catch (error) {
|
|
26
|
-
if (error instanceof Error) {
|
|
27
|
-
throw new Error(`Failed to download file: ${error.message}`);
|
|
28
|
-
}
|
|
29
|
-
throw new Error('Failed to download file: Unknown error');
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Validate if URL is a valid raw GitHub URL
|
|
34
|
-
*/
|
|
35
|
-
function isValidUrl(url) {
|
|
36
|
-
try {
|
|
37
|
-
const urlObj = new URL(url);
|
|
38
|
-
// For MVP, only support raw GitHub URLs
|
|
39
|
-
return (urlObj.protocol === 'https:' &&
|
|
40
|
-
(urlObj.hostname === 'raw.githubusercontent.com' ||
|
|
41
|
-
urlObj.hostname === 'github.com' && urlObj.pathname.includes('/raw/')));
|
|
42
|
-
}
|
|
43
|
-
catch {
|
|
44
|
-
return false;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Extract filename from URL
|
|
49
|
-
*/
|
|
50
|
-
function extractFilename(url) {
|
|
51
|
-
try {
|
|
52
|
-
const urlObj = new URL(url);
|
|
53
|
-
const pathname = urlObj.pathname;
|
|
54
|
-
const filename = pathname.split('/').pop() || 'unknown';
|
|
55
|
-
// If no extension, assume it's a markdown file
|
|
56
|
-
if (!filename.includes('.')) {
|
|
57
|
-
return `${filename}.md`;
|
|
58
|
-
}
|
|
59
|
-
return filename;
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
return 'unknown.md';
|
|
63
|
-
}
|
|
64
|
-
}
|
package/dist/core/errors.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CLIError = void 0;
|
|
4
|
-
exports.createError = createError;
|
|
5
|
-
exports.createSuccess = createSuccess;
|
|
6
|
-
/**
|
|
7
|
-
* Custom error class for CLI commands
|
|
8
|
-
* Allows commands to throw errors with exit codes instead of calling process.exit()
|
|
9
|
-
*/
|
|
10
|
-
class CLIError extends Error {
|
|
11
|
-
constructor(message, exitCode = 1) {
|
|
12
|
-
super(message);
|
|
13
|
-
this.name = 'CLIError';
|
|
14
|
-
this.exitCode = exitCode;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
exports.CLIError = CLIError;
|
|
18
|
-
/**
|
|
19
|
-
* Creates a CLIError with exit code 1 (general error)
|
|
20
|
-
*/
|
|
21
|
-
function createError(message) {
|
|
22
|
-
return new CLIError(message, 1);
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Creates a CLIError with exit code 0 (success, used for early termination)
|
|
26
|
-
*/
|
|
27
|
-
function createSuccess(message) {
|
|
28
|
-
return new CLIError(message || '', 0);
|
|
29
|
-
}
|