@shnitzel/plugscout 0.3.9 → 0.3.10

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.
@@ -41,6 +41,26 @@
41
41
  "mode": "daily",
42
42
  "rateLimitPerMinute": 90
43
43
  }
44
+ },
45
+ {
46
+ "id": "cursor",
47
+ "enabled": true,
48
+ "officialOnly": false,
49
+ "trustLevel": "medium",
50
+ "poll": {
51
+ "mode": "manual",
52
+ "rateLimitPerMinute": 60
53
+ }
54
+ },
55
+ {
56
+ "id": "google",
57
+ "enabled": true,
58
+ "officialOnly": true,
59
+ "trustLevel": "high",
60
+ "poll": {
61
+ "mode": "daily",
62
+ "rateLimitPerMinute": 60
63
+ }
44
64
  }
45
65
  ]
46
66
  }
@@ -2010,6 +2010,650 @@
2010
2010
  "timeoutMs": 15000,
2011
2011
  "fallbackToLocal": true
2012
2012
  }
2013
+ },
2014
+ {
2015
+ "id": "curated-cursor-extensions",
2016
+ "kind": "cursor-extension",
2017
+ "sourceType": "community-list",
2018
+ "adapter": "cursor-extensions-v1",
2019
+ "enabled": true,
2020
+ "officialOnly": false,
2021
+ "entries": [
2022
+ {
2023
+ "id": "cursor-extension:github-copilot",
2024
+ "name": "GitHub Copilot",
2025
+ "description": "AI pair programmer that suggests code completions and generates functions from comments.",
2026
+ "capabilities": ["code-completion", "automation", "prompting"],
2027
+ "compatibility": ["cursor", "node", "python", "general"],
2028
+ "install": {
2029
+ "kind": "manual",
2030
+ "instructions": "Install from Cursor Extensions marketplace: search 'GitHub Copilot'.",
2031
+ "url": "https://marketplace.visualstudio.com/items?itemName=GitHub.copilot"
2032
+ },
2033
+ "adoptionSignal": 95,
2034
+ "maintenanceSignal": 90,
2035
+ "provenanceSignal": 98,
2036
+ "freshnessSignal": 92,
2037
+ "securitySignals": {
2038
+ "knownVulnerabilities": 0,
2039
+ "suspiciousPatterns": 0,
2040
+ "injectionFindings": 0,
2041
+ "exfiltrationSignals": 0,
2042
+ "integrityAlerts": 0
2043
+ },
2044
+ "metadata": { "vsixId": "GitHub.copilot" }
2045
+ },
2046
+ {
2047
+ "id": "cursor-extension:prettier",
2048
+ "name": "Prettier - Code Formatter",
2049
+ "description": "Opinionated code formatter supporting JS, TS, CSS, HTML, JSON, and more.",
2050
+ "capabilities": ["formatting", "automation"],
2051
+ "compatibility": ["cursor", "node", "general"],
2052
+ "install": {
2053
+ "kind": "manual",
2054
+ "instructions": "Install from Cursor Extensions marketplace: search 'Prettier'.",
2055
+ "url": "https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode"
2056
+ },
2057
+ "adoptionSignal": 94,
2058
+ "maintenanceSignal": 88,
2059
+ "provenanceSignal": 95,
2060
+ "freshnessSignal": 90,
2061
+ "securitySignals": {
2062
+ "knownVulnerabilities": 0,
2063
+ "suspiciousPatterns": 0,
2064
+ "injectionFindings": 0,
2065
+ "exfiltrationSignals": 0,
2066
+ "integrityAlerts": 0
2067
+ },
2068
+ "metadata": { "vsixId": "esbenp.prettier-vscode" }
2069
+ },
2070
+ {
2071
+ "id": "cursor-extension:eslint",
2072
+ "name": "ESLint",
2073
+ "description": "Integrates ESLint into VS Code / Cursor for real-time JavaScript and TypeScript linting.",
2074
+ "capabilities": ["linting", "guardrails", "code-scanning"],
2075
+ "compatibility": ["cursor", "node", "general"],
2076
+ "install": {
2077
+ "kind": "manual",
2078
+ "instructions": "Install from Cursor Extensions marketplace: search 'ESLint'.",
2079
+ "url": "https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint"
2080
+ },
2081
+ "adoptionSignal": 93,
2082
+ "maintenanceSignal": 87,
2083
+ "provenanceSignal": 95,
2084
+ "freshnessSignal": 89,
2085
+ "securitySignals": {
2086
+ "knownVulnerabilities": 0,
2087
+ "suspiciousPatterns": 0,
2088
+ "injectionFindings": 0,
2089
+ "exfiltrationSignals": 0,
2090
+ "integrityAlerts": 0
2091
+ },
2092
+ "metadata": { "vsixId": "dbaeumer.vscode-eslint" }
2093
+ },
2094
+ {
2095
+ "id": "cursor-extension:gitlens",
2096
+ "name": "GitLens — Git supercharged",
2097
+ "description": "Supercharge Git inside Cursor with blame, history, code authorship, and repository insights.",
2098
+ "capabilities": ["search", "automation", "docs"],
2099
+ "compatibility": ["cursor", "general"],
2100
+ "install": {
2101
+ "kind": "manual",
2102
+ "instructions": "Install from Cursor Extensions marketplace: search 'GitLens'.",
2103
+ "url": "https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens"
2104
+ },
2105
+ "adoptionSignal": 91,
2106
+ "maintenanceSignal": 88,
2107
+ "provenanceSignal": 93,
2108
+ "freshnessSignal": 88,
2109
+ "securitySignals": {
2110
+ "knownVulnerabilities": 0,
2111
+ "suspiciousPatterns": 0,
2112
+ "injectionFindings": 0,
2113
+ "exfiltrationSignals": 0,
2114
+ "integrityAlerts": 0
2115
+ },
2116
+ "metadata": { "vsixId": "eamodio.gitlens" }
2117
+ },
2118
+ {
2119
+ "id": "cursor-extension:docker",
2120
+ "name": "Docker",
2121
+ "description": "Manage Docker containers, images, volumes, and registries from within Cursor.",
2122
+ "capabilities": ["automation", "guardrails"],
2123
+ "compatibility": ["cursor", "container", "general"],
2124
+ "install": {
2125
+ "kind": "manual",
2126
+ "instructions": "Install from Cursor Extensions marketplace: search 'Docker'.",
2127
+ "url": "https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker"
2128
+ },
2129
+ "adoptionSignal": 89,
2130
+ "maintenanceSignal": 85,
2131
+ "provenanceSignal": 96,
2132
+ "freshnessSignal": 87,
2133
+ "securitySignals": {
2134
+ "knownVulnerabilities": 0,
2135
+ "suspiciousPatterns": 0,
2136
+ "injectionFindings": 0,
2137
+ "exfiltrationSignals": 0,
2138
+ "integrityAlerts": 0
2139
+ },
2140
+ "metadata": { "vsixId": "ms-azuretools.vscode-docker" }
2141
+ },
2142
+ {
2143
+ "id": "cursor-extension:python",
2144
+ "name": "Python",
2145
+ "description": "Full Python language support: IntelliSense, linting, debugging, and Jupyter notebooks.",
2146
+ "capabilities": ["code-completion", "linting", "automation"],
2147
+ "compatibility": ["cursor", "python", "general"],
2148
+ "install": {
2149
+ "kind": "manual",
2150
+ "instructions": "Install from Cursor Extensions marketplace: search 'Python'.",
2151
+ "url": "https://marketplace.visualstudio.com/items?itemName=ms-python.python"
2152
+ },
2153
+ "adoptionSignal": 92,
2154
+ "maintenanceSignal": 90,
2155
+ "provenanceSignal": 97,
2156
+ "freshnessSignal": 91,
2157
+ "securitySignals": {
2158
+ "knownVulnerabilities": 0,
2159
+ "suspiciousPatterns": 0,
2160
+ "injectionFindings": 0,
2161
+ "exfiltrationSignals": 0,
2162
+ "integrityAlerts": 0
2163
+ },
2164
+ "metadata": { "vsixId": "ms-python.python" }
2165
+ },
2166
+ {
2167
+ "id": "cursor-extension:remote-ssh",
2168
+ "name": "Remote - SSH",
2169
+ "description": "Open any folder on a remote machine using SSH and use Cursor as your full development environment.",
2170
+ "capabilities": ["automation", "search"],
2171
+ "compatibility": ["cursor", "cloud", "general"],
2172
+ "install": {
2173
+ "kind": "manual",
2174
+ "instructions": "Install from Cursor Extensions marketplace: search 'Remote - SSH'.",
2175
+ "url": "https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh"
2176
+ },
2177
+ "adoptionSignal": 86,
2178
+ "maintenanceSignal": 84,
2179
+ "provenanceSignal": 97,
2180
+ "freshnessSignal": 85,
2181
+ "securitySignals": {
2182
+ "knownVulnerabilities": 0,
2183
+ "suspiciousPatterns": 0,
2184
+ "injectionFindings": 0,
2185
+ "exfiltrationSignals": 0,
2186
+ "integrityAlerts": 0
2187
+ },
2188
+ "metadata": { "vsixId": "ms-vscode-remote.remote-ssh" }
2189
+ },
2190
+ {
2191
+ "id": "cursor-extension:thunder-client",
2192
+ "name": "Thunder Client",
2193
+ "description": "Lightweight REST API client for testing APIs directly inside Cursor.",
2194
+ "capabilities": ["automation", "search"],
2195
+ "compatibility": ["cursor", "node", "general"],
2196
+ "install": {
2197
+ "kind": "manual",
2198
+ "instructions": "Install from Cursor Extensions marketplace: search 'Thunder Client'.",
2199
+ "url": "https://marketplace.visualstudio.com/items?itemName=rangav.vscode-thunder-client"
2200
+ },
2201
+ "adoptionSignal": 82,
2202
+ "maintenanceSignal": 79,
2203
+ "provenanceSignal": 88,
2204
+ "freshnessSignal": 81,
2205
+ "securitySignals": {
2206
+ "knownVulnerabilities": 0,
2207
+ "suspiciousPatterns": 0,
2208
+ "injectionFindings": 0,
2209
+ "exfiltrationSignals": 0,
2210
+ "integrityAlerts": 0
2211
+ },
2212
+ "metadata": { "vsixId": "rangav.vscode-thunder-client" }
2213
+ },
2214
+ {
2215
+ "id": "cursor-extension:tailwind-intellisense",
2216
+ "name": "Tailwind CSS IntelliSense",
2217
+ "description": "Intelligent Tailwind CSS tooling with autocomplete, syntax highlighting, and linting.",
2218
+ "capabilities": ["code-completion", "linting"],
2219
+ "compatibility": ["cursor", "node", "general"],
2220
+ "install": {
2221
+ "kind": "manual",
2222
+ "instructions": "Install from Cursor Extensions marketplace: search 'Tailwind CSS IntelliSense'.",
2223
+ "url": "https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss"
2224
+ },
2225
+ "adoptionSignal": 87,
2226
+ "maintenanceSignal": 85,
2227
+ "provenanceSignal": 92,
2228
+ "freshnessSignal": 86,
2229
+ "securitySignals": {
2230
+ "knownVulnerabilities": 0,
2231
+ "suspiciousPatterns": 0,
2232
+ "injectionFindings": 0,
2233
+ "exfiltrationSignals": 0,
2234
+ "integrityAlerts": 0
2235
+ },
2236
+ "metadata": { "vsixId": "bradlc.vscode-tailwindcss" }
2237
+ },
2238
+ {
2239
+ "id": "cursor-extension:error-lens",
2240
+ "name": "Error Lens",
2241
+ "description": "Improve highlighting of errors, warnings, and info messages with inline diagnostics.",
2242
+ "capabilities": ["linting", "guardrails"],
2243
+ "compatibility": ["cursor", "general"],
2244
+ "install": {
2245
+ "kind": "manual",
2246
+ "instructions": "Install from Cursor Extensions marketplace: search 'Error Lens'.",
2247
+ "url": "https://marketplace.visualstudio.com/items?itemName=usernamehw.errorlens"
2248
+ },
2249
+ "adoptionSignal": 84,
2250
+ "maintenanceSignal": 80,
2251
+ "provenanceSignal": 88,
2252
+ "freshnessSignal": 83,
2253
+ "securitySignals": {
2254
+ "knownVulnerabilities": 0,
2255
+ "suspiciousPatterns": 0,
2256
+ "injectionFindings": 0,
2257
+ "exfiltrationSignals": 0,
2258
+ "integrityAlerts": 0
2259
+ },
2260
+ "metadata": { "vsixId": "usernamehw.errorlens" }
2261
+ },
2262
+ {
2263
+ "id": "cursor-extension:prisma",
2264
+ "name": "Prisma",
2265
+ "description": "Official Prisma extension with schema syntax highlighting, formatting, and jump-to-definition.",
2266
+ "capabilities": ["code-completion", "formatting"],
2267
+ "compatibility": ["cursor", "node", "postgresql", "general"],
2268
+ "install": {
2269
+ "kind": "manual",
2270
+ "instructions": "Install from Cursor Extensions marketplace: search 'Prisma'.",
2271
+ "url": "https://marketplace.visualstudio.com/items?itemName=Prisma.prisma"
2272
+ },
2273
+ "adoptionSignal": 80,
2274
+ "maintenanceSignal": 82,
2275
+ "provenanceSignal": 92,
2276
+ "freshnessSignal": 80,
2277
+ "securitySignals": {
2278
+ "knownVulnerabilities": 0,
2279
+ "suspiciousPatterns": 0,
2280
+ "injectionFindings": 0,
2281
+ "exfiltrationSignals": 0,
2282
+ "integrityAlerts": 0
2283
+ },
2284
+ "metadata": { "vsixId": "Prisma.prisma" }
2285
+ },
2286
+ {
2287
+ "id": "cursor-extension:markdownlint",
2288
+ "name": "markdownlint",
2289
+ "description": "Markdown linting and style checking for consistent documentation.",
2290
+ "capabilities": ["linting", "guardrails", "docs"],
2291
+ "compatibility": ["cursor", "general"],
2292
+ "install": {
2293
+ "kind": "manual",
2294
+ "instructions": "Install from Cursor Extensions marketplace: search 'markdownlint'.",
2295
+ "url": "https://marketplace.visualstudio.com/items?itemName=DavidAnson.vscode-markdownlint"
2296
+ },
2297
+ "adoptionSignal": 79,
2298
+ "maintenanceSignal": 81,
2299
+ "provenanceSignal": 90,
2300
+ "freshnessSignal": 80,
2301
+ "securitySignals": {
2302
+ "knownVulnerabilities": 0,
2303
+ "suspiciousPatterns": 0,
2304
+ "injectionFindings": 0,
2305
+ "exfiltrationSignals": 0,
2306
+ "integrityAlerts": 0
2307
+ },
2308
+ "metadata": { "vsixId": "DavidAnson.vscode-markdownlint" }
2309
+ },
2310
+ {
2311
+ "id": "cursor-extension:vscode-icons",
2312
+ "name": "vscode-icons",
2313
+ "description": "Brings icons to the Explorer panel for better file type visualization in Cursor.",
2314
+ "capabilities": ["productivity"],
2315
+ "compatibility": ["cursor", "general"],
2316
+ "install": {
2317
+ "kind": "manual",
2318
+ "instructions": "Install from Cursor Extensions marketplace: search 'vscode-icons'.",
2319
+ "url": "https://marketplace.visualstudio.com/items?itemName=vscode-icons-team.vscode-icons"
2320
+ },
2321
+ "adoptionSignal": 88,
2322
+ "maintenanceSignal": 84,
2323
+ "provenanceSignal": 89,
2324
+ "freshnessSignal": 85,
2325
+ "securitySignals": {
2326
+ "knownVulnerabilities": 0,
2327
+ "suspiciousPatterns": 0,
2328
+ "injectionFindings": 0,
2329
+ "exfiltrationSignals": 0,
2330
+ "integrityAlerts": 0
2331
+ },
2332
+ "metadata": { "vsixId": "vscode-icons-team.vscode-icons" }
2333
+ },
2334
+ {
2335
+ "id": "cursor-extension:path-intellisense",
2336
+ "name": "Path Intellisense",
2337
+ "description": "Autocompletes filenames and directory paths as you type import statements.",
2338
+ "capabilities": ["code-completion", "productivity"],
2339
+ "compatibility": ["cursor", "node", "general"],
2340
+ "install": {
2341
+ "kind": "manual",
2342
+ "instructions": "Install from Cursor Extensions marketplace: search 'Path Intellisense'.",
2343
+ "url": "https://marketplace.visualstudio.com/items?itemName=christian-kohler.path-intellisense"
2344
+ },
2345
+ "adoptionSignal": 83,
2346
+ "maintenanceSignal": 78,
2347
+ "provenanceSignal": 88,
2348
+ "freshnessSignal": 81,
2349
+ "securitySignals": {
2350
+ "knownVulnerabilities": 0,
2351
+ "suspiciousPatterns": 0,
2352
+ "injectionFindings": 0,
2353
+ "exfiltrationSignals": 0,
2354
+ "integrityAlerts": 0
2355
+ },
2356
+ "metadata": { "vsixId": "christian-kohler.path-intellisense" }
2357
+ },
2358
+ {
2359
+ "id": "cursor-extension:todo-highlight",
2360
+ "name": "TODO Highlight",
2361
+ "description": "Highlight TODO, FIXME, and other annotations in your code to keep track of open tasks.",
2362
+ "capabilities": ["guardrails", "productivity"],
2363
+ "compatibility": ["cursor", "general"],
2364
+ "install": {
2365
+ "kind": "manual",
2366
+ "instructions": "Install from Cursor Extensions marketplace: search 'TODO Highlight'.",
2367
+ "url": "https://marketplace.visualstudio.com/items?itemName=wayou.vscode-todo-highlight"
2368
+ },
2369
+ "adoptionSignal": 78,
2370
+ "maintenanceSignal": 72,
2371
+ "provenanceSignal": 86,
2372
+ "freshnessSignal": 76,
2373
+ "securitySignals": {
2374
+ "knownVulnerabilities": 0,
2375
+ "suspiciousPatterns": 0,
2376
+ "injectionFindings": 0,
2377
+ "exfiltrationSignals": 0,
2378
+ "integrityAlerts": 0
2379
+ },
2380
+ "metadata": { "vsixId": "wayou.vscode-todo-highlight" }
2381
+ }
2382
+ ]
2383
+ },
2384
+ {
2385
+ "id": "curated-gemini-extensions",
2386
+ "kind": "gemini-extension",
2387
+ "sourceType": "community-list",
2388
+ "adapter": "gemini-extensions-v1",
2389
+ "enabled": true,
2390
+ "officialOnly": false,
2391
+ "entries": [
2392
+ {
2393
+ "id": "gemini-extension:filesystem",
2394
+ "name": "Filesystem MCP Server",
2395
+ "description": "Read and write local files via the Model Context Protocol from Gemini CLI.",
2396
+ "capabilities": ["file-read", "file-write", "search"],
2397
+ "compatibility": ["gemini", "gemini-cli", "node"],
2398
+ "install": {
2399
+ "kind": "manual",
2400
+ "instructions": "Add to ~/.gemini/settings.json under mcpServers: { \"filesystem\": { \"command\": \"npx\", \"args\": [\"-y\", \"@modelcontextprotocol/server-filesystem\"] } }",
2401
+ "url": "https://www.npmjs.com/package/@modelcontextprotocol/server-filesystem"
2402
+ },
2403
+ "adoptionSignal": 88,
2404
+ "maintenanceSignal": 86,
2405
+ "provenanceSignal": 95,
2406
+ "freshnessSignal": 84,
2407
+ "securitySignals": {
2408
+ "knownVulnerabilities": 0,
2409
+ "suspiciousPatterns": 1,
2410
+ "injectionFindings": 0,
2411
+ "exfiltrationSignals": 0,
2412
+ "integrityAlerts": 0
2413
+ },
2414
+ "metadata": { "npmPackage": "@modelcontextprotocol/server-filesystem" }
2415
+ },
2416
+ {
2417
+ "id": "gemini-extension:github",
2418
+ "name": "GitHub MCP Server",
2419
+ "description": "Search code, manage issues and PRs, and access repository data from Gemini CLI.",
2420
+ "capabilities": ["search", "automation", "code-scanning"],
2421
+ "compatibility": ["gemini", "gemini-cli", "node", "github"],
2422
+ "install": {
2423
+ "kind": "manual",
2424
+ "instructions": "Add to ~/.gemini/settings.json under mcpServers: { \"github\": { \"command\": \"npx\", \"args\": [\"-y\", \"@modelcontextprotocol/server-github\"] } }",
2425
+ "url": "https://www.npmjs.com/package/@modelcontextprotocol/server-github"
2426
+ },
2427
+ "adoptionSignal": 86,
2428
+ "maintenanceSignal": 84,
2429
+ "provenanceSignal": 95,
2430
+ "freshnessSignal": 85,
2431
+ "securitySignals": {
2432
+ "knownVulnerabilities": 0,
2433
+ "suspiciousPatterns": 0,
2434
+ "injectionFindings": 0,
2435
+ "exfiltrationSignals": 0,
2436
+ "integrityAlerts": 0
2437
+ },
2438
+ "metadata": { "npmPackage": "@modelcontextprotocol/server-github" }
2439
+ },
2440
+ {
2441
+ "id": "gemini-extension:brave-search",
2442
+ "name": "Brave Search MCP Server",
2443
+ "description": "Web and local search via the Brave Search API from Gemini CLI.",
2444
+ "capabilities": ["search", "automation"],
2445
+ "compatibility": ["gemini", "gemini-cli", "node", "general"],
2446
+ "install": {
2447
+ "kind": "manual",
2448
+ "instructions": "Add to ~/.gemini/settings.json under mcpServers: { \"brave-search\": { \"command\": \"npx\", \"args\": [\"-y\", \"@modelcontextprotocol/server-brave-search\"] } }",
2449
+ "url": "https://www.npmjs.com/package/@modelcontextprotocol/server-brave-search"
2450
+ },
2451
+ "adoptionSignal": 83,
2452
+ "maintenanceSignal": 81,
2453
+ "provenanceSignal": 93,
2454
+ "freshnessSignal": 82,
2455
+ "securitySignals": {
2456
+ "knownVulnerabilities": 0,
2457
+ "suspiciousPatterns": 0,
2458
+ "injectionFindings": 0,
2459
+ "exfiltrationSignals": 0,
2460
+ "integrityAlerts": 0
2461
+ },
2462
+ "metadata": { "npmPackage": "@modelcontextprotocol/server-brave-search" }
2463
+ },
2464
+ {
2465
+ "id": "gemini-extension:sequential-thinking",
2466
+ "name": "Sequential Thinking MCP Server",
2467
+ "description": "Structured step-by-step reasoning tool for complex problem decomposition in Gemini CLI.",
2468
+ "capabilities": ["prompting", "automation"],
2469
+ "compatibility": ["gemini", "gemini-cli", "node", "general"],
2470
+ "install": {
2471
+ "kind": "manual",
2472
+ "instructions": "Add to ~/.gemini/settings.json under mcpServers: { \"sequential-thinking\": { \"command\": \"npx\", \"args\": [\"-y\", \"@modelcontextprotocol/server-sequential-thinking\"] } }",
2473
+ "url": "https://www.npmjs.com/package/@modelcontextprotocol/server-sequential-thinking"
2474
+ },
2475
+ "adoptionSignal": 80,
2476
+ "maintenanceSignal": 82,
2477
+ "provenanceSignal": 93,
2478
+ "freshnessSignal": 80,
2479
+ "securitySignals": {
2480
+ "knownVulnerabilities": 0,
2481
+ "suspiciousPatterns": 0,
2482
+ "injectionFindings": 0,
2483
+ "exfiltrationSignals": 0,
2484
+ "integrityAlerts": 0
2485
+ },
2486
+ "metadata": { "npmPackage": "@modelcontextprotocol/server-sequential-thinking" }
2487
+ },
2488
+ {
2489
+ "id": "gemini-extension:postgres",
2490
+ "name": "PostgreSQL MCP Server",
2491
+ "description": "Query and explore PostgreSQL databases directly from Gemini CLI.",
2492
+ "capabilities": ["search", "automation"],
2493
+ "compatibility": ["gemini", "gemini-cli", "node", "postgresql"],
2494
+ "install": {
2495
+ "kind": "manual",
2496
+ "instructions": "Add to ~/.gemini/settings.json under mcpServers: { \"postgres\": { \"command\": \"npx\", \"args\": [\"-y\", \"@modelcontextprotocol/server-postgres\"] } }",
2497
+ "url": "https://www.npmjs.com/package/@modelcontextprotocol/server-postgres"
2498
+ },
2499
+ "adoptionSignal": 82,
2500
+ "maintenanceSignal": 80,
2501
+ "provenanceSignal": 93,
2502
+ "freshnessSignal": 81,
2503
+ "securitySignals": {
2504
+ "knownVulnerabilities": 0,
2505
+ "suspiciousPatterns": 0,
2506
+ "injectionFindings": 0,
2507
+ "exfiltrationSignals": 0,
2508
+ "integrityAlerts": 0
2509
+ },
2510
+ "metadata": { "npmPackage": "@modelcontextprotocol/server-postgres" }
2511
+ },
2512
+ {
2513
+ "id": "gemini-extension:memory",
2514
+ "name": "Memory MCP Server",
2515
+ "description": "Persistent key-value memory store enabling Gemini CLI to remember facts across sessions.",
2516
+ "capabilities": ["automation", "prompting"],
2517
+ "compatibility": ["gemini", "gemini-cli", "node", "general"],
2518
+ "install": {
2519
+ "kind": "manual",
2520
+ "instructions": "Add to ~/.gemini/settings.json under mcpServers: { \"memory\": { \"command\": \"npx\", \"args\": [\"-y\", \"@modelcontextprotocol/server-memory\"] } }",
2521
+ "url": "https://www.npmjs.com/package/@modelcontextprotocol/server-memory"
2522
+ },
2523
+ "adoptionSignal": 81,
2524
+ "maintenanceSignal": 83,
2525
+ "provenanceSignal": 93,
2526
+ "freshnessSignal": 82,
2527
+ "securitySignals": {
2528
+ "knownVulnerabilities": 0,
2529
+ "suspiciousPatterns": 0,
2530
+ "injectionFindings": 0,
2531
+ "exfiltrationSignals": 0,
2532
+ "integrityAlerts": 0
2533
+ },
2534
+ "metadata": { "npmPackage": "@modelcontextprotocol/server-memory" }
2535
+ },
2536
+ {
2537
+ "id": "gemini-extension:puppeteer",
2538
+ "name": "Puppeteer MCP Server",
2539
+ "description": "Browser automation and web scraping using Puppeteer from Gemini CLI.",
2540
+ "capabilities": ["browser-control", "automation", "search"],
2541
+ "compatibility": ["gemini", "gemini-cli", "node"],
2542
+ "install": {
2543
+ "kind": "manual",
2544
+ "instructions": "Add to ~/.gemini/settings.json under mcpServers: { \"puppeteer\": { \"command\": \"npx\", \"args\": [\"-y\", \"@modelcontextprotocol/server-puppeteer\"] } }",
2545
+ "url": "https://www.npmjs.com/package/@modelcontextprotocol/server-puppeteer"
2546
+ },
2547
+ "adoptionSignal": 78,
2548
+ "maintenanceSignal": 76,
2549
+ "provenanceSignal": 91,
2550
+ "freshnessSignal": 78,
2551
+ "securitySignals": {
2552
+ "knownVulnerabilities": 0,
2553
+ "suspiciousPatterns": 1,
2554
+ "injectionFindings": 0,
2555
+ "exfiltrationSignals": 0,
2556
+ "integrityAlerts": 0
2557
+ },
2558
+ "metadata": { "npmPackage": "@modelcontextprotocol/server-puppeteer" }
2559
+ },
2560
+ {
2561
+ "id": "gemini-extension:slack",
2562
+ "name": "Slack MCP Server",
2563
+ "description": "Read messages, search channels, and post to Slack from Gemini CLI.",
2564
+ "capabilities": ["automation", "search", "productivity"],
2565
+ "compatibility": ["gemini", "gemini-cli", "node", "general"],
2566
+ "install": {
2567
+ "kind": "manual",
2568
+ "instructions": "Add to ~/.gemini/settings.json under mcpServers: { \"slack\": { \"command\": \"npx\", \"args\": [\"-y\", \"@modelcontextprotocol/server-slack\"] } }",
2569
+ "url": "https://www.npmjs.com/package/@modelcontextprotocol/server-slack"
2570
+ },
2571
+ "adoptionSignal": 79,
2572
+ "maintenanceSignal": 77,
2573
+ "provenanceSignal": 91,
2574
+ "freshnessSignal": 79,
2575
+ "securitySignals": {
2576
+ "knownVulnerabilities": 0,
2577
+ "suspiciousPatterns": 0,
2578
+ "injectionFindings": 0,
2579
+ "exfiltrationSignals": 0,
2580
+ "integrityAlerts": 0
2581
+ },
2582
+ "metadata": { "npmPackage": "@modelcontextprotocol/server-slack" }
2583
+ },
2584
+ {
2585
+ "id": "gemini-extension:google-maps",
2586
+ "name": "Google Maps MCP Server",
2587
+ "description": "Geocoding, directions, and place search via Google Maps API from Gemini CLI.",
2588
+ "capabilities": ["search", "automation"],
2589
+ "compatibility": ["gemini", "gemini-cli", "node", "general"],
2590
+ "install": {
2591
+ "kind": "manual",
2592
+ "instructions": "Add to ~/.gemini/settings.json under mcpServers: { \"google-maps\": { \"command\": \"npx\", \"args\": [\"-y\", \"@modelcontextprotocol/server-google-maps\"] } }",
2593
+ "url": "https://www.npmjs.com/package/@modelcontextprotocol/server-google-maps"
2594
+ },
2595
+ "adoptionSignal": 76,
2596
+ "maintenanceSignal": 78,
2597
+ "provenanceSignal": 91,
2598
+ "freshnessSignal": 77,
2599
+ "securitySignals": {
2600
+ "knownVulnerabilities": 0,
2601
+ "suspiciousPatterns": 0,
2602
+ "injectionFindings": 0,
2603
+ "exfiltrationSignals": 0,
2604
+ "integrityAlerts": 0
2605
+ },
2606
+ "metadata": { "npmPackage": "@modelcontextprotocol/server-google-maps" }
2607
+ },
2608
+ {
2609
+ "id": "gemini-extension:sentry",
2610
+ "name": "Sentry MCP Server",
2611
+ "description": "Retrieve Sentry issues, events, and error details from Gemini CLI.",
2612
+ "capabilities": ["search", "automation", "security"],
2613
+ "compatibility": ["gemini", "gemini-cli", "node", "general"],
2614
+ "install": {
2615
+ "kind": "manual",
2616
+ "instructions": "Add to ~/.gemini/settings.json under mcpServers: { \"sentry\": { \"command\": \"npx\", \"args\": [\"-y\", \"@modelcontextprotocol/server-sentry\"] } }",
2617
+ "url": "https://www.npmjs.com/package/@modelcontextprotocol/server-sentry"
2618
+ },
2619
+ "adoptionSignal": 77,
2620
+ "maintenanceSignal": 79,
2621
+ "provenanceSignal": 91,
2622
+ "freshnessSignal": 78,
2623
+ "securitySignals": {
2624
+ "knownVulnerabilities": 0,
2625
+ "suspiciousPatterns": 0,
2626
+ "injectionFindings": 0,
2627
+ "exfiltrationSignals": 0,
2628
+ "integrityAlerts": 0
2629
+ },
2630
+ "metadata": { "npmPackage": "@modelcontextprotocol/server-sentry" }
2631
+ },
2632
+ {
2633
+ "id": "gemini-extension:linear",
2634
+ "name": "Linear MCP Server",
2635
+ "description": "Manage Linear issues, projects, and cycles from Gemini CLI.",
2636
+ "capabilities": ["tickets", "automation", "search"],
2637
+ "compatibility": ["gemini", "gemini-cli", "node", "general"],
2638
+ "install": {
2639
+ "kind": "manual",
2640
+ "instructions": "Add to ~/.gemini/settings.json under mcpServers: { \"linear\": { \"command\": \"npx\", \"args\": [\"-y\", \"@modelcontextprotocol/server-linear\"] } }",
2641
+ "url": "https://www.npmjs.com/package/@modelcontextprotocol/server-linear"
2642
+ },
2643
+ "adoptionSignal": 75,
2644
+ "maintenanceSignal": 77,
2645
+ "provenanceSignal": 89,
2646
+ "freshnessSignal": 76,
2647
+ "securitySignals": {
2648
+ "knownVulnerabilities": 0,
2649
+ "suspiciousPatterns": 0,
2650
+ "injectionFindings": 0,
2651
+ "exfiltrationSignals": 0,
2652
+ "integrityAlerts": 0
2653
+ },
2654
+ "metadata": { "npmPackage": "@modelcontextprotocol/server-linear" }
2655
+ }
2656
+ ]
2013
2657
  }
