@qwen-code/qwen-code 0.0.2 → 0.0.4-nightly.1
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/package.json +6 -4
- package/dist/qwen-code-qwen-code-0.0.3.tgz +0 -0
- package/dist/src/acp/acp.d.ts +208 -0
- package/dist/src/acp/acp.js +193 -0
- package/dist/src/acp/acp.js.map +1 -0
- package/dist/src/acp/acpPeer.d.ts +8 -0
- package/dist/src/acp/acpPeer.js +537 -0
- package/dist/src/acp/acpPeer.js.map +1 -0
- package/dist/src/config/config.d.ts +5 -2
- package/dist/src/config/config.js +70 -28
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/extension.d.ts +2 -2
- package/dist/src/config/extension.js +21 -16
- package/dist/src/config/extension.js.map +1 -1
- package/dist/src/config/settings.d.ts +22 -15
- package/dist/src/config/settings.js +25 -10
- package/dist/src/config/settings.js.map +1 -1
- package/dist/src/gemini.d.ts +1 -0
- package/dist/src/gemini.js +31 -49
- package/dist/src/gemini.js.map +1 -1
- package/dist/src/generated/git-commit.d.ts +1 -1
- package/dist/src/generated/git-commit.js +1 -1
- package/dist/src/generated/git-commit.js.map +1 -1
- package/dist/src/nonInteractiveCli.js +0 -67
- package/dist/src/nonInteractiveCli.js.map +1 -1
- package/dist/src/patches/is-in-ci.d.ts +7 -0
- package/dist/src/patches/is-in-ci.js +15 -0
- package/dist/src/patches/is-in-ci.js.map +1 -0
- package/dist/src/services/BuiltinCommandLoader.d.ts +24 -0
- package/dist/src/services/BuiltinCommandLoader.js +72 -0
- package/dist/src/services/BuiltinCommandLoader.js.map +1 -0
- package/dist/src/services/CommandService.d.ts +43 -5
- package/dist/src/services/CommandService.js +61 -25
- package/dist/src/services/CommandService.js.map +1 -1
- package/dist/src/services/FileCommandLoader.d.ts +37 -0
- package/dist/src/services/FileCommandLoader.js +179 -0
- package/dist/src/services/FileCommandLoader.js.map +1 -0
- package/dist/src/services/McpPromptLoader.d.ts +25 -0
- package/dist/src/services/McpPromptLoader.js +192 -0
- package/dist/src/services/McpPromptLoader.js.map +1 -0
- package/dist/src/services/prompt-processors/argumentProcessor.d.ts +21 -0
- package/dist/src/services/prompt-processors/argumentProcessor.js +28 -0
- package/dist/src/services/prompt-processors/argumentProcessor.js.map +1 -0
- package/dist/src/services/prompt-processors/shellProcessor.d.ts +32 -0
- package/dist/src/services/prompt-processors/shellProcessor.js +77 -0
- package/dist/src/services/prompt-processors/shellProcessor.js.map +1 -0
- package/dist/src/services/prompt-processors/types.d.ts +38 -0
- package/dist/src/services/prompt-processors/types.js +14 -0
- package/dist/src/services/prompt-processors/types.js.map +1 -0
- package/dist/src/services/types.d.ts +22 -0
- package/dist/src/services/types.js +7 -0
- package/dist/src/services/types.js.map +1 -0
- package/dist/src/ui/App.js +130 -101
- package/dist/src/ui/App.js.map +1 -1
- package/dist/src/ui/colors.js +6 -0
- package/dist/src/ui/colors.js.map +1 -1
- package/dist/src/ui/commands/aboutCommand.js +2 -0
- package/dist/src/ui/commands/aboutCommand.js.map +1 -1
- package/dist/src/ui/commands/authCommand.js +2 -0
- package/dist/src/ui/commands/authCommand.js.map +1 -1
- package/dist/src/ui/commands/bugCommand.d.ts +7 -0
- package/dist/src/ui/commands/bugCommand.js +63 -0
- package/dist/src/ui/commands/bugCommand.js.map +1 -0
- package/dist/src/ui/commands/chatCommand.d.ts +7 -0
- package/dist/src/ui/commands/chatCommand.js +179 -0
- package/dist/src/ui/commands/chatCommand.js.map +1 -0
- package/dist/src/ui/commands/clearCommand.js +14 -2
- package/dist/src/ui/commands/clearCommand.js.map +1 -1
- package/dist/src/ui/commands/compressCommand.d.ts +7 -0
- package/dist/src/ui/commands/compressCommand.js +64 -0
- package/dist/src/ui/commands/compressCommand.js.map +1 -0
- package/dist/src/ui/commands/copyCommand.d.ts +7 -0
- package/dist/src/ui/commands/copyCommand.js +59 -0
- package/dist/src/ui/commands/copyCommand.js.map +1 -0
- package/dist/src/ui/commands/corgiCommand.d.ts +7 -0
- package/dist/src/ui/commands/corgiCommand.js +15 -0
- package/dist/src/ui/commands/corgiCommand.js.map +1 -0
- package/dist/src/ui/commands/docsCommand.d.ts +7 -0
- package/dist/src/ui/commands/docsCommand.js +31 -0
- package/dist/src/ui/commands/docsCommand.js.map +1 -0
- package/dist/src/ui/commands/editorCommand.d.ts +7 -0
- package/dist/src/ui/commands/editorCommand.js +16 -0
- package/dist/src/ui/commands/editorCommand.js.map +1 -0
- package/dist/src/ui/commands/extensionsCommand.d.ts +7 -0
- package/dist/src/ui/commands/extensionsCommand.js +31 -0
- package/dist/src/ui/commands/extensionsCommand.js.map +1 -0
- package/dist/src/ui/commands/helpCommand.js +4 -2
- package/dist/src/ui/commands/helpCommand.js.map +1 -1
- package/dist/src/ui/commands/ideCommand.d.ts +8 -0
- package/dist/src/ui/commands/ideCommand.js +121 -0
- package/dist/src/ui/commands/ideCommand.js.map +1 -0
- package/dist/src/ui/commands/mcpCommand.d.ts +7 -0
- package/dist/src/ui/commands/mcpCommand.js +425 -0
- package/dist/src/ui/commands/mcpCommand.js.map +1 -0
- package/dist/src/ui/commands/memoryCommand.js +11 -4
- package/dist/src/ui/commands/memoryCommand.js.map +1 -1
- package/dist/src/ui/commands/privacyCommand.js +2 -0
- package/dist/src/ui/commands/privacyCommand.js.map +1 -1
- package/dist/src/ui/commands/quitCommand.d.ts +7 -0
- package/dist/src/ui/commands/quitCommand.js +34 -0
- package/dist/src/ui/commands/quitCommand.js.map +1 -0
- package/dist/src/ui/commands/restoreCommand.d.ts +8 -0
- package/dist/src/ui/commands/restoreCommand.js +128 -0
- package/dist/src/ui/commands/restoreCommand.js.map +1 -0
- package/dist/src/ui/commands/statsCommand.d.ts +7 -0
- package/dist/src/ui/commands/statsCommand.js +54 -0
- package/dist/src/ui/commands/statsCommand.js.map +1 -0
- package/dist/src/ui/commands/themeCommand.js +2 -0
- package/dist/src/ui/commands/themeCommand.js.map +1 -1
- package/dist/src/ui/commands/toolsCommand.d.ts +7 -0
- package/dist/src/ui/commands/toolsCommand.js +56 -0
- package/dist/src/ui/commands/toolsCommand.js.map +1 -0
- package/dist/src/ui/commands/types.d.ts +76 -4
- package/dist/src/ui/commands/types.js +6 -1
- package/dist/src/ui/commands/types.js.map +1 -1
- package/dist/src/ui/commands/vimCommand.d.ts +7 -0
- package/dist/src/ui/commands/vimCommand.js +23 -0
- package/dist/src/ui/commands/vimCommand.js.map +1 -0
- package/dist/src/ui/components/AuthDialog.js +0 -1
- package/dist/src/ui/components/AuthDialog.js.map +1 -1
- package/dist/src/ui/components/ContextSummaryDisplay.d.ts +6 -1
- package/dist/src/ui/components/ContextSummaryDisplay.js +46 -19
- package/dist/src/ui/components/ContextSummaryDisplay.js.map +1 -1
- package/dist/src/ui/components/Footer.d.ts +1 -0
- package/dist/src/ui/components/Footer.js +2 -2
- package/dist/src/ui/components/Footer.js.map +1 -1
- package/dist/src/ui/components/Header.js +1 -1
- package/dist/src/ui/components/Header.js.map +1 -1
- package/dist/src/ui/components/Help.d.ts +1 -1
- package/dist/src/ui/components/IDEContextDetailDisplay.d.ts +11 -0
- package/dist/src/ui/components/IDEContextDetailDisplay.js +19 -0
- package/dist/src/ui/components/IDEContextDetailDisplay.js.map +1 -0
- package/dist/src/ui/components/InputPrompt.d.ts +3 -1
- package/dist/src/ui/components/InputPrompt.js +86 -123
- package/dist/src/ui/components/InputPrompt.js.map +1 -1
- package/dist/src/ui/components/ShellConfirmationDialog.d.ts +15 -0
- package/dist/src/ui/components/ShellConfirmationDialog.js +44 -0
- package/dist/src/ui/components/ShellConfirmationDialog.js.map +1 -0
- package/dist/src/ui/components/ThemeDialog.js +51 -25
- package/dist/src/ui/components/ThemeDialog.js.map +1 -1
- package/dist/src/ui/components/Tips.js +1 -1
- package/dist/src/ui/components/Tips.js.map +1 -1
- package/dist/src/ui/components/messages/DiffRenderer.d.ts +1 -0
- package/dist/src/ui/components/messages/DiffRenderer.js +12 -11
- package/dist/src/ui/components/messages/DiffRenderer.js.map +1 -1
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js +5 -4
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
- package/dist/src/ui/components/messages/ToolGroupMessage.js +3 -1
- package/dist/src/ui/components/messages/ToolGroupMessage.js.map +1 -1
- package/dist/src/ui/components/shared/MaxSizedBox.js +69 -2
- package/dist/src/ui/components/shared/MaxSizedBox.js.map +1 -1
- package/dist/src/ui/components/shared/RadioButtonSelect.d.ts +3 -1
- package/dist/src/ui/components/shared/RadioButtonSelect.js +69 -50
- package/dist/src/ui/components/shared/RadioButtonSelect.js.map +1 -1
- package/dist/src/ui/components/shared/text-buffer.d.ts +273 -3
- package/dist/src/ui/components/shared/text-buffer.js +426 -80
- package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
- package/dist/src/ui/components/shared/vim-buffer-actions.d.ts +72 -0
- package/dist/src/ui/components/shared/vim-buffer-actions.js +565 -0
- package/dist/src/ui/components/shared/vim-buffer-actions.js.map +1 -0
- package/dist/src/ui/constants.d.ts +1 -0
- package/dist/src/ui/constants.js +1 -0
- package/dist/src/ui/constants.js.map +1 -1
- package/dist/src/ui/contexts/VimModeContext.d.ts +19 -0
- package/dist/src/ui/contexts/VimModeContext.js +48 -0
- package/dist/src/ui/contexts/VimModeContext.js.map +1 -0
- package/dist/src/ui/hooks/atCommandProcessor.js +54 -15
- package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/shellCommandProcessor.d.ts +2 -1
- package/dist/src/ui/hooks/shellCommandProcessor.js +154 -177
- package/dist/src/ui/hooks/shellCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/slashCommandProcessor.d.ts +9 -12
- package/dist/src/ui/hooks/slashCommandProcessor.js +203 -880
- package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/useAuthCommand.js +2 -1
- package/dist/src/ui/hooks/useAuthCommand.js.map +1 -1
- package/dist/src/ui/hooks/useCompletion.d.ts +4 -1
- package/dist/src/ui/hooks/useCompletion.js +137 -24
- package/dist/src/ui/hooks/useCompletion.js.map +1 -1
- package/dist/src/ui/hooks/useConsoleMessages.js +53 -37
- package/dist/src/ui/hooks/useConsoleMessages.js.map +1 -1
- package/dist/src/ui/hooks/useFocus.d.ts +6 -0
- package/dist/src/ui/hooks/useFocus.js +41 -0
- package/dist/src/ui/hooks/useFocus.js.map +1 -0
- package/dist/src/ui/hooks/useGeminiStream.js +57 -11
- package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
- package/dist/src/ui/hooks/useInputHistory.d.ts +1 -1
- package/dist/src/ui/hooks/useKeypress.js +5 -2
- package/dist/src/ui/hooks/useKeypress.js.map +1 -1
- package/dist/src/ui/hooks/usePrivacySettings.js +5 -5
- package/dist/src/ui/hooks/usePrivacySettings.js.map +1 -1
- package/dist/src/ui/hooks/useShellHistory.d.ts +3 -2
- package/dist/src/ui/hooks/useShellHistory.js.map +1 -1
- package/dist/src/ui/hooks/useThemeCommand.js +24 -23
- package/dist/src/ui/hooks/useThemeCommand.js.map +1 -1
- package/dist/src/ui/hooks/vim.d.ts +28 -0
- package/dist/src/ui/hooks/vim.js +630 -0
- package/dist/src/ui/hooks/vim.js.map +1 -0
- package/dist/src/ui/themes/ansi-light.js +3 -1
- package/dist/src/ui/themes/ansi-light.js.map +1 -1
- package/dist/src/ui/themes/ansi.js +2 -0
- package/dist/src/ui/themes/ansi.js.map +1 -1
- package/dist/src/ui/themes/atom-one-dark.js +2 -0
- package/dist/src/ui/themes/atom-one-dark.js.map +1 -1
- package/dist/src/ui/themes/ayu-light.js +3 -1
- package/dist/src/ui/themes/ayu-light.js.map +1 -1
- package/dist/src/ui/themes/ayu.js +3 -1
- package/dist/src/ui/themes/ayu.js.map +1 -1
- package/dist/src/ui/themes/color-utils.d.ts +21 -0
- package/dist/src/ui/themes/color-utils.js +221 -0
- package/dist/src/ui/themes/color-utils.js.map +1 -0
- package/dist/src/ui/themes/dracula.js +2 -0
- package/dist/src/ui/themes/dracula.js.map +1 -1
- package/dist/src/ui/themes/github-dark.js +2 -0
- package/dist/src/ui/themes/github-dark.js.map +1 -1
- package/dist/src/ui/themes/github-light.js +2 -0
- package/dist/src/ui/themes/github-light.js.map +1 -1
- package/dist/src/ui/themes/googlecode.js +3 -1
- package/dist/src/ui/themes/googlecode.js.map +1 -1
- package/dist/src/ui/themes/no-color.js +3 -1
- package/dist/src/ui/themes/no-color.js.map +1 -1
- package/dist/src/ui/themes/qwen-dark.js +2 -0
- package/dist/src/ui/themes/qwen-dark.js.map +1 -1
- package/dist/src/ui/themes/qwen-light.js +2 -0
- package/dist/src/ui/themes/qwen-light.js.map +1 -1
- package/dist/src/ui/themes/shades-of-purple.d.ts +1 -1
- package/dist/src/ui/themes/shades-of-purple.js +3 -1
- package/dist/src/ui/themes/shades-of-purple.js.map +1 -1
- package/dist/src/ui/themes/theme-manager.d.ts +31 -6
- package/dist/src/ui/themes/theme-manager.js +114 -37
- package/dist/src/ui/themes/theme-manager.js.map +1 -1
- package/dist/src/ui/themes/theme.d.ts +23 -3
- package/dist/src/ui/themes/theme.js +244 -182
- package/dist/src/ui/themes/theme.js.map +1 -1
- package/dist/src/ui/themes/xcode.js +3 -1
- package/dist/src/ui/themes/xcode.js.map +1 -1
- package/dist/src/ui/types.d.ts +9 -1
- package/dist/src/ui/utils/CodeColorizer.d.ts +3 -1
- package/dist/src/ui/utils/CodeColorizer.js +23 -11
- package/dist/src/ui/utils/CodeColorizer.js.map +1 -1
- package/dist/src/ui/utils/commandUtils.d.ts +1 -0
- package/dist/src/ui/utils/commandUtils.js +47 -0
- package/dist/src/ui/utils/commandUtils.js.map +1 -1
- package/dist/src/ui/utils/errorParsing.js.map +1 -1
- package/dist/src/ui/utils/markdownUtilities.js +1 -1
- package/dist/src/ui/utils/textUtils.d.ts +0 -8
- package/dist/src/ui/utils/textUtils.js +0 -22
- package/dist/src/ui/utils/textUtils.js.map +1 -1
- package/dist/src/ui/utils/updateCheck.js +5 -1
- package/dist/src/ui/utils/updateCheck.js.map +1 -1
- package/dist/src/utils/events.d.ts +11 -0
- package/dist/src/utils/events.js +13 -0
- package/dist/src/utils/events.js.map +1 -0
- package/dist/src/utils/sandbox.js +7 -3
- package/dist/src/utils/sandbox.js.map +1 -1
- package/dist/src/utils/userStartupWarnings.js +16 -10
- package/dist/src/utils/userStartupWarnings.js.map +1 -1
- package/dist/src/validateNonInterActiveAuth.d.ts +7 -0
- package/dist/src/validateNonInterActiveAuth.js +38 -0
- package/dist/src/validateNonInterActiveAuth.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -5
|
@@ -4,24 +4,23 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import { useCallback, useMemo, useEffect, useState } from 'react';
|
|
7
|
-
import open from 'open';
|
|
8
7
|
import process from 'node:process';
|
|
9
8
|
import { useStateAndRef } from './useStateAndRef.js';
|
|
10
|
-
import { GitService, Logger,
|
|
9
|
+
import { GitService, Logger, ToolConfirmationOutcome, } from '@qwen-code/qwen-code-core';
|
|
11
10
|
import { useSessionStats } from '../contexts/SessionContext.js';
|
|
12
11
|
import { MessageType, } from '../types.js';
|
|
13
|
-
import { promises as fs } from 'fs';
|
|
14
|
-
import path from 'path';
|
|
15
|
-
import { GIT_COMMIT_INFO } from '../../generated/git-commit.js';
|
|
16
|
-
import { formatDuration, formatMemoryUsage } from '../utils/formatters.js';
|
|
17
|
-
import { getCliVersion } from '../../utils/version.js';
|
|
18
12
|
import { CommandService } from '../../services/CommandService.js';
|
|
13
|
+
import { BuiltinCommandLoader } from '../../services/BuiltinCommandLoader.js';
|
|
14
|
+
import { FileCommandLoader } from '../../services/FileCommandLoader.js';
|
|
15
|
+
import { McpPromptLoader } from '../../services/McpPromptLoader.js';
|
|
19
16
|
/**
|
|
20
17
|
* Hook to define and process slash commands (e.g., /help, /clear).
|
|
21
18
|
*/
|
|
22
|
-
export const useSlashCommandProcessor = (config, settings,
|
|
19
|
+
export const useSlashCommandProcessor = (config, settings, addItem, clearItems, loadHistory, refreshStatic, setShowHelp, onDebugMessage, openThemeDialog, openAuthDialog, openEditorDialog, toggleCorgiMode, setQuittingMessages, openPrivacyNotice, toggleVimEnabled, setIsProcessing) => {
|
|
23
20
|
const session = useSessionStats();
|
|
24
21
|
const [commands, setCommands] = useState([]);
|
|
22
|
+
const [shellConfirmationRequest, setShellConfirmationRequest] = useState(null);
|
|
23
|
+
const [sessionShellAllowlist, setSessionShellAllowlist] = useState(new Set());
|
|
25
24
|
const gitService = useMemo(() => {
|
|
26
25
|
if (!config?.getProjectRoot()) {
|
|
27
26
|
return;
|
|
@@ -106,10 +105,16 @@ export const useSlashCommandProcessor = (config, settings, history, addItem, cle
|
|
|
106
105
|
console.clear();
|
|
107
106
|
refreshStatic();
|
|
108
107
|
},
|
|
108
|
+
loadHistory,
|
|
109
109
|
setDebugMessage: onDebugMessage,
|
|
110
|
+
pendingItem: pendingCompressionItemRef.current,
|
|
111
|
+
setPendingItem: setPendingCompressionItem,
|
|
112
|
+
toggleCorgiMode,
|
|
113
|
+
toggleVimEnabled,
|
|
110
114
|
},
|
|
111
115
|
session: {
|
|
112
116
|
stats: session.stats,
|
|
117
|
+
sessionShellAllowlist,
|
|
113
118
|
resetSession: session.resetSession,
|
|
114
119
|
},
|
|
115
120
|
}), [
|
|
@@ -117,926 +122,244 @@ export const useSlashCommandProcessor = (config, settings, history, addItem, cle
|
|
|
117
122
|
settings,
|
|
118
123
|
gitService,
|
|
119
124
|
logger,
|
|
125
|
+
loadHistory,
|
|
120
126
|
addItem,
|
|
121
127
|
clearItems,
|
|
122
128
|
refreshStatic,
|
|
123
129
|
session.stats,
|
|
124
130
|
session.resetSession,
|
|
125
131
|
onDebugMessage,
|
|
132
|
+
pendingCompressionItemRef,
|
|
133
|
+
setPendingCompressionItem,
|
|
134
|
+
toggleCorgiMode,
|
|
135
|
+
toggleVimEnabled,
|
|
136
|
+
sessionShellAllowlist,
|
|
126
137
|
]);
|
|
127
|
-
const commandService = useMemo(() => new CommandService(), []);
|
|
128
138
|
useEffect(() => {
|
|
139
|
+
const controller = new AbortController();
|
|
129
140
|
const load = async () => {
|
|
130
|
-
|
|
141
|
+
const loaders = [
|
|
142
|
+
new McpPromptLoader(config),
|
|
143
|
+
new BuiltinCommandLoader(config),
|
|
144
|
+
new FileCommandLoader(config),
|
|
145
|
+
];
|
|
146
|
+
const commandService = await CommandService.create(loaders, controller.signal);
|
|
131
147
|
setCommands(commandService.getCommands());
|
|
132
148
|
};
|
|
133
149
|
load();
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if (!geminiDir) {
|
|
138
|
-
return [];
|
|
139
|
-
}
|
|
140
|
-
try {
|
|
141
|
-
const files = await fs.readdir(geminiDir);
|
|
142
|
-
return files
|
|
143
|
-
.filter((file) => file.startsWith('checkpoint-') && file.endsWith('.json'))
|
|
144
|
-
.map((file) => file.replace('checkpoint-', '').replace('.json', ''));
|
|
145
|
-
}
|
|
146
|
-
catch (_err) {
|
|
147
|
-
return [];
|
|
148
|
-
}
|
|
150
|
+
return () => {
|
|
151
|
+
controller.abort();
|
|
152
|
+
};
|
|
149
153
|
}, [config]);
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
154
|
+
const handleSlashCommand = useCallback(async (rawQuery, oneTimeShellAllowlist) => {
|
|
155
|
+
setIsProcessing(true);
|
|
156
|
+
try {
|
|
157
|
+
if (typeof rawQuery !== 'string') {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
const trimmed = rawQuery.trim();
|
|
161
|
+
if (!trimmed.startsWith('/') && !trimmed.startsWith('?')) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
const userMessageTimestamp = Date.now();
|
|
165
|
+
addItem({ type: MessageType.USER, text: trimmed }, userMessageTimestamp);
|
|
166
|
+
const parts = trimmed.substring(1).trim().split(/\s+/);
|
|
167
|
+
const commandPath = parts.filter((p) => p); // The parts of the command, e.g., ['memory', 'add']
|
|
168
|
+
let currentCommands = commands;
|
|
169
|
+
let commandToExecute;
|
|
170
|
+
let pathIndex = 0;
|
|
171
|
+
for (const part of commandPath) {
|
|
172
|
+
// TODO: For better performance and architectural clarity, this two-pass
|
|
173
|
+
// search could be replaced. A more optimal approach would be to
|
|
174
|
+
// pre-compute a single lookup map in `CommandService.ts` that resolves
|
|
175
|
+
// all name and alias conflicts during the initial loading phase. The
|
|
176
|
+
// processor would then perform a single, fast lookup on that map.
|
|
177
|
+
// First pass: check for an exact match on the primary command name.
|
|
178
|
+
let foundCommand = currentCommands.find((cmd) => cmd.name === part);
|
|
179
|
+
// Second pass: if no primary name matches, check for an alias.
|
|
180
|
+
if (!foundCommand) {
|
|
181
|
+
foundCommand = currentCommands.find((cmd) => cmd.altNames?.includes(part));
|
|
182
|
+
}
|
|
183
|
+
if (foundCommand) {
|
|
184
|
+
commandToExecute = foundCommand;
|
|
185
|
+
pathIndex++;
|
|
186
|
+
if (foundCommand.subCommands) {
|
|
187
|
+
currentCommands = foundCommand.subCommands;
|
|
167
188
|
}
|
|
168
189
|
else {
|
|
169
|
-
|
|
170
|
-
type: MessageType.INFO,
|
|
171
|
-
content: `Opening documentation in your browser: ${docsUrl}`,
|
|
172
|
-
timestamp: new Date(),
|
|
173
|
-
});
|
|
174
|
-
await open(docsUrl);
|
|
175
|
-
}
|
|
176
|
-
},
|
|
177
|
-
},
|
|
178
|
-
{
|
|
179
|
-
name: 'editor',
|
|
180
|
-
description: 'set external editor preference',
|
|
181
|
-
action: (_mainCommand, _subCommand, _args) => openEditorDialog(),
|
|
182
|
-
},
|
|
183
|
-
{
|
|
184
|
-
name: 'stats',
|
|
185
|
-
altName: 'usage',
|
|
186
|
-
description: 'check session stats. Usage: /stats [model|tools]',
|
|
187
|
-
action: (_mainCommand, subCommand, _args) => {
|
|
188
|
-
if (subCommand === 'model') {
|
|
189
|
-
addMessage({
|
|
190
|
-
type: MessageType.MODEL_STATS,
|
|
191
|
-
timestamp: new Date(),
|
|
192
|
-
});
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
else if (subCommand === 'tools') {
|
|
196
|
-
addMessage({
|
|
197
|
-
type: MessageType.TOOL_STATS,
|
|
198
|
-
timestamp: new Date(),
|
|
199
|
-
});
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
const now = new Date();
|
|
203
|
-
const { sessionStartTime } = session.stats;
|
|
204
|
-
const wallDuration = now.getTime() - sessionStartTime.getTime();
|
|
205
|
-
addMessage({
|
|
206
|
-
type: MessageType.STATS,
|
|
207
|
-
duration: formatDuration(wallDuration),
|
|
208
|
-
timestamp: new Date(),
|
|
209
|
-
});
|
|
210
|
-
},
|
|
211
|
-
},
|
|
212
|
-
{
|
|
213
|
-
name: 'mcp',
|
|
214
|
-
description: 'list configured MCP servers and tools',
|
|
215
|
-
action: async (_mainCommand, _subCommand, _args) => {
|
|
216
|
-
// Check if the _subCommand includes a specific flag to control description visibility
|
|
217
|
-
let useShowDescriptions = showToolDescriptions;
|
|
218
|
-
if (_subCommand === 'desc' || _subCommand === 'descriptions') {
|
|
219
|
-
useShowDescriptions = true;
|
|
190
|
+
break;
|
|
220
191
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
if (serverNames.length === 0) {
|
|
248
|
-
const docsUrl = 'https://goo.gle/gemini-cli-docs-mcp';
|
|
249
|
-
if (process.env.SANDBOX && process.env.SANDBOX !== 'sandbox-exec') {
|
|
250
|
-
addMessage({
|
|
251
|
-
type: MessageType.INFO,
|
|
252
|
-
content: `No MCP servers configured. Please open the following URL in your browser to view documentation:\n${docsUrl}`,
|
|
253
|
-
timestamp: new Date(),
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
else {
|
|
257
|
-
addMessage({
|
|
258
|
-
type: MessageType.INFO,
|
|
259
|
-
content: `No MCP servers configured. Opening documentation in your browser: ${docsUrl}`,
|
|
260
|
-
timestamp: new Date(),
|
|
261
|
-
});
|
|
262
|
-
await open(docsUrl);
|
|
263
|
-
}
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
// Check if any servers are still connecting
|
|
267
|
-
const connectingServers = serverNames.filter((name) => getMCPServerStatus(name) === MCPServerStatus.CONNECTING);
|
|
268
|
-
const discoveryState = getMCPDiscoveryState();
|
|
269
|
-
let message = '';
|
|
270
|
-
// Add overall discovery status message if needed
|
|
271
|
-
if (discoveryState === MCPDiscoveryState.IN_PROGRESS ||
|
|
272
|
-
connectingServers.length > 0) {
|
|
273
|
-
message += `\u001b[33m⏳ MCP servers are starting up (${connectingServers.length} initializing)...\u001b[0m\n`;
|
|
274
|
-
message += `\u001b[90mNote: First startup may take longer. Tool availability will update automatically.\u001b[0m\n\n`;
|
|
275
|
-
}
|
|
276
|
-
message += 'Configured MCP servers:\n\n';
|
|
277
|
-
for (const serverName of serverNames) {
|
|
278
|
-
const serverTools = toolRegistry.getToolsByServer(serverName);
|
|
279
|
-
const status = getMCPServerStatus(serverName);
|
|
280
|
-
// Add status indicator with descriptive text
|
|
281
|
-
let statusIndicator = '';
|
|
282
|
-
let statusText = '';
|
|
283
|
-
switch (status) {
|
|
284
|
-
case MCPServerStatus.CONNECTED:
|
|
285
|
-
statusIndicator = '🟢';
|
|
286
|
-
statusText = 'Ready';
|
|
287
|
-
break;
|
|
288
|
-
case MCPServerStatus.CONNECTING:
|
|
289
|
-
statusIndicator = '🔄';
|
|
290
|
-
statusText = 'Starting... (first startup may take longer)';
|
|
291
|
-
break;
|
|
292
|
-
case MCPServerStatus.DISCONNECTED:
|
|
293
|
-
default:
|
|
294
|
-
statusIndicator = '🔴';
|
|
295
|
-
statusText = 'Disconnected';
|
|
296
|
-
break;
|
|
297
|
-
}
|
|
298
|
-
// Get server description if available
|
|
299
|
-
const server = mcpServers[serverName];
|
|
300
|
-
// Format server header with bold formatting and status
|
|
301
|
-
message += `${statusIndicator} \u001b[1m${serverName}\u001b[0m - ${statusText}`;
|
|
302
|
-
// Add tool count with conditional messaging
|
|
303
|
-
if (status === MCPServerStatus.CONNECTED) {
|
|
304
|
-
message += ` (${serverTools.length} tools)`;
|
|
305
|
-
}
|
|
306
|
-
else if (status === MCPServerStatus.CONNECTING) {
|
|
307
|
-
message += ` (tools will appear when ready)`;
|
|
308
|
-
}
|
|
309
|
-
else {
|
|
310
|
-
message += ` (${serverTools.length} tools cached)`;
|
|
311
|
-
}
|
|
312
|
-
// Add server description with proper handling of multi-line descriptions
|
|
313
|
-
if ((useShowDescriptions || useShowSchema) && server?.description) {
|
|
314
|
-
const greenColor = '\u001b[32m';
|
|
315
|
-
const resetColor = '\u001b[0m';
|
|
316
|
-
const descLines = server.description.trim().split('\n');
|
|
317
|
-
if (descLines) {
|
|
318
|
-
message += ':\n';
|
|
319
|
-
for (const descLine of descLines) {
|
|
320
|
-
message += ` ${greenColor}${descLine}${resetColor}\n`;
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
else {
|
|
324
|
-
message += '\n';
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
else {
|
|
328
|
-
message += '\n';
|
|
329
|
-
}
|
|
330
|
-
// Reset formatting after server entry
|
|
331
|
-
message += '\u001b[0m';
|
|
332
|
-
if (serverTools.length > 0) {
|
|
333
|
-
serverTools.forEach((tool) => {
|
|
334
|
-
if ((useShowDescriptions || useShowSchema) &&
|
|
335
|
-
tool.description) {
|
|
336
|
-
// Format tool name in cyan using simple ANSI cyan color
|
|
337
|
-
message += ` - \u001b[36m${tool.name}\u001b[0m`;
|
|
338
|
-
// Apply green color to the description text
|
|
339
|
-
const greenColor = '\u001b[32m';
|
|
340
|
-
const resetColor = '\u001b[0m';
|
|
341
|
-
// Handle multi-line descriptions by properly indenting and preserving formatting
|
|
342
|
-
const descLines = tool.description.trim().split('\n');
|
|
343
|
-
if (descLines) {
|
|
344
|
-
message += ':\n';
|
|
345
|
-
for (const descLine of descLines) {
|
|
346
|
-
message += ` ${greenColor}${descLine}${resetColor}\n`;
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
else {
|
|
350
|
-
message += '\n';
|
|
351
|
-
}
|
|
352
|
-
// Reset is handled inline with each line now
|
|
353
|
-
}
|
|
354
|
-
else {
|
|
355
|
-
// Use cyan color for the tool name even when not showing descriptions
|
|
356
|
-
message += ` - \u001b[36m${tool.name}\u001b[0m\n`;
|
|
357
|
-
}
|
|
358
|
-
if (useShowSchema) {
|
|
359
|
-
// Prefix the parameters in cyan
|
|
360
|
-
message += ` \u001b[36mParameters:\u001b[0m\n`;
|
|
361
|
-
// Apply green color to the parameter text
|
|
362
|
-
const greenColor = '\u001b[32m';
|
|
363
|
-
const resetColor = '\u001b[0m';
|
|
364
|
-
const paramsLines = JSON.stringify(tool.schema.parameters, null, 2)
|
|
365
|
-
.trim()
|
|
366
|
-
.split('\n');
|
|
367
|
-
if (paramsLines) {
|
|
368
|
-
for (const paramsLine of paramsLines) {
|
|
369
|
-
message += ` ${greenColor}${paramsLine}${resetColor}\n`;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
});
|
|
374
|
-
}
|
|
375
|
-
else {
|
|
376
|
-
message += ' No tools available\n';
|
|
377
|
-
}
|
|
378
|
-
message += '\n';
|
|
379
|
-
}
|
|
380
|
-
// Make sure to reset any ANSI formatting at the end to prevent it from affecting the terminal
|
|
381
|
-
message += '\u001b[0m';
|
|
382
|
-
addMessage({
|
|
383
|
-
type: MessageType.INFO,
|
|
384
|
-
content: message,
|
|
385
|
-
timestamp: new Date(),
|
|
386
|
-
});
|
|
387
|
-
},
|
|
388
|
-
},
|
|
389
|
-
{
|
|
390
|
-
name: 'extensions',
|
|
391
|
-
description: 'list active extensions',
|
|
392
|
-
action: async () => {
|
|
393
|
-
const activeExtensions = config?.getActiveExtensions();
|
|
394
|
-
if (!activeExtensions || activeExtensions.length === 0) {
|
|
395
|
-
addMessage({
|
|
396
|
-
type: MessageType.INFO,
|
|
397
|
-
content: 'No active extensions.',
|
|
398
|
-
timestamp: new Date(),
|
|
399
|
-
});
|
|
400
|
-
return;
|
|
401
|
-
}
|
|
402
|
-
let message = 'Active extensions:\n\n';
|
|
403
|
-
for (const ext of activeExtensions) {
|
|
404
|
-
message += ` - \u001b[36m${ext.name} (v${ext.version})\u001b[0m\n`;
|
|
405
|
-
}
|
|
406
|
-
// Make sure to reset any ANSI formatting at the end to prevent it from affecting the terminal
|
|
407
|
-
message += '\u001b[0m';
|
|
408
|
-
addMessage({
|
|
409
|
-
type: MessageType.INFO,
|
|
410
|
-
content: message,
|
|
411
|
-
timestamp: new Date(),
|
|
412
|
-
});
|
|
413
|
-
},
|
|
414
|
-
},
|
|
415
|
-
{
|
|
416
|
-
name: 'tools',
|
|
417
|
-
description: 'list available Qwen Code tools',
|
|
418
|
-
action: async (_mainCommand, _subCommand, _args) => {
|
|
419
|
-
// Check if the _subCommand includes a specific flag to control description visibility
|
|
420
|
-
let useShowDescriptions = showToolDescriptions;
|
|
421
|
-
if (_subCommand === 'desc' || _subCommand === 'descriptions') {
|
|
422
|
-
useShowDescriptions = true;
|
|
423
|
-
}
|
|
424
|
-
else if (_subCommand === 'nodesc' ||
|
|
425
|
-
_subCommand === 'nodescriptions') {
|
|
426
|
-
useShowDescriptions = false;
|
|
427
|
-
}
|
|
428
|
-
else if (_args === 'desc' || _args === 'descriptions') {
|
|
429
|
-
useShowDescriptions = true;
|
|
430
|
-
}
|
|
431
|
-
else if (_args === 'nodesc' || _args === 'nodescriptions') {
|
|
432
|
-
useShowDescriptions = false;
|
|
433
|
-
}
|
|
434
|
-
const toolRegistry = await config?.getToolRegistry();
|
|
435
|
-
const tools = toolRegistry?.getAllTools();
|
|
436
|
-
if (!tools) {
|
|
437
|
-
addMessage({
|
|
438
|
-
type: MessageType.ERROR,
|
|
439
|
-
content: 'Could not retrieve tools.',
|
|
440
|
-
timestamp: new Date(),
|
|
441
|
-
});
|
|
442
|
-
return;
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (commandToExecute) {
|
|
198
|
+
const args = parts.slice(pathIndex).join(' ');
|
|
199
|
+
if (commandToExecute.action) {
|
|
200
|
+
const fullCommandContext = {
|
|
201
|
+
...commandContext,
|
|
202
|
+
invocation: {
|
|
203
|
+
raw: trimmed,
|
|
204
|
+
name: commandToExecute.name,
|
|
205
|
+
args,
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
// If a one-time list is provided for a "Proceed" action, temporarily
|
|
209
|
+
// augment the session allowlist for this single execution.
|
|
210
|
+
if (oneTimeShellAllowlist && oneTimeShellAllowlist.size > 0) {
|
|
211
|
+
fullCommandContext.session = {
|
|
212
|
+
...fullCommandContext.session,
|
|
213
|
+
sessionShellAllowlist: new Set([
|
|
214
|
+
...fullCommandContext.session.sessionShellAllowlist,
|
|
215
|
+
...oneTimeShellAllowlist,
|
|
216
|
+
]),
|
|
217
|
+
};
|
|
443
218
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
219
|
+
const result = await commandToExecute.action(fullCommandContext, args);
|
|
220
|
+
if (result) {
|
|
221
|
+
switch (result.type) {
|
|
222
|
+
case 'tool':
|
|
223
|
+
return {
|
|
224
|
+
type: 'schedule_tool',
|
|
225
|
+
toolName: result.toolName,
|
|
226
|
+
toolArgs: result.toolArgs,
|
|
227
|
+
};
|
|
228
|
+
case 'message':
|
|
229
|
+
addItem({
|
|
230
|
+
type: result.messageType === 'error'
|
|
231
|
+
? MessageType.ERROR
|
|
232
|
+
: MessageType.INFO,
|
|
233
|
+
text: result.content,
|
|
234
|
+
}, Date.now());
|
|
235
|
+
return { type: 'handled' };
|
|
236
|
+
case 'dialog':
|
|
237
|
+
switch (result.dialog) {
|
|
238
|
+
case 'help':
|
|
239
|
+
setShowHelp(true);
|
|
240
|
+
return { type: 'handled' };
|
|
241
|
+
case 'auth':
|
|
242
|
+
openAuthDialog();
|
|
243
|
+
return { type: 'handled' };
|
|
244
|
+
case 'theme':
|
|
245
|
+
openThemeDialog();
|
|
246
|
+
return { type: 'handled' };
|
|
247
|
+
case 'editor':
|
|
248
|
+
openEditorDialog();
|
|
249
|
+
return { type: 'handled' };
|
|
250
|
+
case 'privacy':
|
|
251
|
+
openPrivacyNotice();
|
|
252
|
+
return { type: 'handled' };
|
|
253
|
+
default: {
|
|
254
|
+
const unhandled = result.dialog;
|
|
255
|
+
throw new Error(`Unhandled slash command result: ${unhandled}`);
|
|
461
256
|
}
|
|
462
257
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
else {
|
|
471
|
-
message += ' No tools available\n';
|
|
472
|
-
}
|
|
473
|
-
message += '\n';
|
|
474
|
-
// Make sure to reset any ANSI formatting at the end to prevent it from affecting the terminal
|
|
475
|
-
message += '\u001b[0m';
|
|
476
|
-
addMessage({
|
|
477
|
-
type: MessageType.INFO,
|
|
478
|
-
content: message,
|
|
479
|
-
timestamp: new Date(),
|
|
480
|
-
});
|
|
481
|
-
},
|
|
482
|
-
},
|
|
483
|
-
{
|
|
484
|
-
name: 'corgi',
|
|
485
|
-
action: (_mainCommand, _subCommand, _args) => {
|
|
486
|
-
toggleCorgiMode();
|
|
487
|
-
},
|
|
488
|
-
},
|
|
489
|
-
{
|
|
490
|
-
name: 'bug',
|
|
491
|
-
description: 'submit a bug report',
|
|
492
|
-
action: async (_mainCommand, _subCommand, args) => {
|
|
493
|
-
let bugDescription = _subCommand || '';
|
|
494
|
-
if (args) {
|
|
495
|
-
bugDescription += ` ${args}`;
|
|
496
|
-
}
|
|
497
|
-
bugDescription = bugDescription.trim();
|
|
498
|
-
const osVersion = `${process.platform} ${process.version}`;
|
|
499
|
-
let sandboxEnv = 'no sandbox';
|
|
500
|
-
if (process.env.SANDBOX && process.env.SANDBOX !== 'sandbox-exec') {
|
|
501
|
-
sandboxEnv = process.env.SANDBOX.replace(/^gemini-(?:code-)?/, '');
|
|
502
|
-
}
|
|
503
|
-
else if (process.env.SANDBOX === 'sandbox-exec') {
|
|
504
|
-
sandboxEnv = `sandbox-exec (${process.env.SEATBELT_PROFILE || 'unknown'})`;
|
|
505
|
-
}
|
|
506
|
-
const modelVersion = config?.getModel() || 'Unknown';
|
|
507
|
-
const cliVersion = await getCliVersion();
|
|
508
|
-
const memoryUsage = formatMemoryUsage(process.memoryUsage().rss);
|
|
509
|
-
const info = `
|
|
510
|
-
* **CLI Version:** ${cliVersion}
|
|
511
|
-
* **Git Commit:** ${GIT_COMMIT_INFO}
|
|
512
|
-
* **Operating System:** ${osVersion}
|
|
513
|
-
* **Sandbox Environment:** ${sandboxEnv}
|
|
514
|
-
* **Model Version:** ${modelVersion}
|
|
515
|
-
* **Memory Usage:** ${memoryUsage}
|
|
516
|
-
`;
|
|
517
|
-
let bugReportUrl = 'https://github.com/QwenLM/Qwen-Code/issues/new?template=bug_report.yml&title={title}&info={info}';
|
|
518
|
-
const bugCommand = config?.getBugCommand();
|
|
519
|
-
if (bugCommand?.urlTemplate) {
|
|
520
|
-
bugReportUrl = bugCommand.urlTemplate;
|
|
521
|
-
}
|
|
522
|
-
bugReportUrl = bugReportUrl
|
|
523
|
-
.replace('{title}', encodeURIComponent(bugDescription))
|
|
524
|
-
.replace('{info}', encodeURIComponent(info));
|
|
525
|
-
addMessage({
|
|
526
|
-
type: MessageType.INFO,
|
|
527
|
-
content: `To submit your bug report, please open the following URL in your browser:\n${bugReportUrl}`,
|
|
528
|
-
timestamp: new Date(),
|
|
529
|
-
});
|
|
530
|
-
(async () => {
|
|
531
|
-
try {
|
|
532
|
-
await open(bugReportUrl);
|
|
533
|
-
}
|
|
534
|
-
catch (error) {
|
|
535
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
536
|
-
addMessage({
|
|
537
|
-
type: MessageType.ERROR,
|
|
538
|
-
content: `Could not open URL in browser: ${errorMessage}`,
|
|
539
|
-
timestamp: new Date(),
|
|
540
|
-
});
|
|
541
|
-
}
|
|
542
|
-
})();
|
|
543
|
-
},
|
|
544
|
-
},
|
|
545
|
-
{
|
|
546
|
-
name: 'chat',
|
|
547
|
-
description: 'Manage conversation history. Usage: /chat <list|save|resume> <tag>',
|
|
548
|
-
action: async (_mainCommand, subCommand, args) => {
|
|
549
|
-
const tag = (args || '').trim();
|
|
550
|
-
const logger = new Logger(config?.getSessionId() || '');
|
|
551
|
-
await logger.initialize();
|
|
552
|
-
const chat = await config?.getGeminiClient()?.getChat();
|
|
553
|
-
if (!chat) {
|
|
554
|
-
addMessage({
|
|
555
|
-
type: MessageType.ERROR,
|
|
556
|
-
content: 'No chat client available for conversation status.',
|
|
557
|
-
timestamp: new Date(),
|
|
558
|
-
});
|
|
559
|
-
return;
|
|
560
|
-
}
|
|
561
|
-
if (!subCommand) {
|
|
562
|
-
addMessage({
|
|
563
|
-
type: MessageType.ERROR,
|
|
564
|
-
content: 'Missing command\nUsage: /chat <list|save|resume> <tag>',
|
|
565
|
-
timestamp: new Date(),
|
|
566
|
-
});
|
|
567
|
-
return;
|
|
568
|
-
}
|
|
569
|
-
switch (subCommand) {
|
|
570
|
-
case 'save': {
|
|
571
|
-
if (!tag) {
|
|
572
|
-
addMessage({
|
|
573
|
-
type: MessageType.ERROR,
|
|
574
|
-
content: 'Missing tag. Usage: /chat save <tag>',
|
|
575
|
-
timestamp: new Date(),
|
|
576
|
-
});
|
|
577
|
-
return;
|
|
578
|
-
}
|
|
579
|
-
const history = chat.getHistory();
|
|
580
|
-
if (history.length > 0) {
|
|
581
|
-
await logger.saveCheckpoint(chat?.getHistory() || [], tag);
|
|
582
|
-
addMessage({
|
|
583
|
-
type: MessageType.INFO,
|
|
584
|
-
content: `Conversation checkpoint saved with tag: ${tag}.`,
|
|
585
|
-
timestamp: new Date(),
|
|
258
|
+
case 'load_history': {
|
|
259
|
+
await config
|
|
260
|
+
?.getGeminiClient()
|
|
261
|
+
?.setHistory(result.clientHistory);
|
|
262
|
+
fullCommandContext.ui.clear();
|
|
263
|
+
result.history.forEach((item, index) => {
|
|
264
|
+
fullCommandContext.ui.addItem(item, index);
|
|
586
265
|
});
|
|
266
|
+
return { type: 'handled' };
|
|
587
267
|
}
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
268
|
+
case 'quit':
|
|
269
|
+
setQuittingMessages(result.messages);
|
|
270
|
+
setTimeout(() => {
|
|
271
|
+
process.exit(0);
|
|
272
|
+
}, 100);
|
|
273
|
+
return { type: 'handled' };
|
|
274
|
+
case 'submit_prompt':
|
|
275
|
+
return {
|
|
276
|
+
type: 'submit_prompt',
|
|
277
|
+
content: result.content,
|
|
278
|
+
};
|
|
279
|
+
case 'confirm_shell_commands': {
|
|
280
|
+
const { outcome, approvedCommands } = await new Promise((resolve) => {
|
|
281
|
+
setShellConfirmationRequest({
|
|
282
|
+
commands: result.commandsToConfirm,
|
|
283
|
+
onConfirm: (resolvedOutcome, resolvedApprovedCommands) => {
|
|
284
|
+
setShellConfirmationRequest(null); // Close the dialog
|
|
285
|
+
resolve({
|
|
286
|
+
outcome: resolvedOutcome,
|
|
287
|
+
approvedCommands: resolvedApprovedCommands,
|
|
288
|
+
});
|
|
289
|
+
},
|
|
290
|
+
});
|
|
605
291
|
});
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
addMessage({
|
|
611
|
-
type: MessageType.INFO,
|
|
612
|
-
content: `No saved checkpoint found with tag: ${tag}.`,
|
|
613
|
-
timestamp: new Date(),
|
|
614
|
-
});
|
|
615
|
-
return;
|
|
616
|
-
}
|
|
617
|
-
clearItems();
|
|
618
|
-
chat.clearHistory();
|
|
619
|
-
const rolemap = {
|
|
620
|
-
user: MessageType.USER,
|
|
621
|
-
model: MessageType.GEMINI,
|
|
622
|
-
};
|
|
623
|
-
let hasSystemPrompt = false;
|
|
624
|
-
let i = 0;
|
|
625
|
-
for (const item of conversation) {
|
|
626
|
-
i += 1;
|
|
627
|
-
// Add each item to history regardless of whether we display
|
|
628
|
-
// it.
|
|
629
|
-
chat.addHistory(item);
|
|
630
|
-
const text = item.parts
|
|
631
|
-
?.filter((m) => !!m.text)
|
|
632
|
-
.map((m) => m.text)
|
|
633
|
-
.join('') || '';
|
|
634
|
-
if (!text) {
|
|
635
|
-
// Parsing Part[] back to various non-text output not yet implemented.
|
|
636
|
-
continue;
|
|
637
|
-
}
|
|
638
|
-
if (i === 1 && text.match(/context for our chat/)) {
|
|
639
|
-
hasSystemPrompt = true;
|
|
292
|
+
if (outcome === ToolConfirmationOutcome.Cancel ||
|
|
293
|
+
!approvedCommands ||
|
|
294
|
+
approvedCommands.length === 0) {
|
|
295
|
+
return { type: 'handled' };
|
|
640
296
|
}
|
|
641
|
-
if (
|
|
642
|
-
|
|
643
|
-
type: (item.role && rolemap[item.role]) || MessageType.GEMINI,
|
|
644
|
-
text,
|
|
645
|
-
}, i);
|
|
297
|
+
if (outcome === ToolConfirmationOutcome.ProceedAlways) {
|
|
298
|
+
setSessionShellAllowlist((prev) => new Set([...prev, ...approvedCommands]));
|
|
646
299
|
}
|
|
300
|
+
return await handleSlashCommand(result.originalInvocation.raw,
|
|
301
|
+
// Pass the approved commands as a one-time grant for this execution.
|
|
302
|
+
new Set(approvedCommands));
|
|
647
303
|
}
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
}
|
|
652
|
-
case 'list':
|
|
653
|
-
addMessage({
|
|
654
|
-
type: MessageType.INFO,
|
|
655
|
-
content: 'list of saved conversations: ' +
|
|
656
|
-
(await savedChatTags()).join(', '),
|
|
657
|
-
timestamp: new Date(),
|
|
658
|
-
});
|
|
659
|
-
return;
|
|
660
|
-
default:
|
|
661
|
-
addMessage({
|
|
662
|
-
type: MessageType.ERROR,
|
|
663
|
-
content: `Unknown /chat command: ${subCommand}. Available: list, save, resume`,
|
|
664
|
-
timestamp: new Date(),
|
|
665
|
-
});
|
|
666
|
-
return;
|
|
667
|
-
}
|
|
668
|
-
},
|
|
669
|
-
completion: async () => (await savedChatTags()).map((tag) => 'resume ' + tag),
|
|
670
|
-
},
|
|
671
|
-
{
|
|
672
|
-
name: 'quit',
|
|
673
|
-
altName: 'exit',
|
|
674
|
-
description: 'exit the cli',
|
|
675
|
-
action: async (mainCommand, _subCommand, _args) => {
|
|
676
|
-
const now = new Date();
|
|
677
|
-
const { sessionStartTime } = session.stats;
|
|
678
|
-
const wallDuration = now.getTime() - sessionStartTime.getTime();
|
|
679
|
-
setQuittingMessages([
|
|
680
|
-
{
|
|
681
|
-
type: 'user',
|
|
682
|
-
text: `/${mainCommand}`,
|
|
683
|
-
id: now.getTime() - 1,
|
|
684
|
-
},
|
|
685
|
-
{
|
|
686
|
-
type: 'quit',
|
|
687
|
-
duration: formatDuration(wallDuration),
|
|
688
|
-
id: now.getTime(),
|
|
689
|
-
},
|
|
690
|
-
]);
|
|
691
|
-
setTimeout(() => {
|
|
692
|
-
process.exit(0);
|
|
693
|
-
}, 100);
|
|
694
|
-
},
|
|
695
|
-
},
|
|
696
|
-
{
|
|
697
|
-
name: 'compress',
|
|
698
|
-
altName: 'summarize',
|
|
699
|
-
description: 'Compresses the context by replacing it with a summary.',
|
|
700
|
-
action: async (_mainCommand, _subCommand, _args) => {
|
|
701
|
-
if (pendingCompressionItemRef.current !== null) {
|
|
702
|
-
addMessage({
|
|
703
|
-
type: MessageType.ERROR,
|
|
704
|
-
content: 'Already compressing, wait for previous request to complete',
|
|
705
|
-
timestamp: new Date(),
|
|
706
|
-
});
|
|
707
|
-
return;
|
|
708
|
-
}
|
|
709
|
-
setPendingCompressionItem({
|
|
710
|
-
type: MessageType.COMPRESSION,
|
|
711
|
-
compression: {
|
|
712
|
-
isPending: true,
|
|
713
|
-
originalTokenCount: null,
|
|
714
|
-
newTokenCount: null,
|
|
715
|
-
},
|
|
716
|
-
});
|
|
717
|
-
try {
|
|
718
|
-
const compressed = await config
|
|
719
|
-
.getGeminiClient()
|
|
720
|
-
// TODO: Set Prompt id for CompressChat from SlashCommandProcessor.
|
|
721
|
-
.tryCompressChat('Prompt Id not set', true);
|
|
722
|
-
if (compressed) {
|
|
723
|
-
addMessage({
|
|
724
|
-
type: MessageType.COMPRESSION,
|
|
725
|
-
compression: {
|
|
726
|
-
isPending: false,
|
|
727
|
-
originalTokenCount: compressed.originalTokenCount,
|
|
728
|
-
newTokenCount: compressed.newTokenCount,
|
|
729
|
-
},
|
|
730
|
-
timestamp: new Date(),
|
|
731
|
-
});
|
|
732
|
-
}
|
|
733
|
-
else {
|
|
734
|
-
addMessage({
|
|
735
|
-
type: MessageType.ERROR,
|
|
736
|
-
content: 'Failed to compress chat history.',
|
|
737
|
-
timestamp: new Date(),
|
|
738
|
-
});
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
catch (e) {
|
|
742
|
-
addMessage({
|
|
743
|
-
type: MessageType.ERROR,
|
|
744
|
-
content: `Failed to compress chat history: ${e instanceof Error ? e.message : String(e)}`,
|
|
745
|
-
timestamp: new Date(),
|
|
746
|
-
});
|
|
747
|
-
}
|
|
748
|
-
setPendingCompressionItem(null);
|
|
749
|
-
},
|
|
750
|
-
},
|
|
751
|
-
];
|
|
752
|
-
if (config?.getCheckpointingEnabled()) {
|
|
753
|
-
commands.push({
|
|
754
|
-
name: 'restore',
|
|
755
|
-
description: 'restore a tool call. This will reset the conversation and file history to the state it was in when the tool call was suggested',
|
|
756
|
-
completion: async () => {
|
|
757
|
-
const checkpointDir = config?.getProjectTempDir()
|
|
758
|
-
? path.join(config.getProjectTempDir(), 'checkpoints')
|
|
759
|
-
: undefined;
|
|
760
|
-
if (!checkpointDir) {
|
|
761
|
-
return [];
|
|
762
|
-
}
|
|
763
|
-
try {
|
|
764
|
-
const files = await fs.readdir(checkpointDir);
|
|
765
|
-
return files
|
|
766
|
-
.filter((file) => file.endsWith('.json'))
|
|
767
|
-
.map((file) => file.replace('.json', ''));
|
|
768
|
-
}
|
|
769
|
-
catch (_err) {
|
|
770
|
-
return [];
|
|
771
|
-
}
|
|
772
|
-
},
|
|
773
|
-
action: async (_mainCommand, subCommand, _args) => {
|
|
774
|
-
const checkpointDir = config?.getProjectTempDir()
|
|
775
|
-
? path.join(config.getProjectTempDir(), 'checkpoints')
|
|
776
|
-
: undefined;
|
|
777
|
-
if (!checkpointDir) {
|
|
778
|
-
addMessage({
|
|
779
|
-
type: MessageType.ERROR,
|
|
780
|
-
content: 'Could not determine the .gemini directory path.',
|
|
781
|
-
timestamp: new Date(),
|
|
782
|
-
});
|
|
783
|
-
return;
|
|
784
|
-
}
|
|
785
|
-
try {
|
|
786
|
-
// Ensure the directory exists before trying to read it.
|
|
787
|
-
await fs.mkdir(checkpointDir, { recursive: true });
|
|
788
|
-
const files = await fs.readdir(checkpointDir);
|
|
789
|
-
const jsonFiles = files.filter((file) => file.endsWith('.json'));
|
|
790
|
-
if (!subCommand) {
|
|
791
|
-
if (jsonFiles.length === 0) {
|
|
792
|
-
addMessage({
|
|
793
|
-
type: MessageType.INFO,
|
|
794
|
-
content: 'No restorable tool calls found.',
|
|
795
|
-
timestamp: new Date(),
|
|
796
|
-
});
|
|
797
|
-
return;
|
|
304
|
+
default: {
|
|
305
|
+
const unhandled = result;
|
|
306
|
+
throw new Error(`Unhandled slash command result: ${unhandled}`);
|
|
798
307
|
}
|
|
799
|
-
const truncatedFiles = jsonFiles.map((file) => {
|
|
800
|
-
const components = file.split('.');
|
|
801
|
-
if (components.length <= 1) {
|
|
802
|
-
return file;
|
|
803
|
-
}
|
|
804
|
-
components.pop();
|
|
805
|
-
return components.join('.');
|
|
806
|
-
});
|
|
807
|
-
const fileList = truncatedFiles.join('\n');
|
|
808
|
-
addMessage({
|
|
809
|
-
type: MessageType.INFO,
|
|
810
|
-
content: `Available tool calls to restore:\n\n${fileList}`,
|
|
811
|
-
timestamp: new Date(),
|
|
812
|
-
});
|
|
813
|
-
return;
|
|
814
|
-
}
|
|
815
|
-
const selectedFile = subCommand.endsWith('.json')
|
|
816
|
-
? subCommand
|
|
817
|
-
: `${subCommand}.json`;
|
|
818
|
-
if (!jsonFiles.includes(selectedFile)) {
|
|
819
|
-
addMessage({
|
|
820
|
-
type: MessageType.ERROR,
|
|
821
|
-
content: `File not found: ${selectedFile}`,
|
|
822
|
-
timestamp: new Date(),
|
|
823
|
-
});
|
|
824
|
-
return;
|
|
825
|
-
}
|
|
826
|
-
const filePath = path.join(checkpointDir, selectedFile);
|
|
827
|
-
const data = await fs.readFile(filePath, 'utf-8');
|
|
828
|
-
const toolCallData = JSON.parse(data);
|
|
829
|
-
if (toolCallData.history) {
|
|
830
|
-
loadHistory(toolCallData.history);
|
|
831
|
-
}
|
|
832
|
-
if (toolCallData.clientHistory) {
|
|
833
|
-
await config
|
|
834
|
-
?.getGeminiClient()
|
|
835
|
-
?.setHistory(toolCallData.clientHistory);
|
|
836
308
|
}
|
|
837
|
-
if (toolCallData.commitHash) {
|
|
838
|
-
await gitService?.restoreProjectFromSnapshot(toolCallData.commitHash);
|
|
839
|
-
addMessage({
|
|
840
|
-
type: MessageType.INFO,
|
|
841
|
-
content: `Restored project to the state before the tool call.`,
|
|
842
|
-
timestamp: new Date(),
|
|
843
|
-
});
|
|
844
|
-
}
|
|
845
|
-
return {
|
|
846
|
-
type: 'tool',
|
|
847
|
-
toolName: toolCallData.toolCall.name,
|
|
848
|
-
toolArgs: toolCallData.toolCall.args,
|
|
849
|
-
};
|
|
850
|
-
}
|
|
851
|
-
catch (error) {
|
|
852
|
-
addMessage({
|
|
853
|
-
type: MessageType.ERROR,
|
|
854
|
-
content: `Could not read restorable tool calls. This is the error: ${error}`,
|
|
855
|
-
timestamp: new Date(),
|
|
856
|
-
});
|
|
857
309
|
}
|
|
858
|
-
|
|
859
|
-
});
|
|
860
|
-
}
|
|
861
|
-
return commands;
|
|
862
|
-
}, [
|
|
863
|
-
addMessage,
|
|
864
|
-
openEditorDialog,
|
|
865
|
-
toggleCorgiMode,
|
|
866
|
-
savedChatTags,
|
|
867
|
-
config,
|
|
868
|
-
showToolDescriptions,
|
|
869
|
-
session,
|
|
870
|
-
gitService,
|
|
871
|
-
loadHistory,
|
|
872
|
-
addItem,
|
|
873
|
-
setQuittingMessages,
|
|
874
|
-
pendingCompressionItemRef,
|
|
875
|
-
setPendingCompressionItem,
|
|
876
|
-
clearItems,
|
|
877
|
-
refreshStatic,
|
|
878
|
-
]);
|
|
879
|
-
const handleSlashCommand = useCallback(async (rawQuery) => {
|
|
880
|
-
if (typeof rawQuery !== 'string') {
|
|
881
|
-
return false;
|
|
882
|
-
}
|
|
883
|
-
const trimmed = rawQuery.trim();
|
|
884
|
-
if (!trimmed.startsWith('/') && !trimmed.startsWith('?')) {
|
|
885
|
-
return false;
|
|
886
|
-
}
|
|
887
|
-
const userMessageTimestamp = Date.now();
|
|
888
|
-
if (trimmed !== '/quit' && trimmed !== '/exit') {
|
|
889
|
-
addItem({ type: MessageType.USER, text: trimmed }, userMessageTimestamp);
|
|
890
|
-
}
|
|
891
|
-
const parts = trimmed.substring(1).trim().split(/\s+/);
|
|
892
|
-
const commandPath = parts.filter((p) => p); // The parts of the command, e.g., ['memory', 'add']
|
|
893
|
-
// --- Start of New Tree Traversal Logic ---
|
|
894
|
-
let currentCommands = commands;
|
|
895
|
-
let commandToExecute;
|
|
896
|
-
let pathIndex = 0;
|
|
897
|
-
for (const part of commandPath) {
|
|
898
|
-
const foundCommand = currentCommands.find((cmd) => cmd.name === part || cmd.altName === part);
|
|
899
|
-
if (foundCommand) {
|
|
900
|
-
commandToExecute = foundCommand;
|
|
901
|
-
pathIndex++;
|
|
902
|
-
if (foundCommand.subCommands) {
|
|
903
|
-
currentCommands = foundCommand.subCommands;
|
|
310
|
+
return { type: 'handled' };
|
|
904
311
|
}
|
|
905
|
-
else {
|
|
906
|
-
|
|
312
|
+
else if (commandToExecute.subCommands) {
|
|
313
|
+
const helpText = `Command '/${commandToExecute.name}' requires a subcommand. Available:\n${commandToExecute.subCommands
|
|
314
|
+
.map((sc) => ` - ${sc.name}: ${sc.description || ''}`)
|
|
315
|
+
.join('\n')}`;
|
|
316
|
+
addMessage({
|
|
317
|
+
type: MessageType.INFO,
|
|
318
|
+
content: helpText,
|
|
319
|
+
timestamp: new Date(),
|
|
320
|
+
});
|
|
321
|
+
return { type: 'handled' };
|
|
907
322
|
}
|
|
908
323
|
}
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
324
|
+
addMessage({
|
|
325
|
+
type: MessageType.ERROR,
|
|
326
|
+
content: `Unknown command: ${trimmed}`,
|
|
327
|
+
timestamp: new Date(),
|
|
328
|
+
});
|
|
329
|
+
return { type: 'handled' };
|
|
912
330
|
}
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
case 'tool':
|
|
920
|
-
return {
|
|
921
|
-
type: 'schedule_tool',
|
|
922
|
-
toolName: result.toolName,
|
|
923
|
-
toolArgs: result.toolArgs,
|
|
924
|
-
};
|
|
925
|
-
case 'message':
|
|
926
|
-
addItem({
|
|
927
|
-
type: result.messageType === 'error'
|
|
928
|
-
? MessageType.ERROR
|
|
929
|
-
: MessageType.INFO,
|
|
930
|
-
text: result.content,
|
|
931
|
-
}, Date.now());
|
|
932
|
-
return { type: 'handled' };
|
|
933
|
-
case 'dialog':
|
|
934
|
-
switch (result.dialog) {
|
|
935
|
-
case 'help':
|
|
936
|
-
setShowHelp(true);
|
|
937
|
-
return { type: 'handled' };
|
|
938
|
-
case 'auth':
|
|
939
|
-
openAuthDialog();
|
|
940
|
-
return { type: 'handled' };
|
|
941
|
-
case 'theme':
|
|
942
|
-
openThemeDialog();
|
|
943
|
-
return { type: 'handled' };
|
|
944
|
-
case 'privacy':
|
|
945
|
-
openPrivacyNotice();
|
|
946
|
-
return { type: 'handled' };
|
|
947
|
-
default: {
|
|
948
|
-
const unhandled = result.dialog;
|
|
949
|
-
throw new Error(`Unhandled slash command result: ${unhandled}`);
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
default: {
|
|
953
|
-
const unhandled = result;
|
|
954
|
-
throw new Error(`Unhandled slash command result: ${unhandled}`);
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
return { type: 'handled' };
|
|
959
|
-
}
|
|
960
|
-
else if (commandToExecute.subCommands) {
|
|
961
|
-
const helpText = `Command '/${commandToExecute.name}' requires a subcommand. Available:\n${commandToExecute.subCommands
|
|
962
|
-
.map((sc) => ` - ${sc.name}: ${sc.description || ''}`)
|
|
963
|
-
.join('\n')}`;
|
|
964
|
-
addMessage({
|
|
965
|
-
type: MessageType.INFO,
|
|
966
|
-
content: helpText,
|
|
967
|
-
timestamp: new Date(),
|
|
968
|
-
});
|
|
969
|
-
return { type: 'handled' };
|
|
970
|
-
}
|
|
331
|
+
catch (e) {
|
|
332
|
+
addItem({
|
|
333
|
+
type: MessageType.ERROR,
|
|
334
|
+
text: e instanceof Error ? e.message : String(e),
|
|
335
|
+
}, Date.now());
|
|
336
|
+
return { type: 'handled' };
|
|
971
337
|
}
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
const mainCommand = parts[0];
|
|
975
|
-
const subCommand = parts[1];
|
|
976
|
-
const legacyArgs = parts.slice(2).join(' ');
|
|
977
|
-
for (const cmd of legacyCommands) {
|
|
978
|
-
if (mainCommand === cmd.name || mainCommand === cmd.altName) {
|
|
979
|
-
const actionResult = await cmd.action(mainCommand, subCommand, legacyArgs);
|
|
980
|
-
if (actionResult?.type === 'tool') {
|
|
981
|
-
return {
|
|
982
|
-
type: 'schedule_tool',
|
|
983
|
-
toolName: actionResult.toolName,
|
|
984
|
-
toolArgs: actionResult.toolArgs,
|
|
985
|
-
};
|
|
986
|
-
}
|
|
987
|
-
if (actionResult?.type === 'message') {
|
|
988
|
-
addItem({
|
|
989
|
-
type: actionResult.messageType === 'error'
|
|
990
|
-
? MessageType.ERROR
|
|
991
|
-
: MessageType.INFO,
|
|
992
|
-
text: actionResult.content,
|
|
993
|
-
}, Date.now());
|
|
994
|
-
}
|
|
995
|
-
return { type: 'handled' };
|
|
996
|
-
}
|
|
338
|
+
finally {
|
|
339
|
+
setIsProcessing(false);
|
|
997
340
|
}
|
|
998
|
-
addMessage({
|
|
999
|
-
type: MessageType.ERROR,
|
|
1000
|
-
content: `Unknown command: ${trimmed}`,
|
|
1001
|
-
timestamp: new Date(),
|
|
1002
|
-
});
|
|
1003
|
-
return { type: 'handled' };
|
|
1004
341
|
}, [
|
|
342
|
+
config,
|
|
1005
343
|
addItem,
|
|
1006
344
|
setShowHelp,
|
|
1007
345
|
openAuthDialog,
|
|
1008
346
|
commands,
|
|
1009
|
-
legacyCommands,
|
|
1010
347
|
commandContext,
|
|
1011
348
|
addMessage,
|
|
1012
349
|
openThemeDialog,
|
|
1013
350
|
openPrivacyNotice,
|
|
351
|
+
openEditorDialog,
|
|
352
|
+
setQuittingMessages,
|
|
353
|
+
setShellConfirmationRequest,
|
|
354
|
+
setSessionShellAllowlist,
|
|
355
|
+
setIsProcessing,
|
|
1014
356
|
]);
|
|
1015
|
-
const allCommands = useMemo(() => {
|
|
1016
|
-
// Adapt legacy commands to the new SlashCommand interface
|
|
1017
|
-
const adaptedLegacyCommands = legacyCommands.map((legacyCmd) => ({
|
|
1018
|
-
name: legacyCmd.name,
|
|
1019
|
-
altName: legacyCmd.altName,
|
|
1020
|
-
description: legacyCmd.description,
|
|
1021
|
-
action: async (_context, args) => {
|
|
1022
|
-
const parts = args.split(/\s+/);
|
|
1023
|
-
const subCommand = parts[0] || undefined;
|
|
1024
|
-
const restOfArgs = parts.slice(1).join(' ') || undefined;
|
|
1025
|
-
return legacyCmd.action(legacyCmd.name, subCommand, restOfArgs);
|
|
1026
|
-
},
|
|
1027
|
-
completion: legacyCmd.completion
|
|
1028
|
-
? async (_context, _partialArg) => legacyCmd.completion()
|
|
1029
|
-
: undefined,
|
|
1030
|
-
}));
|
|
1031
|
-
const newCommandNames = new Set(commands.map((c) => c.name));
|
|
1032
|
-
const filteredAdaptedLegacy = adaptedLegacyCommands.filter((c) => !newCommandNames.has(c.name));
|
|
1033
|
-
return [...commands, ...filteredAdaptedLegacy];
|
|
1034
|
-
}, [commands, legacyCommands]);
|
|
1035
357
|
return {
|
|
1036
358
|
handleSlashCommand,
|
|
1037
|
-
slashCommands:
|
|
359
|
+
slashCommands: commands,
|
|
1038
360
|
pendingHistoryItems,
|
|
1039
361
|
commandContext,
|
|
362
|
+
shellConfirmationRequest,
|
|
1040
363
|
};
|
|
1041
364
|
};
|
|
1042
365
|
//# sourceMappingURL=slashCommandProcessor.js.map
|