/
aqa
/
claude-code
Обзор
Документация
Войти
/
aqa
/
claude-code
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
utils/plugins/pluginIdentifier.ts
123 строки
4 KB
kuberwastaken
new initial commit (history rewritten)
01 апр 2026, 14:57
01 апр 2026, 14:57
c1996f2
Код
Авторство
О чём код?
import type { EditableSettingSource, SettingSource, } from '../settings/constants.js' import { ALLOWED_OFFICIAL_MARKETPLACE_NAMES, type PluginScope, } from './schemas.js' /** * Extended scope type that includes 'flag' for session-only plugins. * 'flag' scope is NOT persisted to installed_plugins.json. */ export type ExtendedPluginScope = PluginScope | 'flag' /** * Scopes that are persisted to installed_plugins.json. * Excludes 'flag' which is session-only. */ export type PersistablePluginScope = Exclude<ExtendedPluginScope, 'flag'> /** * Map from SettingSource to plugin scope. * Note: flagSettings maps to 'flag' which is session-only and not persisted. */ export const SETTING_SOURCE_TO_SCOPE = { policySettings: 'managed', userSettings: 'user', projectSettings: 'project', localSettings: 'local', flagSettings: 'flag', } as const satisfies Record<SettingSource, ExtendedPluginScope> /** * Parsed plugin identifier with name and optional marketplace */ export type ParsedPluginIdentifier = { name: string marketplace?: string } /** * Parse a plugin identifier string into name and marketplace components * @param plugin The plugin identifier (name or name@marketplace) * @returns Parsed plugin name and optional marketplace * * Note: Only the first '@' is used as separator. If the input contains multiple '@' symbols * (e.g., "plugin@market@place"), everything after the second '@' is ignored. * This is intentional as marketplace names should not contain '@'. */ export function parsePluginIdentifier(plugin: string): ParsedPluginIdentifier { if (plugin.includes('@')) { const parts = plugin.split('@') return { name: parts[0] || '', marketplace: parts[1] } } return { name: plugin } } /** * Build a plugin ID from name and marketplace * @param name The plugin name * @param marketplace Optional marketplace name * @returns Plugin ID in format "name" or "name@marketplace" */ export function buildPluginId(name: string, marketplace?: string): string { return marketplace ? `${name}@${marketplace}` : name } /** * Check if a marketplace name is an official (Anthropic-controlled) marketplace. * Used for telemetry redaction — official plugin identifiers are safe to log to * general-access additional_metadata; third-party identifiers go only to the * PII-tagged _PROTO_* BQ columns. */ export function isOfficialMarketplaceName( marketplace: string | undefined, ): boolean { return ( marketplace !== undefined && ALLOWED_OFFICIAL_MARKETPLACE_NAMES.has(marketplace.toLowerCase()) ) } /** * Map from installable plugin scope to editable setting source. * This is the inverse of SETTING_SOURCE_TO_SCOPE for editable scopes only. * Note: 'managed' scope cannot be installed to, so it's not included here. */ const SCOPE_TO_EDITABLE_SOURCE: Record< Exclude<PluginScope, 'managed'>, EditableSettingSource > = { user: 'userSettings', project: 'projectSettings', local: 'localSettings', } /** * Convert a plugin scope to its corresponding editable setting source * @param scope The plugin installation scope * @returns The corresponding setting source for reading/writing settings * @throws Error if scope is 'managed' (cannot install plugins to managed scope) */ export function scopeToSettingSource( scope: PluginScope, ): EditableSettingSource { if (scope === 'managed') { throw new Error('Cannot install plugins to managed scope') } return SCOPE_TO_EDITABLE_SOURCE[scope] } /** * Convert an editable setting source to its corresponding plugin scope. * Derived from SETTING_SOURCE_TO_SCOPE to maintain a single source of truth. * @param source The setting source * @returns The corresponding plugin scope */ export function settingSourceToScope( source: EditableSettingSource, ): Exclude<PluginScope, 'managed'> { return SETTING_SOURCE_TO_SCOPE[source] as Exclude<PluginScope, 'managed'> }