Skip to content

Commit 22ae922

Browse files
authored
feat(marketplace): add stripe plugin to marketplace (#102)
Add Stripe development plugin entry pointing to the official stripe/ai repository's Claude provider plugin at providers/claude/plugin.
1 parent 09c73db commit 22ae922

7 files changed

Lines changed: 79 additions & 7 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,20 @@
405405
"tags": ["mcp", "payment"],
406406
"source": "./plugins/tosspayments"
407407
},
408+
{
409+
"name": "stripe",
410+
"description": "Stripe development plugin for Claude",
411+
"category": "development",
412+
"keywords": ["stripe", "payments", "webhooks", "api", "security"],
413+
"tags": ["mcp", "payments"],
414+
"source": {
415+
"source": "git-subdir",
416+
"url": "stripe/ai",
417+
"path": "providers/claude/plugin",
418+
"ref": "main"
419+
},
420+
"homepage": "https://github.com/stripe/ai/tree/main/providers/claude/plugin"
421+
},
408422
{
409423
"name": "vercel",
410424
"description": "Vercel deployment platform integration. Manage deployments, check build status, access logs, configure domains, and control your frontend infrastructure directly from Claude Code.",

apps/web/app/components/PluginCard.vue

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
11
<script setup lang="ts">
22
import { useTimeoutFn } from '@vueuse/core'
33
4-
interface PluginSource {
4+
interface PluginSourceGitHub {
55
source: 'github'
66
repo: string
77
}
88
9+
interface PluginSourceGitSubdir {
10+
source: 'git-subdir'
11+
url: string
12+
path: string
13+
ref?: string
14+
sha?: string
15+
}
16+
17+
type PluginSource = PluginSourceGitHub | PluginSourceGitSubdir
18+
919
interface Plugin {
1020
name: string
1121
description: string
@@ -50,6 +60,11 @@ async function fetchPluginMetadata() {
5060
return
5161
}
5262
63+
// Only GitHub source plugins support metadata fetch
64+
if (props.plugin.source.source !== 'github') {
65+
return
66+
}
67+
5368
// GitHub plugin - fetch from GitHub
5469
loading.value = true
5570
try {
@@ -92,7 +107,7 @@ async function fetchPluginMetadata() {
92107
// Network-level errors (connection failed, CORS, etc.)
93108
console.error('Network error fetching plugin metadata:', {
94109
plugin: props.plugin.name,
95-
repo: props.plugin.source.repo,
110+
repo: props.plugin.source.source === 'github' ? props.plugin.source.repo : props.plugin.source.url,
96111
error: err instanceof Error ? err.message : String(err),
97112
})
98113
}
@@ -169,6 +184,17 @@ const githubSourceUrl = computed(() => {
169184
170185
return url
171186
}
187+
// git-subdir plugin
188+
if (props.plugin.source.source === 'git-subdir') {
189+
const url = props.plugin.source.url
190+
const path = props.plugin.source.path
191+
const ref = props.plugin.source.ref || 'main'
192+
// Handle both full URLs and owner/repo shorthand
193+
if (url.startsWith('http')) {
194+
return `${url.replace(/\.git$/, '')}/tree/${ref}/${path}`
195+
}
196+
return `https://github.com/${url}/tree/${ref}/${path}`
197+
}
172198
// GitHub plugin
173199
return `https://github.com/${props.plugin.source.repo}`
174200
})
@@ -306,7 +332,7 @@ watch(() => props.autoOpenModal, (shouldOpen) => {
306332
</div>
307333
<div class="flex items-center gap-2 text-xs text-muted">
308334
<UIcon name="i-heroicons-code-bracket" class="shrink-0" />
309-
<span class="truncate">{{ typeof plugin.source === 'string' ? plugin.source : plugin.source.repo }}</span>
335+
<span class="truncate">{{ typeof plugin.source === 'string' ? plugin.source : plugin.source.source === 'github' ? plugin.source.repo : plugin.source.url }}</span>
310336
</div>
311337
</div>
312338
<div class="shrink-0">

apps/web/app/pages/index.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ function pluginMatchesSearch(plugin: Plugin, query: string): boolean {
7575
const searchFields = [
7676
plugin.name,
7777
plugin.description,
78-
typeof plugin.source === 'string' ? plugin.source : plugin.source.repo,
78+
typeof plugin.source === 'string' ? plugin.source : 'repo' in plugin.source ? plugin.source.repo : plugin.source.url,
7979
]
8080
8181
return searchFields.some(field =>

apps/web/app/types/marketplace.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,21 @@ export interface MarketplaceSource {
1111
priority: number
1212
}
1313

14-
export interface PluginSource {
14+
export interface PluginSourceGitHub {
1515
source: 'github'
1616
repo: string
1717
}
1818

19+
export interface PluginSourceGitSubdir {
20+
source: 'git-subdir'
21+
url: string
22+
path: string
23+
ref?: string
24+
sha?: string
25+
}
26+
27+
export type PluginSource = PluginSourceGitHub | PluginSourceGitSubdir
28+
1929
export interface Plugin {
2030
name: string
2131
description?: string

apps/web/content.config.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ export default defineContentConfig({
3838
source: z.literal('github'),
3939
repo: z.string(),
4040
}),
41+
z.object({
42+
source: z.literal('git-subdir'),
43+
url: z.string(),
44+
path: z.string(),
45+
ref: z.string().optional(),
46+
sha: z.string().optional(),
47+
}),
4148
z.string(),
4249
]),
4350
}),

apps/web/server/utils/github.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,23 @@ export async function fetchGitHubStars(owner: string, repo: string): Promise<num
7878
* @param source - Plugin source (GitHub URL or repo string)
7979
* @returns Star count, or null if fetch fails
8080
*/
81-
export async function fetchPluginStars(source: string | { source: string, repo: string }): Promise<number | null> {
82-
// Handle object format with repo property
81+
export async function fetchPluginStars(source: string | { source: string, repo?: string, url?: string }): Promise<number | null> {
82+
// Handle object format with repo property (github source)
8383
if (typeof source === 'object' && source.repo) {
8484
const parsed = parseGitHubRepo(source.repo)
8585
if (!parsed)
8686
return null
8787
return fetchGitHubStars(parsed.owner, parsed.repo)
8888
}
8989

90+
// Handle object format with url property (git-subdir source)
91+
if (typeof source === 'object' && source.url) {
92+
const parsed = parseGitHubRepo(source.url)
93+
if (!parsed)
94+
return null
95+
return fetchGitHubStars(parsed.owner, parsed.repo)
96+
}
97+
9098
// Handle string format
9199
if (typeof source === 'string') {
92100
const parsed = parseGitHubRepo(source)

apps/web/server/utils/marketplace-schema.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ export const pluginSourceSchema = z.union([
1010
source: z.literal('github'),
1111
repo: z.string(),
1212
}),
13+
z.object({
14+
source: z.literal('git-subdir'),
15+
url: z.string(),
16+
path: z.string(),
17+
ref: z.string().optional(),
18+
sha: z.string().optional(),
19+
}),
1320
z.string(),
1421
])
1522

0 commit comments

Comments
 (0)