@robota-sdk/agent-command 3.0.0-beta.64

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.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/dist/node/index.cjs +30 -0
  3. package/dist/node/index.d.ts +293 -0
  4. package/dist/node/index.d.ts.map +1 -0
  5. package/dist/node/index.js +31 -0
  6. package/dist/node/index.js.map +1 -0
  7. package/package.json +48 -0
  8. package/src/agent/__tests__/agent-command.test.ts +504 -0
  9. package/src/agent/agent-command-module.ts +82 -0
  10. package/src/agent/agent-command-parser.ts +180 -0
  11. package/src/agent/agent-command.ts +235 -0
  12. package/src/agent/index.ts +7 -0
  13. package/src/background/__tests__/background-command-module.test.ts +255 -0
  14. package/src/background/background-command-module.ts +53 -0
  15. package/src/background/background-command.ts +63 -0
  16. package/src/background/index.ts +6 -0
  17. package/src/compact/__tests__/compact-command-module.test.ts +162 -0
  18. package/src/compact/compact-command-module.ts +51 -0
  19. package/src/compact/compact-command.ts +21 -0
  20. package/src/compact/index.ts +6 -0
  21. package/src/context/__tests__/context-command-module.test.ts +294 -0
  22. package/src/context/context-command-module.ts +54 -0
  23. package/src/context/context-command.ts +298 -0
  24. package/src/context/index.ts +6 -0
  25. package/src/exit/__tests__/exit-command-module.test.ts +35 -0
  26. package/src/exit/exit-command-module.ts +48 -0
  27. package/src/exit/exit-command.ts +10 -0
  28. package/src/exit/index.ts +6 -0
  29. package/src/help/__tests__/help-command-module.test.ts +106 -0
  30. package/src/help/help-command-module.ts +48 -0
  31. package/src/help/help-command.ts +9 -0
  32. package/src/help/index.ts +6 -0
  33. package/src/index.ts +20 -0
  34. package/src/language/__tests__/language-command-module.test.ts +105 -0
  35. package/src/language/index.ts +6 -0
  36. package/src/language/language-command-module.ts +56 -0
  37. package/src/language/language-command.ts +22 -0
  38. package/src/memory/__tests__/memory-command-module.test.ts +272 -0
  39. package/src/memory/index.ts +6 -0
  40. package/src/memory/memory-command-module.ts +57 -0
  41. package/src/memory/memory-command.ts +234 -0
  42. package/src/mode/__tests__/mode-command-module.test.ts +143 -0
  43. package/src/mode/index.ts +6 -0
  44. package/src/mode/mode-command-module.ts +56 -0
  45. package/src/mode/mode-command.ts +34 -0
  46. package/src/model/__tests__/model-command-module.test.ts +273 -0
  47. package/src/model/index.ts +6 -0
  48. package/src/model/model-command-module.ts +68 -0
  49. package/src/model/model-command.ts +40 -0
  50. package/src/permissions/__tests__/permissions-command-module.test.ts +164 -0
  51. package/src/permissions/index.ts +6 -0
  52. package/src/permissions/permissions-command-module.ts +56 -0
  53. package/src/permissions/permissions-command.ts +45 -0
  54. package/src/plugin/__tests__/plugin-command-module.test.ts +214 -0
  55. package/src/plugin/index.ts +7 -0
  56. package/src/plugin/plugin-command-module.ts +81 -0
  57. package/src/plugin/plugin-command.ts +230 -0
  58. package/src/provider/__tests__/provider-command-module.test.ts +488 -0
  59. package/src/provider/__tests__/provider-setup-flow.test.ts +43 -0
  60. package/src/provider/index.ts +30 -0
  61. package/src/provider/provider-command-execution.ts +150 -0
  62. package/src/provider/provider-command-module.ts +65 -0
  63. package/src/provider/provider-command-profile-lifecycle.ts +211 -0
  64. package/src/provider/provider-command-profile-operations.ts +198 -0
  65. package/src/provider/provider-command-profile.ts +109 -0
  66. package/src/provider/provider-command-setup.ts +104 -0
  67. package/src/provider/provider-setup-flow.ts +309 -0
  68. package/src/reset/__tests__/reset-command-module.test.ts +63 -0
  69. package/src/reset/index.ts +2 -0
  70. package/src/reset/reset-command-module.ts +49 -0
  71. package/src/reset/reset-command.ts +10 -0
  72. package/src/rewind/__tests__/rewind-command-module.test.ts +215 -0
  73. package/src/rewind/index.ts +2 -0
  74. package/src/rewind/rewind-command-module.ts +57 -0
  75. package/src/rewind/rewind-command.ts +184 -0
  76. package/src/session/__tests__/session-command-module.test.ts +339 -0
  77. package/src/session/index.ts +17 -0
  78. package/src/session/session-command-module.ts +168 -0
  79. package/src/session/session-command.ts +74 -0
  80. package/src/settings/index.ts +7 -0
  81. package/src/settings/settings-command-module.ts +50 -0
  82. package/src/skills/__tests__/skills-command-module.test.ts +157 -0
  83. package/src/skills/index.ts +6 -0
  84. package/src/skills/skills-command-module.ts +62 -0
  85. package/src/skills/skills-command.ts +110 -0
  86. package/src/statusline/__tests__/statusline-command-module.test.ts +95 -0
  87. package/src/statusline/index.ts +6 -0
  88. package/src/statusline/statusline-command-module.ts +56 -0
  89. package/src/statusline/statusline-command.ts +79 -0
  90. package/src/user-local/__tests__/user-local-command.test.ts +145 -0
  91. package/src/user-local/index.ts +13 -0
  92. package/src/user-local/user-local-command-constants.ts +5 -0
  93. package/src/user-local/user-local-command-module.ts +67 -0
  94. package/src/user-local/user-local-command.ts +205 -0
  95. package/src/user-local/user-local-memory-command.ts +147 -0
