|
8 | 8 | getWellKnownMarketplaces, |
9 | 9 | } from '../../core/marketplace.js'; |
10 | 10 | import { syncWorkspace, syncUserWorkspace } from '../../core/sync.js'; |
11 | | -import { addPlugin, removePlugin } from '../../core/workspace-modify.js'; |
12 | | -import { addUserPlugin, removeUserPlugin } from '../../core/user-workspace.js'; |
| 11 | +import { addPlugin, removePlugin, hasPlugin } from '../../core/workspace-modify.js'; |
| 12 | +import { addUserPlugin, removeUserPlugin, hasUserPlugin } from '../../core/user-workspace.js'; |
13 | 13 | import { isJsonMode, jsonOutput } from '../json-output.js'; |
14 | 14 | import { buildDescription, conciseSubcommands } from '../help.js'; |
15 | 15 | import { |
@@ -637,7 +637,7 @@ const pluginInstallCmd = command({ |
637 | 637 | if (result.autoRegistered) { |
638 | 638 | console.log(`\u2713 Auto-registered marketplace: ${result.autoRegistered}`); |
639 | 639 | } |
640 | | - console.log(`\u2713 Installed plugin${isUser ? ' (user scope)' : ''}: ${plugin}`); |
| 640 | + console.log(`\u2713 Installed plugin (${isUser ? 'user' : 'project'} scope): ${plugin}`); |
641 | 641 |
|
642 | 642 | const { ok: syncOk } = isUser |
643 | 643 | ? await runUserSyncAndPrint() |
@@ -673,48 +673,122 @@ const pluginUninstallCmd = command({ |
673 | 673 | }, |
674 | 674 | handler: async ({ plugin, scope }) => { |
675 | 675 | try { |
676 | | - const isUser = scope === 'user'; |
677 | | - const result = isUser |
678 | | - ? await removeUserPlugin(plugin) |
679 | | - : await removePlugin(plugin); |
| 676 | + // When an explicit scope is given, only uninstall from that scope |
| 677 | + if (scope) { |
| 678 | + const isUser = scope === 'user'; |
| 679 | + const result = isUser |
| 680 | + ? await removeUserPlugin(plugin) |
| 681 | + : await removePlugin(plugin); |
| 682 | + |
| 683 | + if (!result.success) { |
| 684 | + if (isJsonMode()) { |
| 685 | + jsonOutput({ success: false, command: 'plugin uninstall', error: result.error ?? 'Unknown error' }); |
| 686 | + process.exit(1); |
| 687 | + } |
| 688 | + console.error(`Error: ${result.error}`); |
| 689 | + process.exit(1); |
| 690 | + } |
680 | 691 |
|
681 | | - if (!result.success) { |
682 | 692 | if (isJsonMode()) { |
683 | | - jsonOutput({ success: false, command: 'plugin uninstall', error: result.error ?? 'Unknown error' }); |
| 693 | + const { ok, syncData } = isUser |
| 694 | + ? await runUserSyncAndPrint() |
| 695 | + : await runSyncAndPrint(); |
| 696 | + jsonOutput({ |
| 697 | + success: ok, |
| 698 | + command: 'plugin uninstall', |
| 699 | + data: { plugin, scope, syncResult: syncData }, |
| 700 | + ...(!ok && { error: 'Sync completed with failures' }), |
| 701 | + }); |
| 702 | + if (!ok) process.exit(1); |
| 703 | + return; |
| 704 | + } |
| 705 | + |
| 706 | + console.log(`\u2713 Uninstalled plugin (${scope} scope): ${plugin}`); |
| 707 | + const { ok: syncOk } = isUser |
| 708 | + ? await runUserSyncAndPrint() |
| 709 | + : await runSyncAndPrint(); |
| 710 | + if (!syncOk) process.exit(1); |
| 711 | + return; |
| 712 | + } |
| 713 | + |
| 714 | + // No explicit scope: uninstall from all scopes where the plugin exists |
| 715 | + const inProject = await hasPlugin(plugin); |
| 716 | + const inUser = await hasUserPlugin(plugin); |
| 717 | + |
| 718 | + if (!inProject && !inUser) { |
| 719 | + const error = `Plugin not found: ${plugin}`; |
| 720 | + if (isJsonMode()) { |
| 721 | + jsonOutput({ success: false, command: 'plugin uninstall', error }); |
684 | 722 | process.exit(1); |
685 | 723 | } |
686 | | - console.error(`Error: ${result.error}`); |
| 724 | + console.error(`Error: ${error}`); |
687 | 725 | process.exit(1); |
688 | 726 | } |
689 | 727 |
|
| 728 | + const removedScopes: string[] = []; |
| 729 | + |
| 730 | + if (inProject) { |
| 731 | + const result = await removePlugin(plugin); |
| 732 | + if (!result.success) { |
| 733 | + if (isJsonMode()) { |
| 734 | + jsonOutput({ success: false, command: 'plugin uninstall', error: result.error ?? 'Unknown error' }); |
| 735 | + process.exit(1); |
| 736 | + } |
| 737 | + console.error(`Error: ${result.error}`); |
| 738 | + process.exit(1); |
| 739 | + } |
| 740 | + removedScopes.push('project'); |
| 741 | + } |
| 742 | + |
| 743 | + if (inUser) { |
| 744 | + const result = await removeUserPlugin(plugin); |
| 745 | + if (!result.success) { |
| 746 | + if (isJsonMode()) { |
| 747 | + jsonOutput({ success: false, command: 'plugin uninstall', error: result.error ?? 'Unknown error' }); |
| 748 | + process.exit(1); |
| 749 | + } |
| 750 | + console.error(`Error: ${result.error}`); |
| 751 | + process.exit(1); |
| 752 | + } |
| 753 | + removedScopes.push('user'); |
| 754 | + } |
| 755 | + |
690 | 756 | if (isJsonMode()) { |
691 | | - const { ok, syncData } = isUser |
692 | | - ? await runUserSyncAndPrint() |
693 | | - : await runSyncAndPrint(); |
| 757 | + const syncResults: Record<string, ReturnType<typeof buildSyncData> | null> = {}; |
| 758 | + let allOk = true; |
| 759 | + if (removedScopes.includes('project')) { |
| 760 | + const { ok, syncData } = await runSyncAndPrint(); |
| 761 | + syncResults.project = syncData; |
| 762 | + if (!ok) allOk = false; |
| 763 | + } |
| 764 | + if (removedScopes.includes('user')) { |
| 765 | + const { ok, syncData } = await runUserSyncAndPrint(); |
| 766 | + syncResults.user = syncData; |
| 767 | + if (!ok) allOk = false; |
| 768 | + } |
694 | 769 | jsonOutput({ |
695 | | - success: ok, |
| 770 | + success: allOk, |
696 | 771 | command: 'plugin uninstall', |
697 | | - data: { |
698 | | - plugin, |
699 | | - scope: isUser ? 'user' : 'project', |
700 | | - syncResult: syncData, |
701 | | - }, |
702 | | - ...(!ok && { error: 'Sync completed with failures' }), |
| 772 | + data: { plugin, scopes: removedScopes, syncResults }, |
| 773 | + ...(!allOk && { error: 'Sync completed with failures' }), |
703 | 774 | }); |
704 | | - if (!ok) { |
705 | | - process.exit(1); |
706 | | - } |
| 775 | + if (!allOk) process.exit(1); |
707 | 776 | return; |
708 | 777 | } |
709 | 778 |
|
710 | | - console.log(`\u2713 Uninstalled plugin${isUser ? ' (user scope)' : ''}: ${plugin}`); |
| 779 | + const scopeLabel = removedScopes.join(' + '); |
| 780 | + console.log(`\u2713 Uninstalled plugin (${scopeLabel} scope): ${plugin}`); |
711 | 781 |
|
712 | | - const { ok: syncOk } = isUser |
713 | | - ? await runUserSyncAndPrint() |
714 | | - : await runSyncAndPrint(); |
715 | | - if (!syncOk) { |
716 | | - process.exit(1); |
| 782 | + let syncOk = true; |
| 783 | + if (removedScopes.includes('project')) { |
| 784 | + const { ok } = await runSyncAndPrint(); |
| 785 | + if (!ok) syncOk = false; |
| 786 | + } |
| 787 | + if (removedScopes.includes('user')) { |
| 788 | + const { ok } = await runUserSyncAndPrint(); |
| 789 | + if (!ok) syncOk = false; |
717 | 790 | } |
| 791 | + if (!syncOk) process.exit(1); |
718 | 792 | } catch (error) { |
719 | 793 | if (error instanceof Error) { |
720 | 794 | if (isJsonMode()) { |
|
0 commit comments