@lenne.tech/cli 1.6.2 → 1.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CLAUDE_MARKETPLACES_DIR = void 0;
4
+ exports.checkCommandExists = checkCommandExists;
5
+ exports.checkMarketplaceExists = checkMarketplaceExists;
6
+ exports.findClaudeCli = findClaudeCli;
7
+ exports.runClaudeCommand = runClaudeCommand;
8
+ /**
9
+ * Claude CLI utilities
10
+ * Handles detection and execution of Claude CLI commands
11
+ */
12
+ const child_process_1 = require("child_process");
13
+ const fs_1 = require("fs");
14
+ const os_1 = require("os");
15
+ const path_1 = require("path");
16
+ /**
17
+ * Path to Claude plugins marketplaces directory
18
+ */
19
+ exports.CLAUDE_MARKETPLACES_DIR = (0, path_1.join)((0, os_1.homedir)(), '.claude', 'plugins', 'marketplaces');
20
+ /**
21
+ * Check if a shell command exists and succeeds
22
+ * @param command - Command to check (e.g., 'which typescript-language-server')
23
+ * @returns true if command exits with code 0
24
+ */
25
+ function checkCommandExists(command) {
26
+ try {
27
+ (0, child_process_1.execSync)(command, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
28
+ return true;
29
+ }
30
+ catch (_a) {
31
+ return false;
32
+ }
33
+ }
34
+ /**
35
+ * Check if a marketplace is already installed
36
+ * @param marketplaceName - Name of the marketplace to check
37
+ * @returns true if marketplace directory exists
38
+ */
39
+ function checkMarketplaceExists(marketplaceName) {
40
+ return (0, fs_1.existsSync)((0, path_1.join)(exports.CLAUDE_MARKETPLACES_DIR, marketplaceName));
41
+ }
42
+ /**
43
+ * Find the Claude CLI executable path
44
+ * Checks common installation locations and falls back to 'which'
45
+ * @returns Path to Claude CLI or null if not found
46
+ */
47
+ function findClaudeCli() {
48
+ const possiblePaths = [
49
+ (0, path_1.join)((0, os_1.homedir)(), '.claude', 'local', 'claude'),
50
+ '/usr/local/bin/claude',
51
+ '/usr/bin/claude',
52
+ ];
53
+ for (const p of possiblePaths) {
54
+ if ((0, fs_1.existsSync)(p)) {
55
+ return p;
56
+ }
57
+ }
58
+ try {
59
+ const result = (0, child_process_1.execSync)('which claude', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
60
+ const path = result.trim();
61
+ if (path && (0, fs_1.existsSync)(path)) {
62
+ return path;
63
+ }
64
+ }
65
+ catch (_a) {
66
+ // Claude CLI not found in PATH
67
+ }
68
+ return null;
69
+ }
70
+ /**
71
+ * Execute a Claude CLI command
72
+ * @param cli - Path to Claude CLI executable
73
+ * @param args - Command arguments as string (e.g., 'plugin install foo')
74
+ * @returns Command result with output and success status
75
+ */
76
+ function runClaudeCommand(cli, args) {
77
+ try {
78
+ const result = (0, child_process_1.spawnSync)(cli, args.split(' '), {
79
+ encoding: 'utf-8',
80
+ shell: true,
81
+ stdio: ['pipe', 'pipe', 'pipe'],
82
+ });
83
+ return {
84
+ output: result.stdout + result.stderr,
85
+ success: result.status === 0,
86
+ };
87
+ }
88
+ catch (err) {
89
+ return {
90
+ output: err.message,
91
+ success: false,
92
+ };
93
+ }
94
+ }
95
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhdWRlLWNsaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvY2xhdWRlLWNsaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUE2QkEsZ0RBT0M7QUFPRCx3REFFQztBQU9ELHNDQXdCQztBQVFELDRDQWlCQztBQXJHRDs7O0dBR0c7QUFDSCxpREFBb0Q7QUFDcEQsMkJBQWdDO0FBQ2hDLDJCQUE2QjtBQUM3QiwrQkFBNEI7QUFFNUI7O0dBRUc7QUFDVSxRQUFBLHVCQUF1QixHQUFHLElBQUEsV0FBSSxFQUFDLElBQUEsWUFBTyxHQUFFLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxjQUFjLENBQUMsQ0FBQztBQVk3Rjs7OztHQUlHO0FBQ0gsU0FBZ0Isa0JBQWtCLENBQUMsT0FBZTtJQUNoRCxJQUFJLENBQUM7UUFDSCxJQUFBLHdCQUFRLEVBQUMsT0FBTyxFQUFFLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUMxRSxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFBQyxXQUFNLENBQUM7UUFDUCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7QUFDSCxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQWdCLHNCQUFzQixDQUFDLGVBQXVCO0lBQzVELE9BQU8sSUFBQSxlQUFVLEVBQUMsSUFBQSxXQUFJLEVBQUMsK0JBQXVCLEVBQUUsZUFBZSxDQUFDLENBQUMsQ0FBQztBQUNwRSxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQWdCLGFBQWE7SUFDM0IsTUFBTSxhQUFhLEdBQUc7UUFDcEIsSUFBQSxXQUFJLEVBQUMsSUFBQSxZQUFPLEdBQUUsRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLFFBQVEsQ0FBQztRQUM3Qyx1QkFBdUI7UUFDdkIsaUJBQWlCO0tBQ2xCLENBQUM7SUFFRixLQUFLLE1BQU0sQ0FBQyxJQUFJLGFBQWEsRUFBRSxDQUFDO1FBQzlCLElBQUksSUFBQSxlQUFVLEVBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUNsQixPQUFPLENBQUMsQ0FBQztRQUNYLENBQUM7SUFDSCxDQUFDO0lBRUQsSUFBSSxDQUFDO1FBQ0gsTUFBTSxNQUFNLEdBQUcsSUFBQSx3QkFBUSxFQUFDLGNBQWMsRUFBRSxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLENBQUMsTUFBTSxFQUFFLE1BQU0sRUFBRSxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDaEcsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQzNCLElBQUksSUFBSSxJQUFJLElBQUEsZUFBVSxFQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDN0IsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO0lBQ0gsQ0FBQztJQUFDLFdBQU0sQ0FBQztRQUNQLCtCQUErQjtJQUNqQyxDQUFDO0lBRUQsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxTQUFnQixnQkFBZ0IsQ0FBQyxHQUFXLEVBQUUsSUFBWTtJQUN4RCxJQUFJLENBQUM7UUFDSCxNQUFNLE1BQU0sR0FBRyxJQUFBLHlCQUFTLEVBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUU7WUFDN0MsUUFBUSxFQUFFLE9BQU87WUFDakIsS0FBSyxFQUFFLElBQUk7WUFDWCxLQUFLLEVBQUUsQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sQ0FBQztTQUNoQyxDQUFDLENBQUM7UUFDSCxPQUFPO1lBQ0wsTUFBTSxFQUFFLE1BQU0sQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDLE1BQU07WUFDckMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQztTQUM3QixDQUFDO0lBQ0osQ0FBQztJQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDYixPQUFPO1lBQ0wsTUFBTSxFQUFHLEdBQWEsQ0FBQyxPQUFPO1lBQzlCLE9BQU8sRUFBRSxLQUFLO1NBQ2YsQ0FBQztJQUNKLENBQUM7QUFDSCxDQUFDIn0=
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ /**
3
+ * JSON utility functions
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.safeJsonParse = safeJsonParse;
7
+ /**
8
+ * Safely parse JSON without throwing
9
+ * @param text - JSON string to parse
10
+ * @returns Parsed object or null if parsing fails
11
+ */
12
+ function safeJsonParse(text) {
13
+ try {
14
+ return JSON.parse(text);
15
+ }
16
+ catch (_a) {
17
+ return null;
18
+ }
19
+ }
20
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoianNvbi11dGlscy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvanNvbi11dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7O0dBRUc7O0FBT0gsc0NBTUM7QUFYRDs7OztHQUlHO0FBQ0gsU0FBZ0IsYUFBYSxDQUFJLElBQVk7SUFDM0MsSUFBSSxDQUFDO1FBQ0gsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBTSxDQUFDO0lBQy9CLENBQUM7SUFBQyxXQUFNLENBQUM7UUFDUCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7QUFDSCxDQUFDIn0=
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.DEFAULT_EXTERNAL_PLUGINS = exports.MARKETPLACES = void 0;
13
+ exports.fetchAvailablePlugins = fetchAvailablePlugins;
14
+ exports.fetchPluginsFromMarketplace = fetchPluginsFromMarketplace;
15
+ exports.printAvailablePlugins = printAvailablePlugins;
16
+ /**
17
+ * Plugin marketplace utilities
18
+ * Handles fetching and managing plugins from GitHub-based marketplaces
19
+ */
20
+ const json_utils_1 = require("./json-utils");
21
+ /**
22
+ * Available marketplaces for plugin discovery
23
+ */
24
+ exports.MARKETPLACES = [
25
+ {
26
+ apiBase: 'https://api.github.com/repos/lenneTech/claude-code/contents',
27
+ name: 'lenne-tech',
28
+ rawBase: 'https://raw.githubusercontent.com/lenneTech/claude-code/main',
29
+ repo: 'lenneTech/claude-code',
30
+ },
31
+ {
32
+ apiBase: 'https://api.github.com/repos/anthropics/claude-plugins-official/contents',
33
+ name: 'claude-plugins-official',
34
+ rawBase: 'https://raw.githubusercontent.com/anthropics/claude-plugins-official/main',
35
+ repo: 'anthropics/claude-plugins-official',
36
+ },
37
+ ];
38
+ /**
39
+ * Default plugins to install when no specific plugins are requested
40
+ * These are installed in addition to all plugins from the primary marketplace (lenne-tech)
41
+ */
42
+ exports.DEFAULT_EXTERNAL_PLUGINS = [
43
+ { marketplaceName: 'claude-plugins-official', pluginName: 'typescript-lsp' },
44
+ ];
45
+ /**
46
+ * Fetch available plugins from all configured marketplaces
47
+ * @param spin - Spinner factory function from toolbox
48
+ * @returns Array of plugin configurations
49
+ * @throws Error if no plugins are found
50
+ */
51
+ function fetchAvailablePlugins(spin) {
52
+ return __awaiter(this, void 0, void 0, function* () {
53
+ const spinner = spin('Fetching available plugins from marketplaces');
54
+ try {
55
+ // Fetch plugins from all marketplaces in parallel
56
+ const results = yield Promise.all(exports.MARKETPLACES.map(marketplace => fetchPluginsFromMarketplace(marketplace)));
57
+ // Flatten results
58
+ const plugins = results.flat();
59
+ if (plugins.length === 0) {
60
+ spinner.fail('No plugins found in any marketplace');
61
+ throw new Error('No plugins found');
62
+ }
63
+ // Group by marketplace for display
64
+ const byMarketplace = exports.MARKETPLACES.map(m => ({
65
+ count: plugins.filter(p => p.marketplaceName === m.name).length,
66
+ name: m.name,
67
+ })).filter(m => m.count > 0);
68
+ const summary = byMarketplace.map(m => `${m.name}: ${m.count}`).join(', ');
69
+ spinner.succeed(`Found ${plugins.length} plugins (${summary})`);
70
+ return plugins;
71
+ }
72
+ catch (err) {
73
+ spinner.fail('Failed to fetch plugins from marketplaces');
74
+ throw err;
75
+ }
76
+ });
77
+ }
78
+ /**
79
+ * Fetch available plugins from a single marketplace
80
+ * First tries central marketplace.json, then falls back to directory scan
81
+ * @param marketplace - Marketplace configuration
82
+ * @returns Array of plugin configurations
83
+ */
84
+ function fetchPluginsFromMarketplace(marketplace) {
85
+ return __awaiter(this, void 0, void 0, function* () {
86
+ const plugins = [];
87
+ try {
88
+ // First try to read central marketplace.json (used by official marketplace)
89
+ const marketplaceJsonUrl = `${marketplace.rawBase}/.claude-plugin/marketplace.json`;
90
+ const marketplaceJsonResponse = yield fetch(marketplaceJsonUrl);
91
+ if (marketplaceJsonResponse.ok) {
92
+ const text = yield marketplaceJsonResponse.text();
93
+ const marketplaceManifest = (0, json_utils_1.safeJsonParse)(text);
94
+ if ((marketplaceManifest === null || marketplaceManifest === void 0 ? void 0 : marketplaceManifest.plugins) && marketplaceManifest.plugins.length > 0) {
95
+ for (const plugin of marketplaceManifest.plugins) {
96
+ plugins.push({
97
+ description: plugin.description || '',
98
+ marketplaceName: marketplace.name,
99
+ marketplaceRepo: marketplace.repo,
100
+ pluginName: plugin.name,
101
+ });
102
+ }
103
+ return plugins;
104
+ }
105
+ }
106
+ // Fallback: Get list of plugin directories and read individual plugin.json files
107
+ const dirResponse = yield fetch(`${marketplace.apiBase}/plugins`);
108
+ if (!dirResponse.ok) {
109
+ return plugins;
110
+ }
111
+ const text = yield dirResponse.text();
112
+ const directories = (0, json_utils_1.safeJsonParse)(text);
113
+ if (!directories) {
114
+ return plugins;
115
+ }
116
+ const pluginDirs = directories.filter(d => d.type === 'dir');
117
+ // Fetch plugin.json for each plugin in parallel
118
+ const manifestPromises = pluginDirs.map((dir) => __awaiter(this, void 0, void 0, function* () {
119
+ try {
120
+ const manifestUrl = `${marketplace.rawBase}/plugins/${dir.name}/.claude-plugin/plugin.json`;
121
+ const manifestResponse = yield fetch(manifestUrl);
122
+ if (manifestResponse.ok) {
123
+ const manifestText = yield manifestResponse.text();
124
+ const manifest = (0, json_utils_1.safeJsonParse)(manifestText);
125
+ if (manifest) {
126
+ return {
127
+ description: manifest.description,
128
+ marketplaceName: marketplace.name,
129
+ marketplaceRepo: marketplace.repo,
130
+ pluginName: manifest.name,
131
+ };
132
+ }
133
+ }
134
+ }
135
+ catch (_a) {
136
+ // Skip plugins without valid manifest
137
+ }
138
+ return null;
139
+ }));
140
+ const results = yield Promise.all(manifestPromises);
141
+ plugins.push(...results.filter((p) => p !== null));
142
+ }
143
+ catch (_a) {
144
+ // Marketplace fetch failed, return empty array
145
+ }
146
+ return plugins;
147
+ });
148
+ }
149
+ /**
150
+ * Print available plugins list
151
+ * @param plugins - Array of plugin configurations
152
+ * @param info - Info print function from toolbox
153
+ */
154
+ function printAvailablePlugins(plugins, info) {
155
+ info('Available plugins:');
156
+ for (const plugin of plugins) {
157
+ info(` ${plugin.pluginName} - ${plugin.description}`);
158
+ }
159
+ }
160
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFya2V0cGxhY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbGliL21hcmtldHBsYWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7OztBQWdHQSxzREFnQ0M7QUFRRCxrRUF5RUM7QUFPRCxzREFRQztBQWhPRDs7O0dBR0c7QUFDSCw2Q0FBNkM7QUE0RDdDOztHQUVHO0FBQ1UsUUFBQSxZQUFZLEdBQXdCO0lBQy9DO1FBQ0UsT0FBTyxFQUFFLDZEQUE2RDtRQUN0RSxJQUFJLEVBQUUsWUFBWTtRQUNsQixPQUFPLEVBQUUsOERBQThEO1FBQ3ZFLElBQUksRUFBRSx1QkFBdUI7S0FDOUI7SUFDRDtRQUNFLE9BQU8sRUFBRSwwRUFBMEU7UUFDbkYsSUFBSSxFQUFFLHlCQUF5QjtRQUMvQixPQUFPLEVBQUUsMkVBQTJFO1FBQ3BGLElBQUksRUFBRSxvQ0FBb0M7S0FDM0M7Q0FDRixDQUFDO0FBRUY7OztHQUdHO0FBQ1UsUUFBQSx3QkFBd0IsR0FBMkQ7SUFDOUYsRUFBRSxlQUFlLEVBQUUseUJBQXlCLEVBQUUsVUFBVSxFQUFFLGdCQUFnQixFQUFFO0NBQzdFLENBQUM7QUFFRjs7Ozs7R0FLRztBQUNILFNBQXNCLHFCQUFxQixDQUN6QyxJQUFzRjs7UUFFdEYsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLDhDQUE4QyxDQUFDLENBQUM7UUFFckUsSUFBSSxDQUFDO1lBQ0gsa0RBQWtEO1lBQ2xELE1BQU0sT0FBTyxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FDL0Isb0JBQVksQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQywyQkFBMkIsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUMxRSxDQUFDO1lBRUYsa0JBQWtCO1lBQ2xCLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUUvQixJQUFJLE9BQU8sQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7Z0JBQ3pCLE9B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