2014
2658
  ]
2015
2659
  }
@@ -1,4 +1,6 @@
1
1
  import { adaptAwesomeClaudeCodeEntries } from './adapters/awesome-claude-code-v1.js';
2
+ import { adaptCursorExtensionsEntries } from './adapters/cursor-extensions-v1.js';
3
+ import { adaptGeminiExtensionsEntries } from './adapters/gemini-extensions-v1.js';
2
4
  import { adaptClaudeConnectorsScrapeEntries } from './adapters/claude-connectors-scrape-v1.js';
3
5
  import { adaptClaudeCodeMarketplaceEntries } from './adapters/claude-code-marketplace-v1.js';
4
6
  import { adaptClaudePluginsEntries } from './adapters/claude-plugins-v0.1.js';
@@ -39,5 +41,11 @@ export function adaptRegistryEntries(registry, entries) {
39
41
  if (registry.adapter === 'awesome-claude-code-v1') {
40
42
  return adaptAwesomeClaudeCodeEntries(registry.id, entries);
41
43
  }
44
+ if (registry.adapter === 'cursor-extensions-v1') {
45
+ return adaptCursorExtensionsEntries(registry.id, entries);
46
+ }
47
+ if (registry.adapter === 'gemini-extensions-v1') {
48
+ return adaptGeminiExtensionsEntries(registry.id, entries);
49
+ }
42
50
  return entries;
43
51
  }
