agy-plugins-cli 1.1.14

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.
package/dist/index.js ADDED
@@ -0,0 +1,388 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ const commander_1 = require("commander");
41
+ const chalk_1 = __importDefault(require("chalk"));
42
+ const path = __importStar(require("path"));
43
+ const os = __importStar(require("os"));
44
+ const config_1 = require("./config");
45
+ const fetcher_1 = require("./fetcher");
46
+ const state_1 = require("./state");
47
+ const manager_1 = require("./manager");
48
+ const ora_1 = __importDefault(require("ora"));
49
+ const packageJson = require('../package.json');
50
+ const program = new commander_1.Command();
51
+ program
52
+ .name('agy-plugin')
53
+ .description('Antigravity CLI Package Manager')
54
+ .version(packageJson.version);
55
+ const getTargetDir = (isLocal) => {
56
+ return isLocal ? path.join(process.cwd(), '.agents') : path.join(os.homedir(), '.gemini', 'config');
57
+ };
58
+ const marketplaceCmd = program
59
+ .command('marketplace')
60
+ .description('Manage plugin marketplaces');
61
+ marketplaceCmd
62
+ .command('add <repo>')
63
+ .description('Add a new marketplace repository (e.g. ZaunEkko/agy-plugins)')
64
+ .action((repo) => {
65
+ console.log(chalk_1.default.blue(`Adding marketplace: ${repo}`));
66
+ (0, config_1.addMarketplace)(repo);
67
+ });
68
+ async function runCheckCommand(namespaceArg) {
69
+ let namespace = namespaceArg.replace('@', '').toLowerCase();
70
+ const config = (0, config_1.loadConfig)();
71
+ const targetRepo = config.marketplaces.find(repo => repo.toLowerCase().includes(namespace));
72
+ if (!targetRepo) {
73
+ console.error(chalk_1.default.red(`Error: Namespace '${namespace}' not found in your marketplaces.`));
74
+ process.exit(1);
75
+ }
76
+ const s = (0, ora_1.default)(`Checking namespace @${namespace}...`).start();
77
+ let plugins = [];
78
+ try {
79
+ plugins = await (0, fetcher_1.listPluginsInRepo)(targetRepo);
80
+ s.stop();
81
+ }
82
+ catch (e) {
83
+ s.fail(chalk_1.default.red(`Failed to check namespace @${namespace}`));
84
+ return;
85
+ }
86
+ const { select, isCancel, multiselect } = await Promise.resolve().then(() => __importStar(require('@clack/prompts')));
87
+ while (true) {
88
+ const state = (0, state_1.loadState)();
89
+ const installedPlugins = Object.entries(state.plugins).filter(([k, v]) => v.repo === targetRepo).map(([k, v]) => k);
90
+ console.clear();
91
+ console.log(chalk_1.default.white.bold(namespace));
92
+ console.log(chalk_1.default.gray(targetRepo) + '\n');
93
+ console.log(chalk_1.default.white(`${plugins.length} available plugins\n`));
94
+ if (installedPlugins.length > 0) {
95
+ console.log(chalk_1.default.white.bold(`Installed plugins (${installedPlugins.length}):`));
96
+ installedPlugins.forEach(p => {
97
+ console.log(chalk_1.default.gray(`● `) + chalk_1.default.white(p.split('@')[0]));
98
+ });
99
+ console.log('');
100
+ }
101
+ const action = await select({
102
+ message: 'Select an action (Enter to select • Esc to go back)',
103
+ options: [
104
+ { value: 'browse', label: `> Browse plugins (${plugins.length})` },
105
+ { value: 'update', label: ` Update marketplace` },
106
+ { value: 'remove', label: ` Remove marketplace` },
107
+ { value: 'back', label: ` < Go back` }
108
+ ],
109
+ });
110
+ if (isCancel(action) || action === 'back') {
111
+ return;
112
+ }
113
+ if (action === 'browse') {
114
+ const selectedPlugins = await multiselect({
115
+ message: 'Select plugins to install (Space to select, Enter to confirm, Esc to go back)',
116
+ options: plugins.map(p => {
117
+ const dateStr = p.date ? chalk_1.default.gray(` (updated ${new Date(p.date).toISOString().split('T')[0]})`) : '';
118
+ let statusStr = '';
119
+ const installedPlugin = state.plugins[p.name] || state.plugins[`${p.name}@${namespace}`];
120
+ let colorize = chalk_1.default.white;
121
+ if (installedPlugin) {
122
+ if (p.sha && p.sha !== installedPlugin.sha) {
123
+ statusStr = chalk_1.default.yellow(' (★ Update available)');
124
+ colorize = chalk_1.default.yellow;
125
+ }
126
+ else {
127
+ statusStr = chalk_1.default.green(' (✔ Installed)');
128
+ colorize = chalk_1.default.green;
129
+ }
130
+ }
131
+ return {
132
+ value: p.name,
133
+ label: `${colorize(p.name)}${statusStr}${dateStr}`
134
+ };
135
+ }),
136
+ initialValues: plugins.filter(p => installedPlugins.includes(p.name) || installedPlugins.includes(`${p.name}@${namespace}`)).map(p => p.name),
137
+ required: false,
138
+ });
139
+ if (isCancel(selectedPlugins)) {
140
+ await new Promise(resolve => setTimeout(resolve, 50));
141
+ continue;
142
+ }
143
+ const toInstall = selectedPlugins;
144
+ if (toInstall.length > 0) {
145
+ for (const p of toInstall) {
146
+ // Skip if already installed
147
+ if (!installedPlugins.includes(p) && !installedPlugins.includes(`${p}@${namespace}`)) {
148
+ console.log(chalk_1.default.blue(`\nInstalling ${p}...`));
149
+ const targetDir = getTargetDir(false);
150
+ try {
151
+ const result = await (0, fetcher_1.downloadPlugin)(targetRepo, p, targetDir);
152
+ const sha = await (0, fetcher_1.getLatestCommitSha)(targetRepo, p);
153
+ if (sha) {
154
+ (0, state_1.recordPluginInstall)(`${p}@${namespace}`, targetRepo, sha, result.files, result.hooks);
155
+ }
156
+ console.log(chalk_1.default.green(`✓ Successfully installed ${p}`));
157
+ }
158
+ catch (e) {
159
+ console.log(chalk_1.default.red(`Failed to install ${p}`));
160
+ }
161
+ }
162
+ }
163
+ }
164
+ // Yield to event loop before recreating prompt to prevent terminal hangs
165
+ await new Promise(resolve => setTimeout(resolve, 50));
166
+ }
167
+ else if (action === 'update') {
168
+ console.log(chalk_1.default.yellow('Update marketplace feature coming soon!'));
169
+ await new Promise(r => setTimeout(r, 1000));
170
+ }
171
+ else if (action === 'remove') {
172
+ console.log(chalk_1.default.yellow('Remove marketplace feature coming soon!'));
173
+ await new Promise(r => setTimeout(r, 1000));
174
+ }
175
+ }
176
+ }
177
+ marketplaceCmd
178
+ .command('list')
179
+ .description('List all registered marketplace namespaces')
180
+ .action(async () => {
181
+ const { select, isCancel, text } = await Promise.resolve().then(() => __importStar(require('@clack/prompts')));
182
+ // Fetch GitHub stats ONCE to avoid rate limits when looping back
183
+ const initialConfig = (0, config_1.loadConfig)();
184
+ let stats = {};
185
+ if (initialConfig.marketplaces.length > 0) {
186
+ const s = (0, ora_1.default)('Loading marketplaces...').start();
187
+ for (const repo of initialConfig.marketplaces) {
188
+ let availableCount = 0;
189
+ let lastUpdated = 'unknown';
190
+ try {
191
+ const plugins = await (0, fetcher_1.listPluginsInRepo)(repo);
192
+ availableCount = plugins.length;
193
+ if (plugins.length > 0) {
194
+ const latestDateStr = plugins.reduce((max, p) => p.date && (!max || new Date(p.date) > new Date(max)) ? p.date : max, null);
195
+ if (latestDateStr) {
196
+ const d = new Date(latestDateStr);
197
+ lastUpdated = `${d.getFullYear()}/${d.getMonth() + 1}/${d.getDate()}`;
198
+ }
199
+ }
200
+ }
201
+ catch (e) {
202
+ // Ignore
203
+ }
204
+ stats[repo] = { availableCount, lastUpdated };
205
+ }
206
+ s.stop();
207
+ }
208
+ while (true) {
209
+ // Reload config/state dynamically to reflect any new additions or installs
210
+ const config = (0, config_1.loadConfig)();
211
+ const state = (0, state_1.loadState)();
212
+ let options = [];
213
+ options.push({ value: 'add', label: chalk_1.default.blue('> + Add Marketplace') });
214
+ for (const repo of config.marketplaces) {
215
+ const namespace = repo.split('/')[0].toLowerCase();
216
+ const stat = stats[repo] || { availableCount: 0, lastUpdated: 'unknown' };
217
+ const installedCount = Object.values(state.plugins).filter(p => p.repo === repo).length;
218
+ options.push({
219
+ value: namespace,
220
+ label: chalk_1.default.white(`● `) + chalk_1.default.white.bold(namespace) + chalk_1.default.gray(` (${repo})`),
221
+ hint: `${stat.availableCount} available • ${installedCount} installed • Updated ${stat.lastUpdated}`
222
+ });
223
+ }
224
+ console.clear();
225
+ const action = await select({
226
+ message: 'Manage marketplaces',
227
+ options,
228
+ });
229
+ if (isCancel(action)) {
230
+ process.exit(0);
231
+ }
232
+ if (action === 'add') {
233
+ const repo = await text({
234
+ message: 'Enter the GitHub repository path (e.g., ZaunEkko/agy-plugins):',
235
+ placeholder: 'username/repo',
236
+ validate(value) {
237
+ if (!value)
238
+ return 'Repository path is required!';
239
+ if (!value.includes('/'))
240
+ return 'Must be in username/repo format!';
241
+ }
242
+ });
243
+ if (isCancel(repo)) {
244
+ await new Promise(resolve => setTimeout(resolve, 50));
245
+ continue;
246
+ }
247
+ (0, config_1.addMarketplace)(repo);
248
+ console.log(chalk_1.default.green(`\n✓ Successfully added marketplace: ${repo}`));
249
+ await new Promise(r => setTimeout(r, 1000));
250
+ // Note: For simplicity, new marketplaces added in the same session won't have pre-fetched stats until restart
251
+ }
252
+ else {
253
+ await runCheckCommand(action);
254
+ // Yield to event loop when returning from inner menu to prevent terminal hangs
255
+ await new Promise(resolve => setTimeout(resolve, 50));
256
+ }
257
+ }
258
+ });
259
+ marketplaceCmd
260
+ .command('check <namespace>')
261
+ .description('Check and list all available plugins in a specific namespace (e.g. @zaunekko)')
262
+ .action(runCheckCommand);
263
+ program
264
+ .command('add <plugin>')
265
+ .description('Install a plugin (e.g. commit-commands@zaunekko)')
266
+ .option('-l, --local', 'Install locally to the current project instead of globally')
267
+ .action(async (pluginArg, options) => {
268
+ if (!pluginArg.includes('@')) {
269
+ console.error(chalk_1.default.red(`Error: Please specify the marketplace namespace (e.g., ${pluginArg}@zaunekko)`));
270
+ process.exit(1);
271
+ }
272
+ const parts = pluginArg.split('@');
273
+ const pluginName = parts[0];
274
+ const namespace = parts[1];
275
+ const config = (0, config_1.loadConfig)();
276
+ const targetRepo = config.marketplaces.find(repo => repo.toLowerCase().includes(namespace.toLowerCase()));
277
+ if (!targetRepo) {
278
+ console.error(chalk_1.default.red(`Error: Namespace '${namespace}' not found in your marketplaces.`));
279
+ process.exit(1);
280
+ }
281
+ console.log(chalk_1.default.green(`Installing plugin: ${pluginName} from repository: ${targetRepo}`));
282
+ const spinner = (0, ora_1.default)(`Downloading ${pluginName}...`).start();
283
+ try {
284
+ const targetDir = getTargetDir(options.local);
285
+ const result = await (0, fetcher_1.downloadPlugin)(targetRepo, pluginName, targetDir);
286
+ const sha = await (0, fetcher_1.getLatestCommitSha)(targetRepo, pluginName);
287
+ if (sha) {
288
+ (0, state_1.recordPluginInstall)(pluginArg, targetRepo, sha, result.files, result.hooks);
289
+ }
290
+ spinner.succeed(chalk_1.default.green(`Successfully installed ${pluginName} to ${targetDir}`));
291
+ }
292
+ catch (error) {
293
+ spinner.fail(chalk_1.default.red(`Failed to install ${pluginName}.`));
294
+ process.exit(1);
295
+ }
296
+ });
297
+ program
298
+ .command('update [target]')
299
+ .description('Update all plugins, a specific plugin (e.g. plugin@namespace), or a whole namespace (e.g. @namespace)')
300
+ .option('-l, --local', 'Update locally to the current project instead of globally')
301
+ .action(async (targetArg, options) => {
302
+ const state = (0, state_1.loadState)();
303
+ let pluginsToUpdate = [];
304
+ if (!targetArg) {
305
+ // Update ALL installed plugins
306
+ pluginsToUpdate = Object.keys(state.plugins);
307
+ }
308
+ else if (targetArg.startsWith('@')) {
309
+ // Update ALL plugins in a specific namespace
310
+ const namespace = targetArg.replace('@', '').toLowerCase();
311
+ const config = (0, config_1.loadConfig)();
312
+ const targetRepo = config.marketplaces.find(repo => repo.toLowerCase().includes(namespace));
313
+ if (!targetRepo) {
314
+ console.error(chalk_1.default.red(`Error: Namespace '${namespace}' not found in your marketplaces.`));
315
+ process.exit(1);
316
+ }
317
+ pluginsToUpdate = Object.entries(state.plugins)
318
+ .filter(([k, v]) => v.repo === targetRepo)
319
+ .map(([k, v]) => k);
320
+ if (pluginsToUpdate.length === 0) {
321
+ console.log(chalk_1.default.yellow(`No plugins installed from namespace @${namespace}.`));
322
+ return;
323
+ }
324
+ }
325
+ else {
326
+ // Update a specific plugin
327
+ pluginsToUpdate = [targetArg];
328
+ }
329
+ if (pluginsToUpdate.length === 0) {
330
+ console.log(chalk_1.default.yellow(`No plugins installed yet.`));
331
+ return;
332
+ }
333
+ for (const name of pluginsToUpdate) {
334
+ const installed = state.plugins[name];
335
+ if (!installed) {
336
+ console.log(chalk_1.default.red(`Plugin ${name} is not installed.`));
337
+ continue;
338
+ }
339
+ let actualPluginName = name;
340
+ if (name.includes('@')) {
341
+ actualPluginName = name.split('@')[0];
342
+ }
343
+ console.log(chalk_1.default.blue(`\nChecking for updates: ${name}...`));
344
+ const latestSha = await (0, fetcher_1.getLatestCommitSha)(installed.repo, actualPluginName);
345
+ if (!latestSha) {
346
+ console.log(chalk_1.default.yellow(`Could not fetch version info for ${name}. Skipping.`));
347
+ continue;
348
+ }
349
+ if (latestSha === installed.sha) {
350
+ console.log(chalk_1.default.green(`✓ ${name} is already up to date.`));
351
+ }
352
+ else {
353
+ console.log(chalk_1.default.cyan(`Update found for ${name}. Downloading new version...`));
354
+ const spinner = (0, ora_1.default)(`Updating ${name}...`).start();
355
+ try {
356
+ const targetDir = getTargetDir(options.local);
357
+ const result = await (0, fetcher_1.downloadPlugin)(installed.repo, actualPluginName, targetDir, true);
358
+ (0, state_1.recordPluginInstall)(name, installed.repo, latestSha, result.files, result.hooks);
359
+ spinner.succeed(chalk_1.default.green(`Successfully updated ${name}.`));
360
+ }
361
+ catch (error) {
362
+ spinner.fail(chalk_1.default.red(`Failed to update ${name}.`));
363
+ }
364
+ }
365
+ }
366
+ });
367
+ program
368
+ .command('disable <plugin>')
369
+ .description('Disable an installed plugin')
370
+ .option('-l, --local', 'Disable from the local project instead of globally')
371
+ .action((pluginName, options) => {
372
+ (0, manager_1.disablePlugin)(pluginName, getTargetDir(options.local));
373
+ });
374
+ program
375
+ .command('enable <plugin>')
376
+ .description('Enable a disabled plugin')
377
+ .option('-l, --local', 'Enable from the local project instead of globally')
378
+ .action((pluginName, options) => {
379
+ (0, manager_1.enablePlugin)(pluginName, getTargetDir(options.local));
380
+ });
381
+ program
382
+ .command('remove <plugin>')
383
+ .description('Uninstall a plugin and remove its files')
384
+ .option('-l, --local', 'Remove from the local project instead of globally')
385
+ .action((pluginName, options) => {
386
+ (0, manager_1.removePlugin)(pluginName, getTargetDir(options.local));
387
+ });
388
+ program.parse(process.argv);
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.setPluginHooksState = setPluginHooksState;
40
+ exports.removePluginHooks = removePluginHooks;
41
+ exports.disablePlugin = disablePlugin;
42
+ exports.enablePlugin = enablePlugin;
43
+ exports.removePlugin = removePlugin;
44
+ const fs = __importStar(require("fs"));
45
+ const path = __importStar(require("path"));
46
+ const chalk_1 = __importDefault(require("chalk"));
47
+ const state_1 = require("./state");
48
+ function getHooksPath(targetDir) {
49
+ return path.join(targetDir, 'hooks.json');
50
+ }
51
+ function setPluginHooksState(targetDir, hooks, enabled) {
52
+ const hooksPath = getHooksPath(targetDir);
53
+ if (!fs.existsSync(hooksPath))
54
+ return;
55
+ try {
56
+ const data = JSON.parse(fs.readFileSync(hooksPath, 'utf-8'));
57
+ let changed = false;
58
+ for (const hookName of hooks) {
59
+ if (data[hookName]) {
60
+ data[hookName].enabled = enabled;
61
+ changed = true;
62
+ }
63
+ }
64
+ if (changed) {
65
+ fs.writeFileSync(hooksPath, JSON.stringify(data, null, 2), 'utf-8');
66
+ }
67
+ }
68
+ catch (e) {
69
+ console.warn(chalk_1.default.yellow(`Could not modify hooks at ${hooksPath}`));
70
+ }
71
+ }
72
+ function removePluginHooks(targetDir, hooks) {
73
+ const hooksPath = getHooksPath(targetDir);
74
+ if (!fs.existsSync(hooksPath))
75
+ return;
76
+ try {
77
+ const data = JSON.parse(fs.readFileSync(hooksPath, 'utf-8'));
78
+ let changed = false;
79
+ for (const hookName of hooks) {
80
+ if (data[hookName]) {
81
+ delete data[hookName];
82
+ changed = true;
83
+ }
84
+ }
85
+ if (changed) {
86
+ fs.writeFileSync(hooksPath, JSON.stringify(data, null, 2), 'utf-8');
87
+ }
88
+ }
89
+ catch (e) {
90
+ console.warn(chalk_1.default.yellow(`Could not remove hooks at ${hooksPath}`));
91
+ }
92
+ }
93
+ function disablePlugin(pluginName, targetDir) {
94
+ const plugin = (0, state_1.getInstalledPlugin)(pluginName);
95
+ if (!plugin) {
96
+ console.log(chalk_1.default.red(`Plugin ${pluginName} is not installed.`));
97
+ return;
98
+ }
99
+ if (plugin.files) {
100
+ for (const file of plugin.files) {
101
+ if (fs.existsSync(file) && !file.endsWith('.disabled')) {
102
+ fs.renameSync(file, file + '.disabled');
103
+ }
104
+ }
105
+ }
106
+ if (plugin.hooks) {
107
+ setPluginHooksState(targetDir, plugin.hooks, false);
108
+ }
109
+ console.log(chalk_1.default.green(`✓ Plugin ${pluginName} has been disabled.`));
110
+ }
111
+ function enablePlugin(pluginName, targetDir) {
112
+ const plugin = (0, state_1.getInstalledPlugin)(pluginName);
113
+ if (!plugin) {
114
+ console.log(chalk_1.default.red(`Plugin ${pluginName} is not installed.`));
115
+ return;
116
+ }
117
+ if (plugin.files) {
118
+ for (const file of plugin.files) {
119
+ const disabledFile = file + '.disabled';
120
+ if (fs.existsSync(disabledFile)) {
121
+ fs.renameSync(disabledFile, file);
122
+ }
123
+ }
124
+ }
125
+ if (plugin.hooks) {
126
+ setPluginHooksState(targetDir, plugin.hooks, true);
127
+ }
128
+ console.log(chalk_1.default.green(`✓ Plugin ${pluginName} has been enabled.`));
129
+ }
130
+ function removePlugin(pluginName, targetDir) {
131
+ const plugin = (0, state_1.getInstalledPlugin)(pluginName);
132
+ if (!plugin) {
133
+ console.log(chalk_1.default.red(`Plugin ${pluginName} is not installed.`));
134
+ return;
135
+ }
136
+ if (plugin.files) {
137
+ for (const file of plugin.files) {
138
+ if (fs.existsSync(file)) {
139
+ fs.unlinkSync(file);
140
+ }
141
+ else if (fs.existsSync(file + '.disabled')) {
142
+ fs.unlinkSync(file + '.disabled');
143
+ }
144
+ }
145
+ }
146
+ if (plugin.hooks) {
147
+ removePluginHooks(targetDir, plugin.hooks);
148
+ }
149
+ (0, state_1.removePluginState)(pluginName);
150
+ console.log(chalk_1.default.green(`✓ Plugin ${pluginName} has been removed.`));
151
+ }
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.mergeMcpConfig = mergeMcpConfig;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const chalk_1 = __importDefault(require("chalk"));
43
+ function mergeMcpConfig(localMcpPath, remoteMcpContent) {
44
+ let localMcp = { mcpServers: {} };
45
+ // Read existing local mcp.json if it exists
46
+ if (fs.existsSync(localMcpPath)) {
47
+ try {
48
+ const data = fs.readFileSync(localMcpPath, 'utf-8');
49
+ localMcp = JSON.parse(data);
50
+ if (!localMcp.mcpServers) {
51
+ localMcp.mcpServers = {};
52
+ }
53
+ }
54
+ catch (e) {
55
+ console.warn(chalk_1.default.yellow(`Warning: Could not parse existing local mcp.json at ${localMcpPath}. It will be overwritten.`));
56
+ }
57
+ }
58
+ // Parse remote mcp.json
59
+ let remoteMcp = {};
60
+ try {
61
+ remoteMcp = JSON.parse(remoteMcpContent);
62
+ }
63
+ catch (e) {
64
+ console.error(chalk_1.default.red(`Error: Could not parse remote mcp.json. Skipping MCP merge.`));
65
+ return;
66
+ }
67
+ if (remoteMcp.mcpServers) {
68
+ let addedCount = 0;
69
+ for (const [serverName, serverConfig] of Object.entries(remoteMcp.mcpServers)) {
70
+ if (localMcp.mcpServers[serverName]) {
71
+ console.log(chalk_1.default.yellow(`Warning: MCP server '${serverName}' already exists locally. Overwriting...`));
72
+ }
73
+ else {
74
+ addedCount++;
75
+ }
76
+ localMcp.mcpServers[serverName] = serverConfig;
77
+ }
78
+ // Save merged config
79
+ fs.mkdirSync(path.dirname(localMcpPath), { recursive: true });
80
+ fs.writeFileSync(localMcpPath, JSON.stringify(localMcp, null, 2), 'utf-8');
81
+ if (addedCount > 0) {
82
+ console.log(chalk_1.default.green(`Successfully merged ${addedCount} MCP server(s) into ${localMcpPath}`));
83
+ }
84
+ }
85
+ else {
86
+ console.log(chalk_1.default.gray(`Remote mcp.json contains no mcpServers. Skipping.`));
87
+ }
88
+ }