Files
claude-code/src/commands/plugin/pluginDetailsHelpers.tsx
T
2026-04-06 23:56:45 +08:00

123 lines
3.1 KiB
TypeScript

/**
* Shared helper functions and types for plugin details views
*
* Used by both DiscoverPlugins and BrowseMarketplace components.
*/
import * as React from 'react'
import { ConfigurableShortcutHint } from '../../components/ConfigurableShortcutHint.js'
import { Box, Byline, Text } from '@anthropic/ink'
import type { PluginMarketplaceEntry } from '../../utils/plugins/schemas.js'
/**
* Represents a plugin available for installation from a marketplace
*/
export type InstallablePlugin = {
entry: PluginMarketplaceEntry
marketplaceName: string
pluginId: string
isInstalled: boolean
}
/**
* Menu option for plugin details view
*/
export type PluginDetailsMenuOption = {
label: string
action: string
}
/**
* Extract GitHub repo info from a plugin's source
*/
export function extractGitHubRepo(plugin: InstallablePlugin): string | null {
const isGitHub =
plugin.entry.source &&
typeof plugin.entry.source === 'object' &&
'source' in plugin.entry.source &&
plugin.entry.source.source === 'github'
if (
isGitHub &&
typeof plugin.entry.source === 'object' &&
'repo' in plugin.entry.source
) {
return plugin.entry.source.repo
}
return null
}
/**
* Build menu options for plugin details view with scoped installation options
*/
export function buildPluginDetailsMenuOptions(
hasHomepage: string | undefined,
githubRepo: string | null,
): PluginDetailsMenuOption[] {
const options: PluginDetailsMenuOption[] = [
{ label: 'Install for you (user scope)', action: 'install-user' },
{
label: 'Install for all collaborators on this repository (project scope)',
action: 'install-project',
},
{
label: 'Install for you, in this repo only (local scope)',
action: 'install-local',
},
]
if (hasHomepage) {
options.push({ label: 'Open homepage', action: 'homepage' })
}
if (githubRepo) {
options.push({ label: 'View on GitHub', action: 'github' })
}
options.push({ label: 'Back to plugin list', action: 'back' })
return options
}
/**
* Key hint component for plugin selection screens
*/
export function PluginSelectionKeyHint({
hasSelection,
}: {
hasSelection: boolean
}): React.ReactNode {
return (
<Box marginTop={1}>
<Text dimColor italic>
<Byline>
{hasSelection && (
<ConfigurableShortcutHint
action="plugin:install"
context="Plugin"
fallback="i"
description="install"
bold
/>
)}
<ConfigurableShortcutHint
action="plugin:toggle"
context="Plugin"
fallback="Space"
description="toggle"
/>
<ConfigurableShortcutHint
action="select:accept"
context="Select"
fallback="Enter"
description="details"
/>
<ConfigurableShortcutHint
action="confirm:no"
context="Confirmation"
fallback="Esc"
description="back"
/>
</Byline>
</Text>
</Box>
)
}