@@ -0,0 +1,60 @@
1
+ import { dedupe, extractStringArray, readString, toCount, toScore } from './shared.js';
2
+ export function adaptCursorExtensionsEntries(sourceId, entries) {
3
+ return entries
4
+ .map((entry) => mapCursorExtensionEntry(sourceId, entry))
5
+ .filter((entry) => entry !== null);
6
+ }
7
+ function mapCursorExtensionEntry(sourceId, entry) {
8
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
9
+ return null;
10
+ }
11
+ const record = entry;
12
+ const slug = readString(record, ['slug', 'id', 'name']);
13
+ if (!slug) {
14
+ return null;
15
+ }
16
+ const name = readString(record, ['title', 'name']) ?? slug;
17
+ const description = readString(record, ['description', 'summary']) ?? `Cursor extension ${name}`;
18
+ const capabilities = dedupe(extractStringArray(record, ['capabilities', 'tools']).concat(extractStringArray(record, ['tags'])));
19
+ const compatibility = dedupe(extractStringArray(record, ['compatibility']).concat(['cursor']));
20
+ const metadata = record.metadata && typeof record.metadata === 'object' && !Array.isArray(record.metadata)
21
+ ? record.metadata
22
+ : {};
23
+ const vsixId = typeof record.vsixId === 'string' ? record.vsixId : typeof metadata.vsixId === 'string' ? metadata.vsixId : undefined;
24
+ const installInstructions = readString(record, ['install', 'instructions']) ??
25
+ (vsixId
26
+ ? `Install via Cursor Marketplace: open Extensions panel (Cmd+Shift+X) and search for ${name}.`
27
+ : `Install via Cursor Marketplace: open Extensions panel (Cmd+Shift+X) and search for ${name}.`);
28
+ const installUrl = readString(record, ['install', 'url']) ??
29
+ (vsixId ? `https://marketplace.visualstudio.com/items?itemName=${vsixId}` : undefined);
30
+ return {
31
+ id: slug.startsWith('cursor-extension:') ? slug : `cursor-extension:${slug}`,
32
+ kind: 'cursor-extension',
33
+ provider: readString(record, ['provider']) ?? 'cursor',
34
+ name,
35
+ description,
36
+ capabilities,
37
+ compatibility,
38
+ source: sourceId,
39
+ install: {
40
+ kind: 'manual',
41
+ instructions: installInstructions,
42
+ ...(installUrl ? { url: installUrl } : {})
43
+ },
44
+ adoptionSignal: toScore(record.adoptionSignal, 50),
45
+ maintenanceSignal: toScore(record.maintenanceSignal, 50),
46
+ provenanceSignal: toScore(record.provenanceSignal, 70),
47
+ freshnessSignal: toScore(record.freshnessSignal, 60),
48
+ securitySignals: {
49
+ knownVulnerabilities: toCount(record.knownVulnerabilities),
50
+ suspiciousPatterns: toCount(record.suspiciousPatterns),
51
+ injectionFindings: toCount(record.injectionFindings),
52
+ exfiltrationSignals: toCount(record.exfiltrationSignals),
53
+ integrityAlerts: toCount(record.integrityAlerts)
54
+ },
55
+ metadata: {
56
+ ...metadata,
57
+ ...(vsixId ? { vsixId } : {})
58
+ }
59
+ };
60
+ }
@@ -0,0 +1,64 @@
1
+ import { dedupe, extractStringArray, readString, toCount, toScore } from './shared.js';
2
+ export function adaptGeminiExtensionsEntries(sourceId, entries) {
3
+ return entries
4
+ .map((entry) => mapGeminiExtensionEntry(sourceId, entry))
5
+ .filter((entry) => entry !== null);
6
+ }
7
+ function mapGeminiExtensionEntry(sourceId, entry) {
8
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
9
+ return null;
10
+ }
11
+ const record = entry;
12
+ const slug = readString(record, ['slug', 'id', 'name']);
13
+ if (!slug) {
14
+ return null;
15
+ }
16
+ const name = readString(record, ['title', 'name']) ?? slug;
17
+ const description = readString(record, ['description', 'summary']) ?? `Gemini CLI extension ${name}`;
18
+ const capabilities = dedupe(extractStringArray(record, ['capabilities', 'tools']).concat(extractStringArray(record, ['tags'])));
19
+ const compatibility = dedupe(extractStringArray(record, ['compatibility']).concat(['gemini', 'gemini-cli']));
20
+ const metadata = record.metadata && typeof record.metadata === 'object' && !Array.isArray(record.metadata)
21
+ ? record.metadata
22
+ : {};
23
+ const npmPkg = typeof record.npmPackage === 'string'
24
+ ? record.npmPackage
25
+ : typeof metadata.npmPackage === 'string'
26
+ ? metadata.npmPackage
27
+ : undefined;
28
+ const installInstructions = readString(record, ['install', 'instructions']) ??
29
+ (npmPkg
30
+ ? `Add to ~/.gemini/settings.json under mcpServers: { "${slug.replace('gemini-extension:', '')}": { "command": "npx", "args": ["-y", "${npmPkg}"] } }`
31
+ : `Configure in ~/.gemini/settings.json under mcpServers.`);
32
+ const installUrl = readString(record, ['install', 'url']) ??
33
+ (npmPkg ? `https://www.npmjs.com/package/${npmPkg}` : undefined);
34
+ return {
35
+ id: slug.startsWith('gemini-extension:') ? slug : `gemini-extension:${slug}`,
36
+ kind: 'gemini-extension',
37
+ provider: readString(record, ['provider']) ?? 'google',
38
+ name,
39
+ description,
40
+ capabilities,
41
+ compatibility,
42
+ source: sourceId,
43
+ install: {
44
+ kind: 'manual',
45
+ instructions: installInstructions,
46
+ ...(installUrl ? { url: installUrl } : {})
47
+ },
48
+ adoptionSignal: toScore(record.adoptionSignal, 50),
49
+ maintenanceSignal: toScore(record.maintenanceSignal, 50),
50
+ provenanceSignal: toScore(record.provenanceSignal, 75),
51
+ freshnessSignal: toScore(record.freshnessSignal, 60),
52
+ securitySignals: {
53
+ knownVulnerabilities: toCount(record.knownVulnerabilities),
54
+ suspiciousPatterns: toCount(record.suspiciousPatterns),
55
+ injectionFindings: toCount(record.injectionFindings),
56
+ exfiltrationSignals: toCount(record.exfiltrationSignals),
57
+ integrityAlerts: toCount(record.integrityAlerts)
58
+ },
59
+ metadata: {
60
+ ...metadata,
61
+ ...(npmPkg ? { npmPackage: npmPkg } : {})
62
+ }
63
+ };
64
+ }
@@ -132,6 +132,12 @@ function defaultCatalogKeyByKind(kind) {
132
132
  if (kind === 'copilot-extension') {
133
133
  return 'extensions';
134
134
  }
135
+ if (kind === 'cursor-extension') {
136
+ return 'extensions';
137
+ }
138
+ if (kind === 'gemini-extension') {
139
+ return 'extensions';
140
+ }
135
141
  return 'skills';
136
142
  }
