prpm 1.2.1 → 2.1.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/README.md +90 -862
- package/dist/index.js +24163 -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-capabilities.schema.json +101 -0
- package/dist/schemas/format-registry.schema.json +99 -0
- package/dist/schemas/gemini-extension.schema.json +77 -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 +165 -0
- package/dist/schemas/kiro-steering.schema.json +74 -0
- package/dist/schemas/mcp-server.schema.json +130 -0
- package/dist/schemas/opencode-plugin.schema.json +391 -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 +758 -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/zed-extension.schema.json +238 -0
- package/dist/schemas/zed.schema.json +44 -0
- package/dist/schemas/zencoder.schema.json +51 -0
- package/package.json +20 -14
- package/schemas/prpm-manifest.schema.json +490 -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
package/dist/commands/update.js
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Update command - Update packages to latest compatible versions
|
|
4
|
-
*/
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.handleUpdate = handleUpdate;
|
|
7
|
-
exports.createUpdateCommand = createUpdateCommand;
|
|
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
|
-
/**
|
|
15
|
-
* Update packages to latest minor/patch versions
|
|
16
|
-
*/
|
|
17
|
-
async function handleUpdate(packageName, options = {}) {
|
|
18
|
-
const startTime = Date.now();
|
|
19
|
-
let success = false;
|
|
20
|
-
let error;
|
|
21
|
-
let updatedCount = 0;
|
|
22
|
-
try {
|
|
23
|
-
const config = await (0, user_config_1.getConfig)();
|
|
24
|
-
const client = (0, registry_client_1.getRegistryClient)(config);
|
|
25
|
-
const installedPackages = await (0, lockfile_1.listPackages)();
|
|
26
|
-
if (installedPackages.length === 0) {
|
|
27
|
-
console.log('No packages installed.');
|
|
28
|
-
success = true;
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
// Determine which packages to update
|
|
32
|
-
let packagesToUpdate = installedPackages;
|
|
33
|
-
if (packageName) {
|
|
34
|
-
// Update specific package
|
|
35
|
-
packagesToUpdate = installedPackages.filter(p => p.id === packageName);
|
|
36
|
-
if (packagesToUpdate.length === 0) {
|
|
37
|
-
throw new Error(`Package ${packageName} is not installed`);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
console.log('🔄 Checking for updates...\n');
|
|
41
|
-
for (const pkg of packagesToUpdate) {
|
|
42
|
-
try {
|
|
43
|
-
// Get package info from registry
|
|
44
|
-
const registryPkg = await client.getPackage(pkg.id);
|
|
45
|
-
if (!registryPkg.latest_version || !pkg.version) {
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
const currentVersion = pkg.version;
|
|
49
|
-
const latestVersion = registryPkg.latest_version.version;
|
|
50
|
-
// Only update if it's a minor or patch update (not major)
|
|
51
|
-
const updateType = getUpdateType(currentVersion, latestVersion);
|
|
52
|
-
if (updateType === 'major') {
|
|
53
|
-
console.log(`⏭️ Skipping ${pkg.id} (major update ${currentVersion} → ${latestVersion}, use upgrade)`);
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
if (currentVersion === latestVersion) {
|
|
57
|
-
console.log(`✅ ${pkg.id} is already up to date (${currentVersion})`);
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
console.log(`\n📦 Updating ${pkg.id}: ${currentVersion} → ${latestVersion}`);
|
|
61
|
-
// Install new version
|
|
62
|
-
await (0, install_1.handleInstall)(`${pkg.id}@${latestVersion}`, {
|
|
63
|
-
type: pkg.type,
|
|
64
|
-
});
|
|
65
|
-
updatedCount++;
|
|
66
|
-
}
|
|
67
|
-
catch (err) {
|
|
68
|
-
console.error(` ❌ Failed to update ${pkg.id}: ${err instanceof Error ? err.message : String(err)}`);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
if (updatedCount === 0) {
|
|
72
|
-
console.log('\n✅ All packages are up to date!\n');
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
console.log(`\n✅ Updated ${updatedCount} package(s)\n`);
|
|
76
|
-
}
|
|
77
|
-
success = true;
|
|
78
|
-
}
|
|
79
|
-
catch (err) {
|
|
80
|
-
error = err instanceof Error ? err.message : String(err);
|
|
81
|
-
console.error(`\n❌ Update failed: ${error}`);
|
|
82
|
-
process.exit(1);
|
|
83
|
-
}
|
|
84
|
-
finally {
|
|
85
|
-
await telemetry_1.telemetry.track({
|
|
86
|
-
command: 'update',
|
|
87
|
-
success,
|
|
88
|
-
error,
|
|
89
|
-
duration: Date.now() - startTime,
|
|
90
|
-
data: {
|
|
91
|
-
packageName,
|
|
92
|
-
updatedCount,
|
|
93
|
-
},
|
|
94
|
-
});
|
|
95
|
-
await telemetry_1.telemetry.shutdown();
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Determine update type based on semver
|
|
100
|
-
*/
|
|
101
|
-
function getUpdateType(current, latest) {
|
|
102
|
-
const currentParts = current.split('.').map(Number);
|
|
103
|
-
const latestParts = latest.split('.').map(Number);
|
|
104
|
-
const [currMajor = 0, currMinor = 0, currPatch = 0] = currentParts;
|
|
105
|
-
const [latestMajor = 0, latestMinor = 0, latestPatch = 0] = latestParts;
|
|
106
|
-
if (latestMajor > currMajor)
|
|
107
|
-
return 'major';
|
|
108
|
-
if (latestMinor > currMinor)
|
|
109
|
-
return 'minor';
|
|
110
|
-
return 'patch';
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Create the update command
|
|
114
|
-
*/
|
|
115
|
-
function createUpdateCommand() {
|
|
116
|
-
return new commander_1.Command('update')
|
|
117
|
-
.description('Update packages to latest compatible versions (minor/patch only)')
|
|
118
|
-
.argument('[package]', 'Specific package to update (optional)')
|
|
119
|
-
.option('--all', 'Update all packages')
|
|
120
|
-
.action(handleUpdate);
|
|
121
|
-
}
|
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
|
-
/**
|
|
15
|
-
* Upgrade packages to latest versions (including major updates)
|
|
16
|
-
*/
|
|
17
|
-
async function handleUpgrade(packageName, options = {}) {
|
|
18
|
-
const startTime = Date.now();
|
|
19
|
-
let success = false;
|
|
20
|
-
let error;
|
|
21
|
-
let upgradedCount = 0;
|
|
22
|
-
try {
|
|
23
|
-
const config = await (0, user_config_1.getConfig)();
|
|
24
|
-
const client = (0, registry_client_1.getRegistryClient)(config);
|
|
25
|
-
const installedPackages = await (0, lockfile_1.listPackages)();
|
|
26
|
-
if (installedPackages.length === 0) {
|
|
27
|
-
console.log('No packages installed.');
|
|
28
|
-
success = true;
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
// Determine which packages to upgrade
|
|
32
|
-
let packagesToUpgrade = installedPackages;
|
|
33
|
-
if (packageName) {
|
|
34
|
-
// Upgrade specific package
|
|
35
|
-
packagesToUpgrade = installedPackages.filter(p => p.id === packageName);
|
|
36
|
-
if (packagesToUpgrade.length === 0) {
|
|
37
|
-
throw new Error(`Package ${packageName} is not installed`);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
console.log('🚀 Checking for upgrades...\n');
|
|
41
|
-
for (const pkg of packagesToUpgrade) {
|
|
42
|
-
try {
|
|
43
|
-
// Get package info from registry
|
|
44
|
-
const registryPkg = await client.getPackage(pkg.id);
|
|
45
|
-
if (!registryPkg.latest_version || !pkg.version) {
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
const currentVersion = pkg.version;
|
|
49
|
-
const latestVersion = registryPkg.latest_version.version;
|
|
50
|
-
if (currentVersion === latestVersion) {
|
|
51
|
-
console.log(`✅ ${pkg.id} is already at latest version (${currentVersion})`);
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
const updateType = getUpdateType(currentVersion, latestVersion);
|
|
55
|
-
const emoji = updateType === 'major' ? '🔴' : updateType === 'minor' ? '🟡' : '🟢';
|
|
56
|
-
console.log(`\n${emoji} Upgrading ${pkg.id}: ${currentVersion} → ${latestVersion} (${updateType})`);
|
|
57
|
-
if (updateType === 'major' && !options.force) {
|
|
58
|
-
console.log(` ⚠️ This is a major version upgrade and may contain breaking changes`);
|
|
59
|
-
}
|
|
60
|
-
// Install new version
|
|
61
|
-
await (0, install_1.handleInstall)(`${pkg.id}@${latestVersion}`, {
|
|
62
|
-
type: pkg.type,
|
|
63
|
-
});
|
|
64
|
-
upgradedCount++;
|
|
65
|
-
}
|
|
66
|
-
catch (err) {
|
|
67
|
-
console.error(` ❌ Failed to upgrade ${pkg.id}: ${err instanceof Error ? err.message : String(err)}`);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
if (upgradedCount === 0) {
|
|
71
|
-
console.log('\n✅ All packages are at the latest version!\n');
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
console.log(`\n✅ Upgraded ${upgradedCount} package(s)\n`);
|
|
75
|
-
}
|
|
76
|
-
success = true;
|
|
77
|
-
}
|
|
78
|
-
catch (err) {
|
|
79
|
-
error = err instanceof Error ? err.message : String(err);
|
|
80
|
-
console.error(`\n❌ Upgrade failed: ${error}`);
|
|
81
|
-
process.exit(1);
|
|
82
|
-
}
|
|
83
|
-
finally {
|
|
84
|
-
await telemetry_1.telemetry.track({
|
|
85
|
-
command: 'upgrade',
|
|
86
|
-
success,
|
|
87
|
-
error,
|
|
88
|
-
duration: Date.now() - startTime,
|
|
89
|
-
data: {
|
|
90
|
-
packageName,
|
|
91
|
-
upgradedCount,
|
|
92
|
-
},
|
|
93
|
-
});
|
|
94
|
-
await telemetry_1.telemetry.shutdown();
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Determine update type based on semver
|
|
99
|
-
*/
|
|
100
|
-
function getUpdateType(current, latest) {
|
|
101
|
-
const currentParts = current.split('.').map(Number);
|
|
102
|
-
const latestParts = latest.split('.').map(Number);
|
|
103
|
-
const [currMajor = 0, currMinor = 0, currPatch = 0] = currentParts;
|
|
104
|
-
const [latestMajor = 0, latestMinor = 0, latestPatch = 0] = latestParts;
|
|
105
|
-
if (latestMajor > currMajor)
|
|
106
|
-
return 'major';
|
|
107
|
-
if (latestMinor > currMinor)
|
|
108
|
-
return 'minor';
|
|
109
|
-
return 'patch';
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Create the upgrade command
|
|
113
|
-
*/
|
|
114
|
-
function createUpgradeCommand() {
|
|
115
|
-
return new commander_1.Command('upgrade')
|
|
116
|
-
.description('Upgrade packages to latest versions (including major updates)')
|
|
117
|
-
.argument('[package]', 'Specific package to upgrade (optional)')
|
|
118
|
-
.option('--all', 'Upgrade all packages')
|
|
119
|
-
.option('--force', 'Skip warning for major version upgrades')
|
|
120
|
-
.action(handleUpgrade);
|
|
121
|
-
}
|
package/dist/commands/whoami.js
DELETED
|
@@ -1,75 +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
|
-
/**
|
|
13
|
-
* Show current logged-in user
|
|
14
|
-
*/
|
|
15
|
-
async function handleWhoami() {
|
|
16
|
-
const startTime = Date.now();
|
|
17
|
-
let success = false;
|
|
18
|
-
let error;
|
|
19
|
-
try {
|
|
20
|
-
const config = await (0, user_config_1.getConfig)();
|
|
21
|
-
if (!config.token || !config.username) {
|
|
22
|
-
console.log('Not logged in');
|
|
23
|
-
console.log('\n💡 Run "prpm login" to authenticate\n');
|
|
24
|
-
success = true;
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
// Fetch user profile from registry
|
|
28
|
-
try {
|
|
29
|
-
const client = (0, registry_client_1.getRegistryClient)(config);
|
|
30
|
-
const userProfile = await client.getUserProfile(config.username);
|
|
31
|
-
console.log(`\n👤 ${userProfile.username}${userProfile.verified_author ? ' ✓' : ''}`);
|
|
32
|
-
if (userProfile.stats) {
|
|
33
|
-
console.log(`\n📊 Stats:`);
|
|
34
|
-
console.log(` 📦 Packages: ${userProfile.stats.total_packages}`);
|
|
35
|
-
console.log(` ⬇️ Downloads: ${userProfile.stats.total_downloads.toLocaleString()}`);
|
|
36
|
-
}
|
|
37
|
-
// TODO: Add organizations when implemented in the database
|
|
38
|
-
if (userProfile.organizations && userProfile.organizations.length > 0) {
|
|
39
|
-
console.log(`\n🏢 Organizations:`);
|
|
40
|
-
userProfile.organizations.forEach((org) => {
|
|
41
|
-
console.log(` • ${org.name} (${org.role})`);
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
console.log('');
|
|
45
|
-
}
|
|
46
|
-
catch (apiError) {
|
|
47
|
-
// Fallback to simple username display if API call fails
|
|
48
|
-
console.log(`${config.username}`);
|
|
49
|
-
}
|
|
50
|
-
success = true;
|
|
51
|
-
}
|
|
52
|
-
catch (err) {
|
|
53
|
-
error = err instanceof Error ? err.message : String(err);
|
|
54
|
-
console.error(`❌ Error: ${error}`);
|
|
55
|
-
process.exit(1);
|
|
56
|
-
}
|
|
57
|
-
finally {
|
|
58
|
-
// Track telemetry
|
|
59
|
-
await telemetry_1.telemetry.track({
|
|
60
|
-
command: 'whoami',
|
|
61
|
-
success,
|
|
62
|
-
error,
|
|
63
|
-
duration: Date.now() - startTime,
|
|
64
|
-
});
|
|
65
|
-
await telemetry_1.telemetry.shutdown();
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Create the whoami command
|
|
70
|
-
*/
|
|
71
|
-
function createWhoamiCommand() {
|
|
72
|
-
return new commander_1.Command('whoami')
|
|
73
|
-
.description('Show current logged-in user')
|
|
74
|
-
.action(handleWhoami);
|
|
75
|
-
}
|
|
@@ -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
|
-
}
|