UNPKG

@lenne.tech/cli

Version:

lenne.Tech CLI: lt

160 lines (159 loc) 7.3 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DEFAULT_EXTERNAL_PLUGINS = exports.MARKETPLACES = void 0; exports.fetchAvailablePlugins = fetchAvailablePlugins; exports.fetchPluginsFromMarketplace = fetchPluginsFromMarketplace; exports.printAvailablePlugins = printAvailablePlugins; /** * Plugin marketplace utilities * Handles fetching and managing plugins from GitHub-based marketplaces */ const json_utils_1 = require("./json-utils"); /** * Available marketplaces for plugin discovery */ exports.MARKETPLACES = [ { apiBase: 'https://api.github.com/repos/lenneTech/claude-code/contents', name: 'lenne-tech', rawBase: 'https://raw.githubusercontent.com/lenneTech/claude-code/main', repo: 'lenneTech/claude-code', }, { apiBase: 'https://api.github.com/repos/anthropics/claude-plugins-official/contents', name: 'claude-plugins-official', rawBase: 'https://raw.githubusercontent.com/anthropics/claude-plugins-official/main', repo: 'anthropics/claude-plugins-official', }, ]; /** * Default plugins to install when no specific plugins are requested * These are installed in addition to all plugins from the primary marketplace (lenne-tech) */ exports.DEFAULT_EXTERNAL_PLUGINS = [ { marketplaceName: 'claude-plugins-official', pluginName: 'typescript-lsp' }, ]; /** * Fetch available plugins from all configured marketplaces * @param spin - Spinner factory function from toolbox * @returns Array of plugin configurations * @throws Error if no plugins are found */ function fetchAvailablePlugins(spin) { return __awaiter(this, void 0, void 0, function* () { const spinner = spin('Fetching available plugins from marketplaces'); try { // Fetch plugins from all marketplaces in parallel const results = yield Promise.all(exports.MARKETPLACES.map((marketplace) => fetchPluginsFromMarketplace(marketplace))); // Flatten results const plugins = results.flat(); if (plugins.length === 0) { spinner.fail('No plugins found in any marketplace'); throw new Error('No plugins found'); } // Group by marketplace for display const byMarketplace = exports.MARKETPLACES.map((m) => ({ count: plugins.filter((p) => p.marketplaceName === m.name).length, name: m.name, })).filter((m) => m.count > 0); const summary = byMarketplace.map((m) => `${m.name}: ${m.count}`).join(', '); spinner.succeed(`Found ${plugins.length} plugins (${summary})`); return plugins; } catch (err) { spinner.fail('Failed to fetch plugins from marketplaces'); throw err; } }); } /** * Fetch available plugins from a single marketplace * First tries central marketplace.json, then falls back to directory scan * @param marketplace - Marketplace configuration * @returns Array of plugin configurations */ function fetchPluginsFromMarketplace(marketplace) { return __awaiter(this, void 0, void 0, function* () { const plugins = []; try { // First try to read central marketplace.json (used by official marketplace) const marketplaceJsonUrl = `${marketplace.rawBase}/.claude-plugin/marketplace.json`; const marketplaceJsonResponse = yield fetch(marketplaceJsonUrl); if (marketplaceJsonResponse.ok) { const text = yield marketplaceJsonResponse.text(); const marketplaceManifest = (0, json_utils_1.safeJsonParse)(text); if ((marketplaceManifest === null || marketplaceManifest === void 0 ? void 0 : marketplaceManifest.plugins) && marketplaceManifest.plugins.length > 0) { for (const plugin of marketplaceManifest.plugins) { plugins.push({ description: plugin.description || '', marketplaceName: marketplace.name, marketplaceRepo: marketplace.repo, pluginName: plugin.name, }); } return plugins; } } // Fallback: Get list of plugin directories and read individual plugin.json files const dirResponse = yield fetch(`${marketplace.apiBase}/plugins`); if (!dirResponse.ok) { return plugins; } const text = yield dirResponse.text(); const directories = (0, json_utils_1.safeJsonParse)(text); if (!directories) { return plugins; } const pluginDirs = directories.filter((d) => d.type === 'dir'); // Fetch plugin.json for each plugin in parallel const manifestPromises = pluginDirs.map((dir) => __awaiter(this, void 0, void 0, function* () { try { const manifestUrl = `${marketplace.rawBase}/plugins/${dir.name}/.claude-plugin/plugin.json`; const manifestResponse = yield fetch(manifestUrl); if (manifestResponse.ok) { const manifestText = yield manifestResponse.text(); const manifest = (0, json_utils_1.safeJsonParse)(manifestText); if (manifest) { return { description: manifest.description, marketplaceName: marketplace.name, marketplaceRepo: marketplace.repo, pluginName: manifest.name, }; } } } catch (_a) { // Skip plugins without valid manifest } return null; })); const results = yield Promise.all(manifestPromises); plugins.push(...results.filter((p) => p !== null)); } catch (_a) { // Marketplace fetch failed, return empty array } return plugins; }); } /** * Print available plugins list * @param plugins - Array of plugin configurations * @param info - Info print function from toolbox */ function printAvailablePlugins(plugins, info) { info('Available plugins:'); for (const plugin of plugins) { info(` ${plugin.pluginName} - ${plugin.description}`); } }