137
143
  function resolveByPath(value, path) {
@@ -192,5 +198,10 @@ function validateRemoteHost(registry) {
192
198
  }
193
199
  }
194
200
  function requiresSafeHostAllowlist(kind) {
195
- return kind === 'claude-plugin' || kind === 'claude-connector' || kind === 'copilot-extension' || kind === 'mcp';
201
+ return (kind === 'claude-plugin' ||
202
+ kind === 'claude-connector' ||
203
+ kind === 'copilot-extension' ||
204
+ kind === 'cursor-extension' ||
205
+ kind === 'gemini-extension' ||
206
+ kind === 'mcp');
196
207
  }
@@ -38,7 +38,7 @@ export async function syncCatalogs(today = new Date().toISOString().slice(0, 10)
38
38
  await Promise.all([saveCatalogItems(mergedItems), saveLegacyCatalogViews(mergedItems)]);
39
39
  await saveSyncState(syncState);
40
40
  const kindCounts = countByKind(mergedItems);
41
- logger.info(`Synced ${mergedItems.length} items (${kindCounts.skill} skills, ${kindCounts.mcp} MCPs, ${kindCounts['claude-plugin']} Claude plugins, ${kindCounts['claude-connector']} Claude connectors, ${kindCounts['copilot-extension']} Copilot extensions)`);
41
+ logger.info(`Synced ${mergedItems.length} items (${kindCounts.skill} skills, ${kindCounts.mcp} MCPs, ${kindCounts['claude-plugin']} Claude plugins, ${kindCounts['claude-connector']} Claude connectors, ${kindCounts['copilot-extension']} Copilot extensions, ${kindCounts['cursor-extension']} Cursor extensions, ${kindCounts['gemini-extension']} Gemini extensions)`);
42
42
  const staleRegistries = getStaleRegistries(syncState);
43
43
  if (staleRegistries.length > 0) {
44
44
  logger.warn(`Stale registries (>48h without success): ${staleRegistries.join(', ')}`);
@@ -84,7 +84,9 @@ function normalizeId(id, kind) {
84
84
  mcp: 'mcp',
85
85
  'claude-plugin': 'claude-plugin',
86
86
  'claude-connector': 'claude-connector',
87
- 'copilot-extension': 'copilot-extension'
87
+ 'copilot-extension': 'copilot-extension',
88
+ 'cursor-extension': 'cursor-extension',
89
+ 'gemini-extension': 'gemini-extension'
88
90
  };
89
91
  return `${prefixMap[kind]}:${id.replace(/^([a-z-]+):/, '')}`;
90
92
  }
@@ -101,6 +103,12 @@ function inferProviderFromKind(kind) {
101
103
  if (kind === 'copilot-extension') {
102
104
  return 'github';
103
105
  }
106
+ if (kind === 'cursor-extension') {
107
+ return 'cursor';
108
+ }
109
+ if (kind === 'gemini-extension') {
110
+ return 'google';
111
+ }
104
112
  return 'openai';
105
113
  }
106
114
  function mergeItemsById(items) {
@@ -142,7 +150,9 @@ function countByKind(items) {
142
150
  mcp: 0,
143
151
  'claude-plugin': 0,
144
152
  'claude-connector': 0,
145
- 'copilot-extension': 0
153
+ 'copilot-extension': 0,
154
+ 'cursor-extension': 0,
155
+ 'gemini-extension': 0
146
156
  });
147
157
  }
