Merge pull request #12 from DimoHG/cursor-marketplace-plugin

feat(cursor): enable Cursor marketplace plugin publishing
This commit is contained in:
Simba Khadder
2026-03-10 06:16:25 -07:00
committed by GitHub
42 changed files with 174 additions and 44 deletions
+3 -2
View File
@@ -6,12 +6,13 @@
},
"metadata": {
"description": "Official Redis plugins for Cursor",
"version": "1.0.0"
"version": "1.0.0",
"pluginRoot": "skills"
},
"plugins": [
{
"name": "redis-development",
"source": "./plugins/redis-development",
"source": "redis-development",
"description": "Redis development best practices — data structures, query engine, vector search, caching, and performance optimization",
"version": "1.0.0",
"category": "database",
-17
View File
@@ -1,17 +0,0 @@
{
"name": "redis",
"displayName": "Redis",
"version": "1.0.0",
"description": "Redis development best practices — data structures, query engine, vector search, caching, and performance optimization.",
"author": {
"name": "Redis",
"email": "support@redis.com"
},
"homepage": "https://redis.io/docs/",
"repository": "https://github.com/redis/agent-skills",
"license": "MIT",
"keywords": ["redis", "database", "caching", "vector-search", "performance", "cursor"],
"logo": "plugins/redis-development/assets/logo.png",
"skills": "./skills/",
"rules": "./skills/redis-development/rules/"
}
+2
View File
@@ -85,6 +85,8 @@ title: Clear, Action-Oriented Title
impact: HIGH|MEDIUM|LOW
impactDescription: Quantified benefit (e.g., "10x faster")
tags: relevant, keywords
description: Clear, Action-Oriented Title
alwaysApply: true
---
## {Title}
+95 -21
View File
@@ -109,34 +109,26 @@ async function validateManifestPath(pluginDir, pluginName, fieldName, value) {
}
}
async function main() {
const manifestPath = path.join(
repoRoot,
".cursor-plugin",
"plugin.json",
);
const pluginManifest = await readJsonFile(
manifestPath,
"Cursor plugin manifest",
);
async function validatePluginManifest(manifestPath, pluginDir, context) {
const pluginManifest = await readJsonFile(manifestPath, context);
if (!pluginManifest) {
summarizeAndExit();
return;
}
const label = pluginManifest.name || context;
if (
typeof pluginManifest.name !== "string" ||
!pluginNamePattern.test(pluginManifest.name)
) {
addError(
'"name" in plugin.json must be lowercase and use only alphanumerics, hyphens, and periods.',
`${label}: "name" must be lowercase and use only alphanumerics, hyphens, and periods.`,
);
}
validateRequiredString(pluginManifest.displayName, "displayName");
validateRequiredString(pluginManifest.version, "version");
validateRequiredString(pluginManifest.description, "description");
validateRequiredString(pluginManifest.license, "license");
validateRequiredString(pluginManifest.version, `${label}: version`);
validateRequiredString(pluginManifest.description, `${label}: description`);
validateRequiredString(pluginManifest.license, `${label}: license`);
if (
!pluginManifest.author ||
@@ -144,7 +136,7 @@ async function main() {
typeof pluginManifest.author.name !== "string" ||
pluginManifest.author.name.length === 0
) {
addError("author.name is required in plugin.json.");
addError(`${label}: author.name is required.`);
}
if (
!Array.isArray(pluginManifest.keywords) ||
@@ -153,11 +145,9 @@ async function main() {
(keyword) => typeof keyword !== "string" || keyword.trim().length === 0,
)
) {
addError("keywords must be a non-empty string array.");
addError(`${label}: keywords must be a non-empty string array.`);
}
await ensureDirectory(path.join(repoRoot, ".cursor-plugin"), ".cursor-plugin");
for (const field of [
"logo",
"rules",
@@ -168,9 +158,93 @@ async function main() {
"mcpServers",
]) {
for (const value of extractPathValues(pluginManifest[field])) {
await validateManifestPath(repoRoot, pluginManifest.name, field, value);
await validateManifestPath(pluginDir, label, field, value);
}
}
}
async function validateMarketplace(marketplacePath) {
const marketplace = await readJsonFile(marketplacePath, "Cursor marketplace manifest");
if (!marketplace) {
return;
}
validateRequiredString(marketplace.name, "marketplace: name");
if (
!marketplace.owner ||
typeof marketplace.owner !== "object" ||
typeof marketplace.owner.name !== "string" ||
marketplace.owner.name.length === 0
) {
addError("marketplace: owner.name is required.");
}
if (!Array.isArray(marketplace.plugins) || marketplace.plugins.length === 0) {
addError("marketplace: plugins must be a non-empty array.");
return;
}
const pluginRoot = marketplace.metadata?.pluginRoot || "";
if (pluginRoot && !isSafeRelativePath(pluginRoot)) {
addError(`marketplace: metadata.pluginRoot has invalid path "${pluginRoot}".`);
return;
}
for (const entry of marketplace.plugins) {
if (
typeof entry.name !== "string" ||
!pluginNamePattern.test(entry.name)
) {
addError(
`marketplace plugin entry: "name" must be lowercase kebab-case.`,
);
continue;
}
const source = typeof entry.source === "string"
? entry.source
: entry.source?.path;
if (!source) {
addError(`${entry.name}: marketplace entry requires a "source" path.`);
continue;
}
if (!isSafeRelativePath(source)) {
addError(`${entry.name}: source has invalid path "${source}".`);
continue;
}
const pluginDir = path.resolve(repoRoot, pluginRoot, source);
if (!(await pathExists(pluginDir))) {
addError(`${entry.name}: resolved plugin directory does not exist: ${pluginDir}`);
continue;
}
const perPluginManifest = path.join(pluginDir, ".cursor-plugin", "plugin.json");
if (!(await pathExists(perPluginManifest))) {
addError(`${entry.name}: per-plugin manifest is missing: ${perPluginManifest}`);
continue;
}
await validatePluginManifest(perPluginManifest, pluginDir, `${entry.name} plugin.json`);
}
}
async function main() {
await ensureDirectory(path.join(repoRoot, ".cursor-plugin"), ".cursor-plugin");
const marketplacePath = path.join(repoRoot, ".cursor-plugin", "marketplace.json");
const rootManifestPath = path.join(repoRoot, ".cursor-plugin", "plugin.json");
if (await pathExists(marketplacePath)) {
await validateMarketplace(marketplacePath);
} else if (await pathExists(rootManifestPath)) {
await validatePluginManifest(rootManifestPath, repoRoot, "Cursor plugin manifest");
} else {
addError("No .cursor-plugin/marketplace.json or .cursor-plugin/plugin.json found.");
}
summarizeAndExit();
}
@@ -1,16 +1,14 @@
{
"name": "redis-development",
"displayName": "Redis Development",
"version": "1.0.0",
"description": "Redis development best practices — data structures, query engine, vector search, caching, and performance optimization",
"author": {
"name": "Redis",
"url": "https://redis.io"
"email": "support@redis.com"
},
"homepage": "https://redis.io",
"repository": "https://github.com/redis/agent-skills",
"license": "MIT",
"keywords": ["redis", "database", "caching", "vector-search", "performance", "best-practices"],
"skills": "./skills/",
"rules": "./skills/redis-development/rules/"
"logo": "assets/logo.png"
}
+2
View File
@@ -64,6 +64,8 @@ title: Rule Title Here
impact: MEDIUM
impactDescription: Optional description
tags: tag1, tag2, tag3
description: Rule Title Here
alwaysApply: true
---
## Rule Title Here

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

@@ -3,6 +3,8 @@ title: Clear, Action-Oriented Title (e.g., "Use Connection Pooling")
impact: MEDIUM
impactDescription: Brief quantified benefit (e.g., "Reduces connection overhead by 10x")
tags: relevant, keywords, here
description: Clear, Action-Oriented Title (e.g., "Use Connection Pooling")
alwaysApply: true
---
## [Rule Title]
@@ -3,6 +3,8 @@ title: Use Hash Tags for Multi-Key Operations
impact: HIGH
impactDescription: Enables multi-key operations in Redis Cluster
tags: cluster, hash-tags, keys, sharding, multi-key
description: Use Hash Tags for Multi-Key Operations
alwaysApply: true
---
## Use Hash Tags for Multi-Key Operations
@@ -3,6 +3,8 @@ title: Use Read Replicas for Read-Heavy Workloads
impact: MEDIUM
impactDescription: Scales read throughput without adding primary nodes
tags: cluster, replicas, read-scaling, high-availability
description: Use Read Replicas for Read-Heavy Workloads
alwaysApply: true
---
## Use Read Replicas for Read-Heavy Workloads
@@ -3,6 +3,8 @@ title: Avoid Slow Commands in Production
impact: HIGH
impactDescription: Prevents Redis from becoming unresponsive
tags: slow-commands, keys, scan, performance
description: Avoid Slow Commands in Production
alwaysApply: true
---
## Avoid Slow Commands in Production
@@ -3,6 +3,8 @@ title: Use Client-Side Caching for Frequently Read Data
impact: HIGH
impactDescription: Reduces network round-trips for repeated reads
tags: caching, performance, client-side, tracking
description: Use Client-Side Caching for Frequently Read Data
alwaysApply: true
---
## Use Client-Side Caching for Frequently Read Data
@@ -3,6 +3,8 @@ title: Use Pipelining for Bulk Operations
impact: HIGH
impactDescription: Reduces round trips, 5-10x faster for batch operations
tags: pipelining, batch, performance, round-trips
description: Use Pipelining for Bulk Operations
alwaysApply: true
---
## Use Pipelining for Bulk Operations
@@ -3,6 +3,8 @@ title: Use Connection Pooling or Multiplexing
impact: HIGH
impactDescription: Reduces connection overhead by 10x or more
tags: connections, pooling, multiplexing, performance
description: Use Connection Pooling or Multiplexing
alwaysApply: true
---
## Use Connection Pooling or Multiplexing
@@ -3,6 +3,8 @@ title: Configure Connection Timeouts
impact: MEDIUM
impactDescription: Improves connection resilience and failure recovery
tags: timeouts, connections, reliability
description: Configure Connection Timeouts
alwaysApply: true
---
## Configure Connection Timeouts
@@ -3,6 +3,8 @@ title: Choose the Right Data Structure
impact: HIGH
impactDescription: Optimal memory usage and operation performance
tags: data-structures, strings, hashes, sets, lists, sorted-sets, json, streams, vector-sets
description: Choose the Right Data Structure
alwaysApply: true
---
## Choose the Right Data Structure
@@ -3,6 +3,8 @@ title: Use Hash Field Expiration for Per-Field TTL
impact: MEDIUM
impactDescription: Fine-grained expiration without managing timers
tags: hash, expiration, ttl, hexpire
description: Use Hash Field Expiration for Per-Field TTL
alwaysApply: true
---
## Use Hash Field Expiration for Per-Field TTL
@@ -3,6 +3,8 @@ title: Use INCR for Atomic Counters
impact: MEDIUM
impactDescription: Atomic increment avoids race conditions
tags: incr, counters, atomic, performance
description: Use INCR for Atomic Counters
alwaysApply: true
---
## Use INCR for Atomic Counters
@@ -3,6 +3,8 @@ title: Use Consistent Key Naming Conventions
impact: MEDIUM
impactDescription: Improved maintainability and debugging
tags: keys, naming, conventions, prefixes
description: Use Consistent Key Naming Conventions
alwaysApply: true
---
## Use Consistent Key Naming Conventions
@@ -3,6 +3,8 @@ title: Use Transactions for Atomic Multi-Command Operations
impact: MEDIUM
impactDescription: Prevents race conditions and data inconsistency
tags: transactions, multi, exec, atomicity
description: Use Transactions for Atomic Multi-Command Operations
alwaysApply: true
---
## Use Transactions for Atomic Multi-Command Operations
@@ -3,6 +3,8 @@ title: Use JSON Paths for Partial Updates
impact: MEDIUM
impactDescription: Avoids fetching and rewriting entire documents
tags: json, partial-updates, paths, atomic
description: Use JSON Paths for Partial Updates
alwaysApply: true
---
## Use JSON Paths for Partial Updates
@@ -3,6 +3,8 @@ title: Choose JSON vs Hash vs String Appropriately
impact: MEDIUM
impactDescription: Optimal data model for your use case
tags: json, hash, string, data-structures, documents
description: Choose JSON vs Hash vs String Appropriately
alwaysApply: true
---
## Choose JSON vs Hash vs String Appropriately
@@ -3,6 +3,8 @@ title: Use Observability Commands for Debugging
impact: MEDIUM
impactDescription: Enables quick diagnosis of performance issues
tags: observability, slowlog, info, memory, debugging
description: Use Observability Commands for Debugging
alwaysApply: true
---
## Use Observability Commands for Debugging
@@ -3,6 +3,8 @@ title: Monitor Key Redis Metrics
impact: MEDIUM
impactDescription: Early detection of performance and capacity issues
tags: observability, metrics, monitoring, memory, connections
description: Monitor Key Redis Metrics
alwaysApply: true
---
## Monitor Key Redis Metrics
@@ -3,6 +3,8 @@ title: Configure Memory Limits and Eviction Policies
impact: HIGH
impactDescription: Prevents out-of-memory crashes and unpredictable behavior
tags: memory, maxmemory, eviction, lru, ttl
description: Configure Memory Limits and Eviction Policies
alwaysApply: true
---
## Configure Memory Limits and Eviction Policies
@@ -3,6 +3,8 @@ title: Set TTL on Cache Keys
impact: HIGH
impactDescription: Prevents unbounded memory growth
tags: ttl, expiration, cache, memory
description: Set TTL on Cache Keys
alwaysApply: true
---
## Set TTL on Cache Keys
@@ -3,6 +3,8 @@ title: Use DIALECT 2 for Query Syntax
impact: MEDIUM
impactDescription: Ensures consistent query behavior and access to modern features
tags: rqe, dialect, query, syntax
description: Use DIALECT 2 for Query Syntax
alwaysApply: true
---
## Use DIALECT 2 for Query Syntax
@@ -3,6 +3,8 @@ title: Choose the Correct Field Type
impact: HIGH
impactDescription: Use TAG instead of TEXT for filtering to improve query speed 10x
tags: rqe, field-types, text, tag, numeric, geo, geoshape, vector
description: Choose the Correct Field Type
alwaysApply: true
---
## Choose the Correct Field Type
@@ -3,6 +3,8 @@ title: Index Only Fields You Query
impact: HIGH
impactDescription: Reduces index size and improves write performance
tags: rqe, ft.create, index, schema
description: Index Only Fields You Query
alwaysApply: true
---
## Index Only Fields You Query
@@ -3,6 +3,8 @@ title: Manage Indexes for Zero-Downtime Updates
impact: MEDIUM
impactDescription: Use aliases for seamless index updates
tags: rqe, index, alias, management, reindex
description: Manage Indexes for Zero-Downtime Updates
alwaysApply: true
---
## Manage Indexes for Zero-Downtime Updates
@@ -3,6 +3,8 @@ title: Write Efficient Queries
impact: HIGH
impactDescription: Proper filtering reduces query time by orders of magnitude
tags: rqe, ft.search, query, performance, filters
description: Write Efficient Queries
alwaysApply: true
---
## Write Efficient Queries
@@ -3,6 +3,8 @@ title: Use SKIPINITIALSCAN for New Data Only Indexes
impact: MEDIUM
impactDescription: Faster index creation, avoids indexing existing data
tags: index, skipinitialscan, rqe, search
description: Use SKIPINITIALSCAN for New Data Only Indexes
alwaysApply: true
---
## Use SKIPINITIALSCAN for New Data Only Indexes
@@ -3,6 +3,8 @@ title: Use ACLs for Fine-Grained Access Control
impact: HIGH
impactDescription: Limits blast radius if credentials are compromised
tags: security, acl, users, permissions, least-privilege
description: Use ACLs for Fine-Grained Access Control
alwaysApply: true
---
## Use ACLs for Fine-Grained Access Control
@@ -3,6 +3,8 @@ title: Always Use Authentication in Production
impact: HIGH
impactDescription: Prevents unauthorized access to your data
tags: security, authentication, password, tls, ssl
description: Always Use Authentication in Production
alwaysApply: true
---
## Always Use Authentication in Production
@@ -3,6 +3,8 @@ title: Secure Network Access
impact: HIGH
impactDescription: Reduces attack surface and prevents unauthorized access
tags: security, network, firewall, bind, tls
description: Secure Network Access
alwaysApply: true
---
## Secure Network Access
@@ -3,6 +3,8 @@ title: Configure Semantic Cache Properly
impact: MEDIUM
impactDescription: Correct threshold tuning balances hit rate vs accuracy
tags: langcache, cache, threshold, ttl, semantic
description: Configure Semantic Cache Properly
alwaysApply: true
---
## Configure Semantic Cache Properly
@@ -3,6 +3,8 @@ title: Use LangCache for LLM Response Caching
impact: HIGH
impactDescription: Reduces LLM API costs by 50-90% for similar queries
tags: langcache, llm, semantic-cache, embeddings, ai
description: Use LangCache for LLM Response Caching
alwaysApply: true
---
## Use LangCache for LLM Response Caching
@@ -3,6 +3,8 @@ title: Choose Streams vs Pub/Sub Appropriately
impact: MEDIUM
impactDescription: Wrong choice leads to lost messages or unnecessary complexity
tags: streams, pubsub, messaging, events, queues
description: Choose Streams vs Pub/Sub Appropriately
alwaysApply: true
---
## Choose Streams vs Pub/Sub Appropriately
@@ -3,6 +3,8 @@ title: Choose HNSW vs FLAT Based on Requirements
impact: HIGH
impactDescription: HNSW trades accuracy for speed, FLAT provides exact results
tags: vector, hnsw, flat, algorithm, performance
description: Choose HNSW vs FLAT Based on Requirements
alwaysApply: true
---
## Choose HNSW vs FLAT Based on Requirements
@@ -3,6 +3,8 @@ title: Use Hybrid Search for Better Results
impact: MEDIUM
impactDescription: Combining vector + filters improves relevance and reduces search space
tags: vector, hybrid, filters, redisvl, search
description: Use Hybrid Search for Better Results
alwaysApply: true
---
## Use Hybrid Search for Better Results
@@ -3,6 +3,8 @@ title: Configure Vector Indexes Properly
impact: HIGH
impactDescription: Correct configuration is essential for vector search accuracy
tags: vector, index, hnsw, flat, embeddings, rqe
description: Configure Vector Indexes Properly
alwaysApply: true
---
## Configure Vector Indexes Properly
@@ -3,6 +3,8 @@ title: Implement RAG Pattern Correctly
impact: HIGH
impactDescription: Proper RAG implementation improves LLM response quality
tags: vector, rag, llm, embeddings, retrieval
description: Implement RAG Pattern Correctly
alwaysApply: true
---
## Implement RAG Pattern Correctly