/*** Plugin Version Calculation Module** Handles version calculation for plugins from various sources.* Versions are used for versioned cache paths and update detection.** Version sources (in order of preference):* 1. Explicit version from plugin.json* 2. Git commit SHA (for git/github sources)* 3. Fallback timestamp for local sources*/import { createHash } from 'crypto'import { logForDebugging } from '../debug.js'import { getHeadForDir } from '../git/gitFilesystem.js'import type { PluginManifest, PluginSource } from './schemas.js'/*** Calculate the version for a plugin based on its source.** Version sources (in order of priority):* 1. plugin.json version field (highest priority)* 2. Provided version (typically from marketplace entry)* 3. Git commit SHA from install path* 4. 'unknown' as last resort** @param pluginId - Plugin identifier (e.g., "plugin@marketplace")* @param source - Plugin source configuration (used for git-subdir path hashing)* @param manifest - Optional plugin manifest with version field* @param installPath - Optional path to installed plugin (for git SHA extraction)* @param providedVersion - Optional version from marketplace entry or caller* @param gitCommitSha - Optional pre-resolved git SHA (for sources like* git-subdir where the clone is discarded and the install path has no .git)* @returns Version string (semver, short SHA, or 'unknown')*/export async function calculatePluginVersion(pluginId: string,source: PluginSource,manifest?: PluginManifest,installPath?: string,providedVersion?: string,gitCommitSha?: string,): Promise<string> {// 1. Use explicit version from plugin.json if availableif (manifest?.version) {logForDebugging(`Using manifest version for ${pluginId}: ${manifest.version}`,)return manifest.version}// 2. Use provided version (typically from marketplace entry)if (providedVersion) {logForDebugging(`Using provided version for ${pluginId}: ${providedVersion}`,)return providedVersion}// 3. Use pre-resolved git SHA if caller captured it before discarding the cloneif (gitCommitSha) {const shortSha = gitCommitSha.substring(0, 12)if (typeof source === 'object' && source.source === 'git-subdir') {// Encode the subdir path in the version so cache keys differ when// marketplace.json's `path` changes but the monorepo SHA doesn't.// Without this, two plugins at different subdirs of the same commit// collide at cache/<m>/<p>/<sha>/ and serve each other's trees.//// Normalization MUST match the squashfs cron byte-for-byte:// 1. backslash → forward slash// 2. strip one leading `./`// 3. strip all trailing `/`// 4. UTF-8 sha256, first 8 hex chars// See api/.../plugins_official_squashfs/job.py _validate_subdir().const normPath = source.path.replace(/\\/g, '/').replace(/^\.\//, '').replace(/\/+$/, '')const pathHash = createHash('sha256').update(normPath).digest('hex').substring(0, 8)const v = `${shortSha}-${pathHash}`logForDebugging(`Using git-subdir SHA+path version for ${pluginId}: ${v} (path=${normPath})`,)return v}logForDebugging(`Using pre-resolved git SHA for ${pluginId}: ${shortSha}`)return shortSha}// 4. Try to get git SHA from install pathif (installPath) {const sha = await getGitCommitSha(installPath)if (sha) {const shortSha = sha.substring(0, 12)logForDebugging(`Using git SHA for ${pluginId}: ${shortSha}`)return shortSha}}// 5. Return 'unknown' as last resortlogForDebugging(`No version found for ${pluginId}, using 'unknown'`)return 'unknown'}/*** Get the git commit SHA for a directory.** @param dirPath - Path to directory (should be a git repository)* @returns Full commit SHA or null if not a git repo*/export function getGitCommitSha(dirPath: string): Promise<string | null> {return getHeadForDir(dirPath)}/*** Extract version from a versioned cache path.** Given a path like `~/.claude/plugins/cache/marketplace/plugin/1.0.0`,* extracts and returns `1.0.0`.** @param installPath - Full path to plugin installation* @returns Version string from path, or null if not a versioned path*/export function getVersionFromPath(installPath: string): string | null {// Versioned paths have format: .../plugins/cache/marketplace/plugin/version/const parts = installPath.split('/').filter(Boolean)// Find 'cache' index to determine depthconst cacheIndex = parts.findIndex((part, i) => part === 'cache' && parts[i - 1] === 'plugins',)if (cacheIndex === -1) {return null}// Versioned path has 3 components after 'cache': marketplace/plugin/versionconst componentsAfterCache = parts.slice(cacheIndex + 1)if (componentsAfterCache.length >= 3) {return componentsAfterCache[2] || null}return null}/*** Check if a path is a versioned plugin path.** @param path - Path to check* @returns True if path follows versioned structure*/export function isVersionedPath(path: string): boolean {return getVersionFromPath(path) !== null}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。