148
158
  function defaultSourceConfidence(sourceType) {
@@ -0,0 +1,60 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import os from 'node:os';
4
+ const PLUGSCOUT_MCP_VALUE = { command: 'npx', args: ['plugscout', 'mcp'] };
5
+ export function getConfigPath(client, scope) {
6
+ if (client === 'cursor') {
7
+ if (scope === 'project') {
8
+ return path.join(process.cwd(), '.cursor', 'mcp.json');
9
+ }
10
+ return path.join(os.homedir(), '.cursor', 'mcp.json');
11
+ }
12
+ return path.join(os.homedir(), '.gemini', 'settings.json');
13
+ }
14
+ export async function getClientMcpConfigStatus(client, scope) {
15
+ const configPath = getConfigPath(client, scope);
16
+ try {
17
+ const raw = await fs.readFile(configPath, 'utf8');
18
+ const config = JSON.parse(raw);
19
+ const mcpServers = config.mcpServers;
20
+ const configured = !!(mcpServers?.plugscout);
21
+ return { configured, configPath };
22
+ }
23
+ catch {
24
+ return { configured: false, configPath };
25
+ }
26
+ }
27
+ export async function writeClientMcpConfig(options) {
28
+ const { client, force = false } = options;
29
+ const scope = client === 'gemini' ? 'user' : options.scope;
30
+ const configPath = getConfigPath(client, scope);
31
+ let existing = {};
32
+ try {
33
+ const raw = await fs.readFile(configPath, 'utf8');
34
+ existing = JSON.parse(raw);
35
+ }
36
+ catch {
37
+ // file doesn't exist yet — start empty
38
+ }
39
+ const mcpServers = existing.mcpServers ?? {};
40
+ const current = mcpServers.plugscout;
41
+ if (current !== undefined) {
42
+ const isSame = JSON.stringify(current) === JSON.stringify(PLUGSCOUT_MCP_VALUE);
43
+ if (isSame) {
44
+ return { status: 'already-configured', configPath };
45
+ }
46
+ if (!force) {
47
+ throw new Error(`plugscout already exists in ${configPath} with a different value. Use --force to overwrite.`);
48
+ }
49
+ }
50
+ const updated = {
51
+ ...existing,
52
+ mcpServers: { ...mcpServers, plugscout: PLUGSCOUT_MCP_VALUE }
53
+ };
54
+ const dir = path.dirname(configPath);
55
+ await fs.mkdir(dir, { recursive: true });
56
+ const tmpPath = `${configPath}.plugscout.tmp`;
57
+ await fs.writeFile(tmpPath, `${JSON.stringify(updated, null, 2)}\n`, 'utf8');
58
+ await fs.rename(tmpPath, configPath);
59
+ return { status: 'written', configPath };
60
+ }
@@ -1,9 +1,11 @@
1
1
  import { spawnSync } from 'node:child_process';
2
2
  import path from 'node:path';
3
+ import os from 'node:os';
3
4
  import fs from 'node:fs/promises';
4
5
  import { getStaleRegistries, loadSyncState } from '../../catalog/sync-state.js';
5
6
  import { loadCatalogItems } from '../../catalog/repository.js';
6
7
  import { hasLegacySkillSh, resolveSkillsRuntime } from '../../install/dependencies.js';
8
+ import { getClientMcpConfigStatus } from './client-setup.js';
7
9
  export async function runDoctorChecks(projectPath = '.') {
8
10
  const checks = [];
9
11
  checks.push(checkSkillsRuntime());
@@ -58,6 +60,34 @@ export async function runDoctorChecks(projectPath = '.') {
58
60
  suggestion: 'Run: npm run dev -- init'
59
61
  });
60
62
  }