@@ -0,0 +1,214 @@
1
+ import type {
2
+ ICommandHostContext,
3
+ ICommandPluginAdapter,
4
+ ICommandSessionRuntime,
5
+ } from '@robota-sdk/agent-framework';
6
+ import { describe, expect, it, vi } from 'vitest';
7
+ import { createPluginCommandModule } from '../plugin-command-module.js';
8
+ import { executePluginCommand, executeReloadPluginsCommand } from '../plugin-command.js';
9
+
10
+ function createPluginAdapter(overrides?: Partial<ICommandPluginAdapter>): ICommandPluginAdapter {
11
+ return {
12
+ listInstalled: vi.fn().mockResolvedValue([]),
13
+ listAvailablePlugins: vi.fn().mockResolvedValue([]),
14
+ install: vi.fn().mockResolvedValue(undefined),
15
+ uninstall: vi.fn().mockResolvedValue(undefined),
16
+ enable: vi.fn().mockResolvedValue(undefined),
17
+ disable: vi.fn().mockResolvedValue(undefined),
18
+ marketplaceAdd: vi.fn().mockResolvedValue('community'),
19
+ marketplaceRemove: vi.fn().mockResolvedValue(undefined),
20
+ marketplaceUpdate: vi.fn().mockResolvedValue(undefined),
21
+ marketplaceList: vi.fn().mockResolvedValue([]),
22
+ reloadPlugins: vi.fn().mockResolvedValue({ loadedPluginCount: 2 }),
23
+ ...overrides,
24
+ };
25
+ }
26
+
27
+ function createCommandSessionRuntime(): ICommandSessionRuntime {
28
+ return {
29
+ clearHistory: () => undefined,
30
+ compact: async () => undefined,
31
+ getContextState: () => ({
32
+ maxTokens: 100,
33
+ usedTokens: 10,
34
+ usedPercentage: 10,
35
+ remainingPercentage: 90,
36
+ }),
37
+ getPermissionMode: () => 'default',
38
+ setPermissionMode: () => undefined,
39
+ getSessionId: () => 'session_1',
40
+ getMessageCount: () => 0,
41
+ getSessionAllowedTools: () => [],
42
+ getAutoCompactThreshold: () => false,
43
+ };
44
+ }
45
+
46
+ function createCommandHostContext(adapter?: ICommandPluginAdapter): ICommandHostContext {
47
+ const checkpoint = {
48
+ id: 'checkpoint_1',
49
+ sessionId: 'session_1',
50
+ sequence: 1,
51
+ prompt: 'prompt',
52
+ createdAt: '2026-05-03T00:00:00.000Z',
53
+ fileCount: 0,
54
+ };
55
+ return {
56
+ getSession: () => createCommandSessionRuntime(),
57
+ getContextState: () => ({
58
+ maxTokens: 100,
59
+ usedTokens: 10,
60
+ usedPercentage: 10,
61
+ remainingPercentage: 90,
62
+ }),
63
+ getAutoCompactThreshold: () => 0.8,
64
+ getCommandHostAdapters: () => (adapter === undefined ? {} : { plugin: adapter }),
65
+ compactContext: async () => undefined,
66
+ getCwd: () => '/workspace',
67
+ listCommands: () => [],
68
+ listEditCheckpoints: () => [],
69
+ restoreEditCheckpoint: async () => ({
70
+ target: checkpoint,
71
+ restoredCheckpointCount: 0,
72
+ restoredFileCount: 0,
73
+ removedCheckpointCount: 0,
74
+ }),
75
+ rollbackEditCheckpoint: async () => ({
76
+ target: checkpoint,
77
+ restoredCheckpointCount: 0,
78
+ restoredFileCount: 0,
79
+ removedCheckpointCount: 0,
80
+ }),
81
+ getUsedMemoryReferences: () => [],
82
+ recordMemoryEvent: () => undefined,
83
+ listBackgroundTasks: () => [],
84
+ readBackgroundTaskLog: async (taskId) => ({ taskId, lines: [] }),
85
+ cancelBackgroundTask: async () => undefined,
86
+ closeBackgroundTask: async () => undefined,
87
+ };
88
+ }
89
+
90
+ describe('createPluginCommandModule', () => {
91
+ it('contributes plugin command metadata and executable commands', () => {
92
+ const module = createPluginCommandModule();
93
+
94
+ expect(module.name).toBe('agent-command-plugin');
95
+ expect(module.commandSources?.[0]?.getCommands()).toEqual([
96
+ expect.objectContaining({
97
+ name: 'plugin',
98
+ description: 'Manage plugins',
99
+ source: 'plugin-manager',
100
+ modelInvocable: false,
101
+ argumentHint: expect.stringContaining('install'),
102
+ }),
103
+ expect.objectContaining({
104
+ name: 'reload-plugins',
105
+ description: 'Reload all plugin resources',
106
+ source: 'plugin-manager',
107
+ modelInvocable: false,
108
+ }),
109
+ ]);
110
+ expect(module.systemCommands?.map((command) => command.name)).toEqual([
111
+ 'plugin',
112
+ 'reload-plugins',
113
+ ]);
114
+ expect(module.systemCommands?.[0]?.lifecycle).toBe('inline');
115
+ });
116
+ });
117
+
118
+ describe('executePluginCommand', () => {
119
+ it('opens the host plugin manager for empty args', async () => {
120
+ await expect(executePluginCommand(createCommandHostContext(), '')).resolves.toEqual({
121
+ success: true,
122
+ message: 'Opening plugin manager...',
123
+ effects: [{ type: 'plugin-tui-requested' }],
124
+ });
125
+ });
126
+
127
+ it('returns unavailable when an operation needs a missing adapter', async () => {
128
+ await expect(
129
+ executePluginCommand(createCommandHostContext(), 'install demo@community'),
130
+ ).resolves.toEqual({
131
+ success: false,
132
+ message: 'Plugin management is not available.',
133
+ });
134
+ });
135
+
136
+ it('installs plugins through the adapter', async () => {
137
+ const adapter = createPluginAdapter();
138
+
139
+ await expect(
140
+ executePluginCommand(createCommandHostContext(adapter), 'install demo@community'),
141
+ ).resolves.toEqual({
142
+ success: true,
143
+ message: 'Installed plugin: demo@community',
144
+ });
145
+ expect(adapter.install).toHaveBeenCalledWith('demo@community');
146
+ });
147
+
148
+ it('lists marketplaces through the adapter', async () => {
149
+ const adapter = createPluginAdapter({
150
+ marketplaceList: vi.fn().mockResolvedValue([{ name: 'community', type: 'git' }]),
151
+ });
152
+
153
+ const result = await executePluginCommand(
154
+ createCommandHostContext(adapter),
155
+ 'marketplace list',
156
+ );
157
+
158
+ expect(result).toEqual({
159
+ success: true,
160
+ message: 'Marketplace sources:\n community (git)',
161
+ });
162
+ expect(adapter.marketplaceList).toHaveBeenCalled();
163
+ });
164
+
165
+ it('reports adapter errors as command failures', async () => {
166
+ const adapter = createPluginAdapter({
167
+ enable: vi.fn().mockRejectedValue(new Error('not installed')),
168
+ });
169
+
170
+ await expect(
171
+ executePluginCommand(createCommandHostContext(adapter), 'enable missing@community'),
172
+ ).resolves.toEqual({
173
+ success: false,
174
+ message: 'Plugin error: not installed',
175
+ });
176
+ });
177
+
178
+ it('returns usage for incomplete subcommands', async () => {
179
+ await expect(executePluginCommand(createCommandHostContext(), 'disable')).resolves.toEqual({
180
+ success: false,
181
+ message: 'Usage: /plugin disable <name>@<marketplace>',
182
+ });
183
+ });
184
+ });
185
+
186
+ describe('executeReloadPluginsCommand', () => {
187
+ it('reloads plugins through the adapter and requests registry refresh', async () => {
188
+ const adapter = createPluginAdapter({
189
+ reloadPlugins: vi.fn().mockResolvedValue({ loadedPluginCount: 3 }),
190
+ });
191
+
192
+ await expect(
193
+ executeReloadPluginsCommand(createCommandHostContext(adapter), ''),
194
+ ).resolves.toEqual({
195
+ success: true,
196
+ message: 'Reloaded 3 plugin resources.',
197
+ effects: [{ type: 'plugin-registry-reload-requested' }],
198
+ });
199
+ expect(adapter.reloadPlugins).toHaveBeenCalled();
200
+ });
201
+
202
+ it('reports reload failures instead of returning placeholder success', async () => {
203
+ const adapter = createPluginAdapter({
204
+ reloadPlugins: vi.fn().mockRejectedValue(new Error('manifest failed')),
205
+ });
206
+
207
+ await expect(
208
+ executeReloadPluginsCommand(createCommandHostContext(adapter), ''),
209
+ ).resolves.toEqual({
210
+ success: false,
211
+ message: 'Plugin error: manifest failed',
212
+ });
213
+ });
214
+ });
@@ -0,0 +1,7 @@
1
+ export {
2
+ createPluginCommandEntry,
3
+ createPluginCommandModule,
4
+ createReloadPluginsCommandEntry,
5
+ PluginManagerCommandSource,
6
+ } from './plugin-command-module.js';
7
+ export { executePluginCommand, executeReloadPluginsCommand } from './plugin-command.js';
@@ -0,0 +1,81 @@
1
+ import type {
2
+ ICommand,
3
+ ICommandModule,
4
+ ICommandSource,
5
+ ISystemCommand,
6
+ } from '@robota-sdk/agent-framework';
7
+ import {
8
+ buildPluginCommandSubcommands,
9
+ PLUGIN_COMMAND_ARGUMENT_HINT,
10
+ PLUGIN_COMMAND_DESCRIPTION,
11
+ RELOAD_PLUGINS_COMMAND_DESCRIPTION,
12
+ } from '@robota-sdk/agent-framework';
13
+ import { executePluginCommand, executeReloadPluginsCommand } from './plugin-command.js';
14
+
15
+ export function createPluginCommandEntry(): ICommand {
16
+ return {
17
+ name: 'plugin',
18
+ displayName: 'Plugins',
19
+ description: PLUGIN_COMMAND_DESCRIPTION,
20
+ source: 'plugin-manager',
21
+ modelInvocable: false,
22
+ argumentHint: PLUGIN_COMMAND_ARGUMENT_HINT,
23
+ subcommands: buildPluginCommandSubcommands(),
24
+ };
25
+ }
26
+
27
+ export function createReloadPluginsCommandEntry(): ICommand {
28
+ return {
29
+ name: 'reload-plugins',
30
+ displayName: 'Reload Plugins',
31
+ description: RELOAD_PLUGINS_COMMAND_DESCRIPTION,
32
+ source: 'plugin-manager',
33
+ modelInvocable: false,
34
+ };
35
+ }
36
+
37
+ function createPluginSystemCommand(): ISystemCommand {
38
+ const entry = createPluginCommandEntry();
39
+ return {
40
+ name: entry.name,
41
+ displayName: entry.displayName,
42
+ description: entry.description,
43
+ requiresPermission: false,
44
+ userInvocable: true,
45
+ modelInvocable: false,
46
+ argumentHint: entry.argumentHint,
47
+ lifecycle: 'inline',
48
+ subcommands: entry.subcommands,
49
+ execute: executePluginCommand,
50
+ };
51
+ }
52
+
53
+ function createReloadPluginsSystemCommand(): ISystemCommand {
54
+ const entry = createReloadPluginsCommandEntry();
55
+ return {
56
+ name: entry.name,
57
+ displayName: entry.displayName,
58
+ description: entry.description,
59
+ requiresPermission: false,
60
+ userInvocable: true,
61
+ modelInvocable: false,
62
+ lifecycle: 'inline',
63
+ execute: executeReloadPluginsCommand,
64
+ };
65
+ }
66
+
67
+ export class PluginManagerCommandSource implements ICommandSource {
68
+ readonly name = 'plugin-manager';
69
+
70
+ getCommands(): ICommand[] {
71
+ return [createPluginCommandEntry(), createReloadPluginsCommandEntry()];
72
+ }
73
+ }
74
+
75
+ export function createPluginCommandModule(): ICommandModule {
76
+ return {
77
+ name: 'agent-command-plugin',
78
+ commandSources: [new PluginManagerCommandSource()],
79
+ systemCommands: [createPluginSystemCommand(), createReloadPluginsSystemCommand()],
80
+ };
81
+ }
@@ -0,0 +1,230 @@
1
+ import type {
2
+ ICommandHostContext,
3
+ ICommandPluginAdapter,
4
+ ICommandResult,
5
+ } from '@robota-sdk/agent-framework';
6
+ import {
7
+ createPluginRegistryReloadRequestedEffect,
8
+ createPluginTuiRequestedEffect,
9
+ resolvePluginCommandAdapter,
10
+ } from '@robota-sdk/agent-framework';
11
+
12
+ function getSubcommandParts(args: string): { subcommand: string; subArgs: string } {
13
+ const parts = args
14
+ .trim()
15
+ .split(/\s+/)
16
+ .filter((part) => part.length > 0);
17
+ return {
18
+ subcommand: parts[0] ?? '',
19
+ subArgs: parts.slice(1).join(' ').trim(),
20
+ };
21
+ }
22
+
23
+ function usage(message: string): ICommandResult {
24
+ return {
25
+ success: false,
26
+ message,
27
+ };
28
+ }
29
+
30
+ function getPluginAdapter(context: ICommandHostContext): ICommandPluginAdapter | undefined {
31
+ return resolvePluginCommandAdapter(context);
32
+ }
33
+
34
+ async function executePluginOperation(
35
+ context: ICommandHostContext,
36
+ operation: (adapter: ICommandPluginAdapter) => Promise<string>,
37
+ ): Promise<ICommandResult> {
38
+ const adapter = getPluginAdapter(context);
39
+ if (adapter === undefined) {
40
+ return {
41
+ success: false,
42
+ message: 'Plugin management is not available.',
43
+ };
44
+ }
45
+
46
+ try {
47
+ return {
48
+ success: true,
49
+ message: await operation(adapter),
50
+ };
51
+ } catch (error) {
52
+ const message = error instanceof Error ? error.message : String(error);
53
+ return {
54
+ success: false,
55
+ message: `Plugin error: ${message}`,
56
+ };
57
+ }
58
+ }
59
+
60
+ async function executeMarketplaceCommand(
61
+ context: ICommandHostContext,
62
+ subArgs: string,
63
+ ): Promise<ICommandResult> {
64
+ const { subcommand, subArgs: marketplaceArgs } = getSubcommandParts(subArgs);
65
+
66
+ if (subcommand === 'add' && marketplaceArgs.length > 0) {
67
+ return executePluginOperation(context, async (adapter) => {
68
+ const registeredName = await adapter.marketplaceAdd(marketplaceArgs);
69
+ return `Added marketplace: "${registeredName}" (from ${marketplaceArgs})\nInstall plugins with: /plugin install <name>@${registeredName}`;
70
+ });
71
+ }
72
+
73
+ if (subcommand === 'remove' && marketplaceArgs.length > 0) {
74
+ return executePluginOperation(context, async (adapter) => {
75
+ await adapter.marketplaceRemove(marketplaceArgs);
76
+ return `Removed marketplace "${marketplaceArgs}" and uninstalled its plugins.`;
77
+ });
78
+ }
79
+
80
+ if (subcommand === 'update' && marketplaceArgs.length > 0) {
81
+ return executePluginOperation(context, async (adapter) => {
82
+ await adapter.marketplaceUpdate(marketplaceArgs);
83
+ return `Updated marketplace "${marketplaceArgs}".`;
84
+ });
85
+ }
86
+
87
+ if (subcommand === 'list') {
88
+ return executePluginOperation(context, async (adapter) => {
89
+ const sources = await adapter.marketplaceList();
90
+ if (sources.length === 0) {
91
+ return 'No marketplace sources configured.';
92
+ }
93
+ const lines = sources.map((source) => ` ${source.name} (${source.type})`);
94
+ return `Marketplace sources:\n${lines.join('\n')}`;
95
+ });
96
+ }
97
+
98
+ return usage('Usage: /plugin marketplace add <source> | remove <name> | update <name> | list');
99
+ }
100
+
101
+ type TPluginIdOperation = (
102
+ adapter: ICommandPluginAdapter,
103
+ pluginId: string,
104
+ ) => Promise<string> | string;
105
+
106
+ function executePluginIdOperation(
107
+ context: ICommandHostContext,
108
+ pluginId: string,
109
+ usageMessage: string,
110
+ operation: TPluginIdOperation,
111
+ ): Promise<ICommandResult> {
112
+ if (pluginId.length === 0) {
113
+ return Promise.resolve(usage(usageMessage));
114
+ }
115
+ return executePluginOperation(context, (adapter) =>
116
+ Promise.resolve(operation(adapter, pluginId)),
117
+ );
118
+ }
119
+
120
+ function executePluginManager(): ICommandResult {
121
+ return {
122
+ success: true,
123
+ message: 'Opening plugin manager...',
124
+ effects: [createPluginTuiRequestedEffect()],
125
+ };
126
+ }
127
+
128
+ function executeInstallCommand(
129
+ context: ICommandHostContext,
130
+ pluginId: string,
131
+ ): Promise<ICommandResult> {
132
+ return executePluginIdOperation(
133
+ context,
134
+ pluginId,
135
+ 'Usage: /plugin install <name>@<marketplace>',
136
+ async (adapter, targetPluginId) => {
137
+ await adapter.install(targetPluginId);
138
+ return `Installed plugin: ${targetPluginId}`;
139
+ },
140
+ );
141
+ }
142
+
143
+ function executeUninstallCommand(
144
+ context: ICommandHostContext,
145
+ pluginId: string,
146
+ ): Promise<ICommandResult> {
147
+ return executePluginIdOperation(
148
+ context,
149
+ pluginId,
150
+ 'Usage: /plugin uninstall <name>@<marketplace>',
151
+ async (adapter, targetPluginId) => {
152
+ await adapter.uninstall(targetPluginId);
153
+ return `Uninstalled plugin: ${targetPluginId}`;
154
+ },
155
+ );
156
+ }
157
+
158
+ function executeEnableCommand(
159
+ context: ICommandHostContext,
160
+ pluginId: string,
161
+ ): Promise<ICommandResult> {
162
+ return executePluginIdOperation(
163
+ context,
164
+ pluginId,
165
+ 'Usage: /plugin enable <name>@<marketplace>',
166
+ async (adapter, targetPluginId) => {
167
+ await adapter.enable(targetPluginId);
168
+ return `Enabled plugin: ${targetPluginId}`;
169
+ },
170
+ );
171
+ }
172
+
173
+ function executeDisableCommand(
174
+ context: ICommandHostContext,
175
+ pluginId: string,
176
+ ): Promise<ICommandResult> {
177
+ return executePluginIdOperation(
178
+ context,
179
+ pluginId,
180
+ 'Usage: /plugin disable <name>@<marketplace>',
181
+ async (adapter, targetPluginId) => {
182
+ await adapter.disable(targetPluginId);
183
+ return `Disabled plugin: ${targetPluginId}`;
184
+ },
185
+ );
186
+ }
187
+
188
+ export async function executePluginCommand(
189
+ context: ICommandHostContext,
190
+ args: string,
191
+ ): Promise<ICommandResult> {
192
+ const { subcommand, subArgs } = getSubcommandParts(args);
193
+ switch (subcommand) {
194
+ case '':
195
+ case 'manage':
196
+ return executePluginManager();
197
+ case 'install':
198
+ return executeInstallCommand(context, subArgs);
199
+ case 'uninstall':
200
+ return executeUninstallCommand(context, subArgs);
201
+ case 'enable':
202
+ return executeEnableCommand(context, subArgs);
203
+ case 'disable':
204
+ return executeDisableCommand(context, subArgs);
205
+ case 'marketplace':
206
+ return executeMarketplaceCommand(context, subArgs);
207
+ default:
208
+ return usage(`Unknown plugin subcommand: ${subcommand}`);
209
+ }
210
+ }
211
+
212
+ export async function executeReloadPluginsCommand(
213
+ context: ICommandHostContext,
214
+ _args: string,
215
+ ): Promise<ICommandResult> {
216
+ return executePluginOperation(context, async (adapter) => {
217
+ const result = await adapter.reloadPlugins();
218
+ const suffix =
219
+ result.loadedPluginCount === 1
220
+ ? '1 plugin resource'
221
+ : `${result.loadedPluginCount} plugin resources`;
222
+ return `Reloaded ${suffix}.`;
223
+ }).then((result) => {
224
+ if (!result.success) return result;
225
+ return {
226
+ ...result,
227
+ effects: [createPluginRegistryReloadRequestedEffect()],
228
+ };
229
+ });
230
+ }