63
+ // Cursor IDE check
64
+ const cursorInstalled = spawnSync('which', ['cursor'], { encoding: 'utf8' }).status === 0 ||
65
+ await fs.access(path.join(os.homedir(), '.cursor')).then(() => true).catch(() => false);
66
+ checks.push(cursorInstalled
67
+ ? { name: 'Cursor IDE', status: 'pass', message: 'Cursor detected' }
68
+ : { name: 'Cursor IDE', status: 'warn', message: 'Cursor not detected', suggestion: 'Install Cursor from https://cursor.sh' });
69
+ // Gemini CLI check
70
+ checks.push(checkBinary('gemini', { suggestion: 'Install Gemini CLI: npm install -g @google/gemini-cli' }));
71
+ // Cursor MCP config check
72
+ try {
73
+ const cursorStatus = await getClientMcpConfigStatus('cursor', 'user');
74
+ checks.push(cursorStatus.configured
75
+ ? { name: 'Cursor MCP config', status: 'pass', message: `plugscout wired in ${cursorStatus.configPath}` }
76
+ : { name: 'Cursor MCP config', status: 'warn', message: 'plugscout not in Cursor MCP config', suggestion: 'Run: plugscout client setup --client cursor' });
77
+ }
78
+ catch {
79
+ checks.push({ name: 'Cursor MCP config', status: 'warn', message: 'Could not read Cursor MCP config', suggestion: 'Run: plugscout client setup --client cursor' });
80
+ }
81
+ // Gemini MCP config check
82
+ try {
83
+ const geminiStatus = await getClientMcpConfigStatus('gemini', 'user');
84
+ checks.push(geminiStatus.configured
85
+ ? { name: 'Gemini MCP config', status: 'pass', message: `plugscout wired in ${geminiStatus.configPath}` }
86
+ : { name: 'Gemini MCP config', status: 'warn', message: 'plugscout not in Gemini MCP config', suggestion: 'Run: plugscout client setup --client gemini' });
87
+ }
88
+ catch {
89
+ checks.push({ name: 'Gemini MCP config', status: 'warn', message: 'Could not read Gemini MCP config', suggestion: 'Run: plugscout client setup --client gemini' });
90
+ }
61
91
  return checks;
62
92
  }
63
93
  function checkSkillsRuntime() {
@@ -62,6 +62,7 @@ const COMMAND_ALIASES = {
62
62
  setup: 'setup',
63
63
  help: 'help',
64
64
  mcp: 'mcp',
65
+ client: 'client',
65
66
  };
66
67
  export async function runCli(argv) {
67
68
  const noUpdateCheck = hasFlag(argv, '--no-update-check');
@@ -136,6 +137,9 @@ export async function runCli(argv) {
136
137
  case 'mcp':
137
138
  await handleMcp(rest);
138
139
  return; // intentional: MCP server is long-lived; update banner would corrupt JSON-RPC stream
140
+ case 'client':
141
+ await handleClient(rest);
142
+ break;
139
143
  case 'help':
140
144
  printHelp();
141
145
  break;
@@ -166,7 +170,7 @@ async function handleAbout() {
166
170
  if (pkg.author) {
167
171
  console.log(`Author: ${pkg.author}`);
168
172
  }
169
- console.log('Scope: Claude plugins, Claude connectors, Copilot extensions, Skills, MCP servers');
173
+ console.log('Scope: Claude plugins, Claude connectors, Copilot extensions, Cursor extensions, Gemini extensions, Skills, MCP servers');
170
174
  console.log('Ranking: trust-first (fit + trust - risk penalties + freshness bonus)');
171
175
  console.log('Meaning: top/recommend output is repo-aware guidance, not a global popularity leaderboard.');
172
176
  console.log('Install discipline: review each suggestion, check provenance and risk, and do not install blindly from rank alone.');
@@ -190,7 +194,7 @@ async function handleStatus(args) {
190
194
  });
191
195
  console.log('Catalog Status');
192
196
  console.log(`Items: ${items.length}`);
193
- console.log(`Kinds: skill=${kindCounts.get('skill') ?? 0}, mcp=${kindCounts.get('mcp') ?? 0}, claude-plugin=${kindCounts.get('claude-plugin') ?? 0}, claude-connector=${kindCounts.get('claude-connector') ?? 0}, copilot-extension=${kindCounts.get('copilot-extension') ?? 0}`);
197
+ console.log(`Kinds: skill=${kindCounts.get('skill') ?? 0}, mcp=${kindCounts.get('mcp') ?? 0}, claude-plugin=${kindCounts.get('claude-plugin') ?? 0}, claude-connector=${kindCounts.get('claude-connector') ?? 0}, copilot-extension=${kindCounts.get('copilot-extension') ?? 0}, cursor-extension=${kindCounts.get('cursor-extension') ?? 0}, gemini-extension=${kindCounts.get('gemini-extension') ?? 0}`);
194
198
  console.log(`Providers: ${Array.from(providerCounts.entries())
195
199
  .sort((a, b) => a[0].localeCompare(b[0]))
196
200
  .map(([name, count]) => `${name}=${count}`)
@@ -228,7 +232,7 @@ async function handleInit(args) {
228
232
  const root = path.resolve(project);
229
233
  const [items, policy] = await Promise.all([loadCatalogItems(), loadSecurityPolicy()]);
230
234
  const providers = Array.from(new Set(items.map((item) => item.provider))).sort((a, b) => a.localeCompare(b));
231
- const defaultKinds = ['skill', 'mcp', 'claude-plugin', 'claude-connector', 'copilot-extension'];
235
+ const defaultKinds = ['skill', 'mcp', 'claude-plugin', 'claude-connector', 'copilot-extension', 'cursor-extension', 'gemini-extension'];
232
236
  const defaults = {
233
237
  defaultKinds,
234
238
  defaultProviders: providers,
@@ -298,7 +302,7 @@ async function handleSetup(args) {
298
302
  console.log('Step 2/3: Initializing local config...');
299
303
  const [items, policy] = await Promise.all([loadCatalogItems(), loadSecurityPolicy()]);
300
304
  const providers = Array.from(new Set(items.map((item) => item.provider))).sort((a, b) => a.localeCompare(b));
301
- const defaultKinds = ['skill', 'mcp', 'claude-plugin', 'claude-connector', 'copilot-extension'];
305
+ const defaultKinds = ['skill', 'mcp', 'claude-plugin', 'claude-connector', 'copilot-extension', 'cursor-extension', 'gemini-extension'];
302
306
  const defaults = {
303
307
  defaultKinds,
304
308
  defaultProviders: providers,
@@ -853,6 +857,33 @@ async function handleQuarantine(args) {
853
857
  const result = await applyQuarantineFromReport(report);
854
858
  console.log(renderJson(result));
855
859
  }
860
+ async function handleClient(args) {
861
+ const subcommand = args[0];
862
+ if (subcommand !== 'setup') {
863
+ throw new Error('Usage: client setup --client cursor|gemini [--scope user|project] [--force]');
864
+ }
865
+ const clientFlag = readFlag(args, '--client');
866
+ if (clientFlag !== 'cursor' && clientFlag !== 'gemini') {
867
+ throw new Error('Usage: client setup --client cursor|gemini');
868
+ }
869
+ const scopeFlag = readFlag(args, '--scope') ?? 'user';
870
+ if (scopeFlag !== 'user' && scopeFlag !== 'project') {
871
+ throw new Error('--scope must be user or project');
872
+ }
873
+ if (clientFlag === 'gemini' && scopeFlag === 'project') {
874
+ logger.warn('Gemini CLI only supports user scope; falling back to user scope.');
875
+ }
876
+ const force = hasFlag(args, '--force');
877
+ const { writeClientMcpConfig } = await import('./client-setup.js');
878
+ const result = await writeClientMcpConfig({ client: clientFlag, scope: scopeFlag, force });
879
+ if (result.status === 'already-configured') {
880
+ console.log(`plugscout already configured in ${result.configPath}`);
881
+ }
882
+ else {
883
+ console.log(`plugscout MCP config written: ${result.configPath}`);
884
+ printHint(`Restart ${clientFlag === 'cursor' ? 'Cursor IDE' : 'Gemini CLI'} for the change to take effect.`);
885
+ }
886
+ }
856
887
  async function handleUpgrade(args) {
857
888
  const subcommand = args[0] ?? 'check';
858
889
  if (subcommand !== 'check') {
@@ -980,7 +1011,7 @@ function printHelp() {
980
1011
  console.log(' init [--project .]');
981
1012
  console.log(' doctor [--project .] [--install-deps]');
982
1013
  console.log(' status [--verbose]');
983
- console.log(' sync [--kind skill,mcp,claude-plugin,claude-connector,copilot-extension] [--dry-run]');
1014
+ console.log(' sync [--kind skill,mcp,claude-plugin,claude-connector,copilot-extension,cursor-extension,gemini-extension] [--dry-run]');
984
1015
  console.log('');
985
1016
  console.log('Explore');
986
1017
  console.log(' list [--kind ...] [--provider ...] [--risk-tier low|medium|high|critical] [--blocked true|false] [--search q] [--limit n] [--sort name|risk|trust] [--format json|table] [--readable] [--details]');
@@ -1005,6 +1036,7 @@ function printHelp() {
1005
1036
  console.log('Other');
1006
1037
  console.log(' about');
1007
1038
  console.log(' web [--out .plugscout/report.html] [--kind ...] [--limit n] [--open]');
1039
+ console.log(' client setup --client cursor|gemini [--scope user|project] [--force]');
1008
1040
  console.log(' upgrade check');
1009
1041
  console.log(' help');
1010
1042
  console.log('');
@@ -1014,11 +1046,18 @@ function printHelp() {
1014
1046
  console.log(' plugins -> claude-plugin');
1015
1047
  console.log(' connectors -> claude-connector');
1016
1048
  console.log(' extensions, copilot -> copilot-extension');
1049
+ console.log(' cursor, cursor-extensions -> cursor-extension');
1050
+ console.log(' gemini, gemini-extensions -> gemini-extension');
1017
1051
  console.log('');
1018
1052
  console.log('Examples');
1019
1053
  console.log(' plugscout recommend --project . --only-safe --limit 10');
1054
+ console.log(' plugscout list --kind cursor --limit 15');
1055
+ console.log(' plugscout list --kind gemini --limit 11');
1020
1056
  console.log(' plugscout list --kind connectors --limit 10');
1021
1057
  console.log(' plugscout show --id claude-connector:asana');
1058
+ console.log(' plugscout client setup --client cursor');
1059
+ console.log(' plugscout client setup --client gemini');
1060
+ console.log(' plugscout sync --kind cursor-extension,gemini-extension');
1022
1061
  console.log('');
1023
1062
  console.log('Global options');
1024
1063
  console.log(' --no-update-check');
@@ -1032,7 +1071,7 @@ async function loadLocalCliConfig(projectRoot) {
1032
1071
  return null;
1033
1072
  }
1034
1073
  return {
1035
- defaultKinds: Array.isArray(parsed.defaultKinds) ? parsed.defaultKinds : ['skill', 'mcp', 'claude-plugin', 'claude-connector', 'copilot-extension'],
1074
+ defaultKinds: Array.isArray(parsed.defaultKinds) ? parsed.defaultKinds : ['skill', 'mcp', 'claude-plugin', 'claude-connector', 'copilot-extension', 'cursor-extension', 'gemini-extension'],
1036
1075
  defaultProviders: Array.isArray(parsed.defaultProviders) ? parsed.defaultProviders : [],
1037
1076
  riskPosture: parsed.riskPosture,
1038
1077
  outputStyle: parsed.outputStyle === 'json' ? 'json' : 'rich-table',
@@ -18,7 +18,7 @@ export function createMcpServer(version = '0.0.0') {
18
18
  type: 'object',
19
19
  properties: {
20
20
  query: { type: 'string', description: 'Search term' },
21
- kind: { type: 'string', description: 'Filter by kind: skill, mcp, claude-plugin, claude-connector, copilot-extension' },
21
+ kind: { type: 'string', description: 'Filter by kind: skill, mcp, claude-plugin, claude-connector, copilot-extension, cursor-extension, gemini-extension' },
22
22
  provider: { type: 'string', description: 'Filter by provider' },
23
23
  limit: { type: 'number', description: 'Max results (default: 20)' },
24
24
  },
@@ -24,7 +24,13 @@ const KIND_ALIASES = {
24
24
  'copilot extensions': 'copilot-extension',
25
25
  extension: 'copilot-extension',
26
26
  extensions: 'copilot-extension',
27
- copilot: 'copilot-extension'
27
+ copilot: 'copilot-extension',
28
+ 'cursor-extension': 'cursor-extension',
29
+ 'cursor-extensions': 'cursor-extension',
30
+ cursor: 'cursor-extension',
31
+ 'gemini-extension': 'gemini-extension',
32
+ 'gemini-extensions': 'gemini-extension',
33
+ gemini: 'gemini-extension'
28
34
  };
29
35
  export function readFlag(args, flag) {
30
36
  const index = args.indexOf(flag);
@@ -57,7 +63,7 @@ export function normalizeKind(raw) {
57
63
  return CatalogKindSchema.parse(normalized);
58
64
  }
59
65
  catch {
60
- throw new Error(`Invalid --kind value: ${raw}. Expected one of: skill, mcp, claude-plugin, claude-connector, copilot-extension. Aliases also supported: skills, mcps, plugins, connectors, extensions.`);
66
+ throw new Error(`Invalid --kind value: ${raw}. Expected one of: skill, mcp, claude-plugin, claude-connector, copilot-extension, cursor-extension, gemini-extension. Aliases also supported: skills, mcps, plugins, connectors, extensions, cursor, gemini.`);
61
67
  }
62
68
  }
63
69
  export function readCsvList(args, flag) {
@@ -205,13 +205,15 @@ function renderHtml(rows, stats, policy) {
205
205
  <body>
206
206
  <div class="wrap">
207
207
  <h1>PlugScout Web Report</h1>
208
- <p class="sub">Claude plugins · Claude connectors · Copilot extensions · Skills · MCP servers</p>
208
+ <p class="sub">Claude plugins · Claude connectors · Copilot extensions · Cursor extensions · Gemini extensions · Skills · MCP servers</p>
209
209
 
210
210
  <div class="stat-cards">
211
211
  <div class="stat-card"><div class="k">Total</div><div class="v">${stats.totalItems}</div></div>
212
212
  <div class="stat-card"><div class="k">Plugins</div><div class="v">${kindCounts['claude-plugin']}</div></div>
213
213
  <div class="stat-card"><div class="k">Connectors</div><div class="v">${kindCounts['claude-connector']}</div></div>
214
214
  <div class="stat-card"><div class="k">Copilot Ext</div><div class="v">${kindCounts['copilot-extension']}</div></div>
215
+ <div class="stat-card"><div class="k">Cursor Ext</div><div class="v">${kindCounts['cursor-extension']}</div></div>
216
+ <div class="stat-card"><div class="k">Gemini Ext</div><div class="v">${kindCounts['gemini-extension']}</div></div>
215
217
  <div class="stat-card"><div class="k">Skills</div><div class="v">${kindCounts.skill}</div></div>
216
218
  <div class="stat-card"><div class="k">MCP Servers</div><div class="v">${kindCounts.mcp}</div></div>
217
219
  <div class="stat-card"><div class="k">Whitelist / Quarantine</div><div class="v">${stats.whitelist} / ${stats.quarantined}</div></div>
@@ -232,6 +234,8 @@ function renderHtml(rows, stats, policy) {
232
234
  <option value="claude-plugin">Claude plugin</option>
233
235
  <option value="claude-connector">Claude connector</option>
234
236
  <option value="copilot-extension">Copilot extension</option>
237
+ <option value="cursor-extension">Cursor extension</option>
238
+ <option value="gemini-extension">Gemini extension</option>
235
239
  <option value="skill">Skill</option>
236
240
  <option value="mcp">MCP server</option>
237
241
  </select>
@@ -440,6 +444,8 @@ function countByKind(items) {
440
444
  mcp: 0,
441
445
  'claude-plugin': 0,
442
446
  'claude-connector': 0,
443
- 'copilot-extension': 0
447
+ 'copilot-extension': 0,
448
+ 'cursor-extension': 0,
449
+ 'gemini-extension': 0
444
450
  });
445
451
  }
@@ -3,7 +3,7 @@ const isoDate = z
3
3
  .string()
4
4
  .regex(/^(19|20|21)\d{2}-[01]\d-[0-3]\d$/, 'Expected ISO date (YYYY-MM-DD)');
5
5
  export const RiskTierSchema = z.enum(['low', 'medium', 'high', 'critical']);
6
- export const CatalogKindSchema = z.enum(['skill', 'mcp', 'claude-plugin', 'claude-connector', 'copilot-extension']);
6
+ export const CatalogKindSchema = z.enum(['skill', 'mcp', 'claude-plugin', 'claude-connector', 'copilot-extension', 'cursor-extension', 'gemini-extension']);
7
7
  const SecuritySignalsSchema = z
8
8
  .object({
9
9
  knownVulnerabilities: z.number().int().min(0).default(0),
@@ -137,7 +137,9 @@ export const RegistrySchema = z.object({
137
137
  'copilot-extensions-v0.1',
138
138
  'copilot-plugin-marketplace-v1',
139
139
  'claude-connectors-scrape-v1',
140
- 'awesome-claude-code-v1'
140
+ 'awesome-claude-code-v1',
141
+ 'cursor-extensions-v1',
142
+ 'gemini-extensions-v1'
141
143
  ])
142
144
  .default('direct'),
143
145
  enabled: z.boolean().default(true),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shnitzel/plugscout",
3
- "version": "0.3.9",
3
+ "version": "0.3.10",
4
4
  "description": "Claude plugins + Claude connectors + Copilot extensions + Skills + MCP security intelligence framework",
5
5
  "private": false,
6
6
  "type": "module",