@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
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { Config } from '@qwen-code/qwen-code-core';
|
|
7
|
+
import { ICommandLoader } from './types.js';
|
|
8
|
+
import { SlashCommand } from '../ui/commands/types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Discovers and loads custom slash commands from .toml files in both the
|
|
11
|
+
* user's global config directory and the current project's directory.
|
|
12
|
+
*
|
|
13
|
+
* This loader is responsible for:
|
|
14
|
+
* - Recursively scanning command directories.
|
|
15
|
+
* - Parsing and validating TOML files.
|
|
16
|
+
* - Adapting valid definitions into executable SlashCommand objects.
|
|
17
|
+
* - Handling file system errors and malformed files gracefully.
|
|
18
|
+
*/
|
|
19
|
+
export declare class FileCommandLoader implements ICommandLoader {
|
|
20
|
+
private readonly config;
|
|
21
|
+
private readonly projectRoot;
|
|
22
|
+
constructor(config: Config | null);
|
|
23
|
+
/**
|
|
24
|
+
* Loads all commands, applying the precedence rule where project-level
|
|
25
|
+
* commands override user-level commands with the same name.
|
|
26
|
+
* @param signal An AbortSignal to cancel the loading process.
|
|
27
|
+
* @returns A promise that resolves to an array of loaded SlashCommands.
|
|
28
|
+
*/
|
|
29
|
+
loadCommands(signal: AbortSignal): Promise<SlashCommand[]>;
|
|
30
|
+
/**
|
|
31
|
+
* Parses a single .toml file and transforms it into a SlashCommand object.
|
|
32
|
+
* @param filePath The absolute path to the .toml file.
|
|
33
|
+
* @param baseDir The root command directory for name calculation.
|
|
34
|
+
* @returns A promise resolving to a SlashCommand, or null if the file is invalid.
|
|
35
|
+
*/
|
|
36
|
+
private parseAndAdaptFile;
|
|
37
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { promises as fs } from 'fs';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import toml from '@iarna/toml';
|
|
9
|
+
import { glob } from 'glob';
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import { getProjectCommandsDir, getUserCommandsDir, } from '@qwen-code/qwen-code-core';
|
|
12
|
+
import { CommandKind, } from '../ui/commands/types.js';
|
|
13
|
+
import { DefaultArgumentProcessor, ShorthandArgumentProcessor, } from './prompt-processors/argumentProcessor.js';
|
|
14
|
+
import { SHORTHAND_ARGS_PLACEHOLDER, SHELL_INJECTION_TRIGGER, } from './prompt-processors/types.js';
|
|
15
|
+
import { ConfirmationRequiredError, ShellProcessor, } from './prompt-processors/shellProcessor.js';
|
|
16
|
+
/**
|
|
17
|
+
* Defines the Zod schema for a command definition file. This serves as the
|
|
18
|
+
* single source of truth for both validation and type inference.
|
|
19
|
+
*/
|
|
20
|
+
const TomlCommandDefSchema = z.object({
|
|
21
|
+
prompt: z.string({
|
|
22
|
+
required_error: "The 'prompt' field is required.",
|
|
23
|
+
invalid_type_error: "The 'prompt' field must be a string.",
|
|
24
|
+
}),
|
|
25
|
+
description: z.string().optional(),
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* Discovers and loads custom slash commands from .toml files in both the
|
|
29
|
+
* user's global config directory and the current project's directory.
|
|
30
|
+
*
|
|
31
|
+
* This loader is responsible for:
|
|
32
|
+
* - Recursively scanning command directories.
|
|
33
|
+
* - Parsing and validating TOML files.
|
|
34
|
+
* - Adapting valid definitions into executable SlashCommand objects.
|
|
35
|
+
* - Handling file system errors and malformed files gracefully.
|
|
36
|
+
*/
|
|
37
|
+
export class FileCommandLoader {
|
|
38
|
+
config;
|
|
39
|
+
projectRoot;
|
|
40
|
+
constructor(config) {
|
|
41
|
+
this.config = config;
|
|
42
|
+
this.projectRoot = config?.getProjectRoot() || process.cwd();
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Loads all commands, applying the precedence rule where project-level
|
|
46
|
+
* commands override user-level commands with the same name.
|
|
47
|
+
* @param signal An AbortSignal to cancel the loading process.
|
|
48
|
+
* @returns A promise that resolves to an array of loaded SlashCommands.
|
|
49
|
+
*/
|
|
50
|
+
async loadCommands(signal) {
|
|
51
|
+
const commandMap = new Map();
|
|
52
|
+
const globOptions = {
|
|
53
|
+
nodir: true,
|
|
54
|
+
dot: true,
|
|
55
|
+
signal,
|
|
56
|
+
follow: true,
|
|
57
|
+
};
|
|
58
|
+
try {
|
|
59
|
+
// User Commands
|
|
60
|
+
const userDir = getUserCommandsDir();
|
|
61
|
+
const userFiles = await glob('**/*.toml', {
|
|
62
|
+
...globOptions,
|
|
63
|
+
cwd: userDir,
|
|
64
|
+
});
|
|
65
|
+
const userCommandPromises = userFiles.map((file) => this.parseAndAdaptFile(path.join(userDir, file), userDir));
|
|
66
|
+
const userCommands = (await Promise.all(userCommandPromises)).filter((cmd) => cmd !== null);
|
|
67
|
+
for (const cmd of userCommands) {
|
|
68
|
+
commandMap.set(cmd.name, cmd);
|
|
69
|
+
}
|
|
70
|
+
// Project Commands (these intentionally override user commands)
|
|
71
|
+
const projectDir = getProjectCommandsDir(this.projectRoot);
|
|
72
|
+
const projectFiles = await glob('**/*.toml', {
|
|
73
|
+
...globOptions,
|
|
74
|
+
cwd: projectDir,
|
|
75
|
+
});
|
|
76
|
+
const projectCommandPromises = projectFiles.map((file) => this.parseAndAdaptFile(path.join(projectDir, file), projectDir));
|
|
77
|
+
const projectCommands = (await Promise.all(projectCommandPromises)).filter((cmd) => cmd !== null);
|
|
78
|
+
for (const cmd of projectCommands) {
|
|
79
|
+
commandMap.set(cmd.name, cmd);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
console.error(`[FileCommandLoader] Error during file search:`, error);
|
|
84
|
+
}
|
|
85
|
+
return Array.from(commandMap.values());
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Parses a single .toml file and transforms it into a SlashCommand object.
|
|
89
|
+
* @param filePath The absolute path to the .toml file.
|
|
90
|
+
* @param baseDir The root command directory for name calculation.
|
|
91
|
+
* @returns A promise resolving to a SlashCommand, or null if the file is invalid.
|
|
92
|
+
*/
|
|
93
|
+
async parseAndAdaptFile(filePath, baseDir) {
|
|
94
|
+
let fileContent;
|
|
95
|
+
try {
|
|
96
|
+
fileContent = await fs.readFile(filePath, 'utf-8');
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
console.error(`[FileCommandLoader] Failed to read file ${filePath}:`, error instanceof Error ? error.message : String(error));
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
let parsed;
|
|
103
|
+
try {
|
|
104
|
+
parsed = toml.parse(fileContent);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
console.error(`[FileCommandLoader] Failed to parse TOML file ${filePath}:`, error instanceof Error ? error.message : String(error));
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
const validationResult = TomlCommandDefSchema.safeParse(parsed);
|
|
111
|
+
if (!validationResult.success) {
|
|
112
|
+
console.error(`[FileCommandLoader] Skipping invalid command file: ${filePath}. Validation errors:`, validationResult.error.flatten());
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
const validDef = validationResult.data;
|
|
116
|
+
const relativePathWithExt = path.relative(baseDir, filePath);
|
|
117
|
+
const relativePath = relativePathWithExt.substring(0, relativePathWithExt.length - 5);
|
|
118
|
+
const commandName = relativePath
|
|
119
|
+
.split(path.sep)
|
|
120
|
+
// Sanitize each path segment to prevent ambiguity. Since ':' is our
|
|
121
|
+
// namespace separator, we replace any literal colons in filenames
|
|
122
|
+
// with underscores to avoid naming conflicts.
|
|
123
|
+
.map((segment) => segment.replaceAll(':', '_'))
|
|
124
|
+
.join(':');
|
|
125
|
+
const processors = [];
|
|
126
|
+
// Add the Shell Processor if needed.
|
|
127
|
+
if (validDef.prompt.includes(SHELL_INJECTION_TRIGGER)) {
|
|
128
|
+
processors.push(new ShellProcessor(commandName));
|
|
129
|
+
}
|
|
130
|
+
// The presence of '{{args}}' is the switch that determines the behavior.
|
|
131
|
+
if (validDef.prompt.includes(SHORTHAND_ARGS_PLACEHOLDER)) {
|
|
132
|
+
processors.push(new ShorthandArgumentProcessor());
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
processors.push(new DefaultArgumentProcessor());
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
name: commandName,
|
|
139
|
+
description: validDef.description ||
|
|
140
|
+
`Custom command from ${path.basename(filePath)}`,
|
|
141
|
+
kind: CommandKind.FILE,
|
|
142
|
+
action: async (context, _args) => {
|
|
143
|
+
if (!context.invocation) {
|
|
144
|
+
console.error(`[FileCommandLoader] Critical error: Command '${commandName}' was executed without invocation context.`);
|
|
145
|
+
return {
|
|
146
|
+
type: 'submit_prompt',
|
|
147
|
+
content: validDef.prompt, // Fallback to unprocessed prompt
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
let processedPrompt = validDef.prompt;
|
|
152
|
+
for (const processor of processors) {
|
|
153
|
+
processedPrompt = await processor.process(processedPrompt, context);
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
type: 'submit_prompt',
|
|
157
|
+
content: processedPrompt,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
catch (e) {
|
|
161
|
+
// Check if it's our specific error type
|
|
162
|
+
if (e instanceof ConfirmationRequiredError) {
|
|
163
|
+
// Halt and request confirmation from the UI layer.
|
|
164
|
+
return {
|
|
165
|
+
type: 'confirm_shell_commands',
|
|
166
|
+
commandsToConfirm: e.commandsToConfirm,
|
|
167
|
+
originalInvocation: {
|
|
168
|
+
raw: context.invocation.raw,
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
// Re-throw other errors to be handled by the global error handler.
|
|
173
|
+
throw e;
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=FileCommandLoader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileCommandLoader.js","sourceRoot":"","sources":["../../../src/services/FileCommandLoader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,IAAI,MAAM,aAAa,CAAC;AAC/B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAEL,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAEL,WAAW,GAGZ,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,wBAAwB,EACxB,0BAA0B,GAC3B,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAEL,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,yBAAyB,EACzB,cAAc,GACf,MAAM,uCAAuC,CAAC;AAE/C;;;GAGG;AACH,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,cAAc,EAAE,iCAAiC;QACjD,kBAAkB,EAAE,sCAAsC;KAC3D,CAAC;IACF,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACnC,CAAC,CAAC;AAEH;;;;;;;;;GASG;AACH,MAAM,OAAO,iBAAiB;IAGC;IAFZ,WAAW,CAAS;IAErC,YAA6B,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;QAChD,IAAI,CAAC,WAAW,GAAG,MAAM,EAAE,cAAc,EAAE,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAC/D,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,YAAY,CAAC,MAAmB;QACpC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAwB,CAAC;QACnD,MAAM,WAAW,GAAG;YAClB,KAAK,EAAE,IAAI;YACX,GAAG,EAAE,IAAI;YACT,MAAM;YACN,MAAM,EAAE,IAAI;SACb,CAAC;QAEF,IAAI,CAAC;YACH,gBAAgB;YAChB,MAAM,OAAO,GAAG,kBAAkB,EAAE,CAAC;YACrC,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE;gBACxC,GAAG,WAAW;gBACd,GAAG,EAAE,OAAO;aACb,CAAC,CAAC;YACH,MAAM,mBAAmB,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACjD,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAC1D,CAAC;YACF,MAAM,YAAY,GAAG,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC,MAAM,CAClE,CAAC,GAAG,EAAuB,EAAE,CAAC,GAAG,KAAK,IAAI,CAC3C,CAAC;YACF,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;gBAC/B,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAChC,CAAC;YAED,gEAAgE;YAChE,MAAM,UAAU,GAAG,qBAAqB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC3D,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE;gBAC3C,GAAG,WAAW;gBACd,GAAG,EAAE,UAAU;aAChB,CAAC,CAAC;YACH,MAAM,sBAAsB,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACvD,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,UAAU,CAAC,CAChE,CAAC;YACF,MAAM,eAAe,GAAG,CACtB,MAAM,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAC1C,CAAC,MAAM,CAAC,CAAC,GAAG,EAAuB,EAAE,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;YACrD,KAAK,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;gBAClC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,+CAA+C,EAAE,KAAK,CAAC,CAAC;QACxE,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;IACzC,CAAC;IAED;;;;;OAKG;IACK,KAAK,CAAC,iBAAiB,CAC7B,QAAgB,EAChB,OAAe;QAEf,IAAI,WAAmB,CAAC;QACxB,IAAI,CAAC;YACH,WAAW,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACrD,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,OAAO,CAAC,KAAK,CACX,2CAA2C,QAAQ,GAAG,EACtD,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CACvD,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,MAAe,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACnC,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,OAAO,CAAC,KAAK,CACX,iDAAiD,QAAQ,GAAG,EAC5D,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CACvD,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,gBAAgB,GAAG,oBAAoB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAEhE,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC;YAC9B,OAAO,CAAC,KAAK,CACX,sDAAsD,QAAQ,sBAAsB,EACpF,gBAAgB,CAAC,KAAK,CAAC,OAAO,EAAE,CACjC,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,QAAQ,GAAG,gBAAgB,CAAC,IAAI,CAAC;QAEvC,MAAM,mBAAmB,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC7D,MAAM,YAAY,GAAG,mBAAmB,CAAC,SAAS,CAChD,CAAC,EACD,mBAAmB,CAAC,MAAM,GAAG,CAAC,CAC/B,CAAC;QACF,MAAM,WAAW,GAAG,YAAY;aAC7B,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;YAChB,oEAAoE;YACpE,kEAAkE;YAClE,8CAA8C;aAC7C,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;aAC9C,IAAI,CAAC,GAAG,CAAC,CAAC;QAEb,MAAM,UAAU,GAAuB,EAAE,CAAC;QAE1C,qCAAqC;QACrC,IAAI,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,CAAC;YACtD,UAAU,CAAC,IAAI,CAAC,IAAI,cAAc,CAAC,WAAW,CAAC,CAAC,CAAC;QACnD,CAAC;QAED,yEAAyE;QACzE,IAAI,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,0BAA0B,CAAC,EAAE,CAAC;YACzD,UAAU,CAAC,IAAI,CAAC,IAAI,0BAA0B,EAAE,CAAC,CAAC;QACpD,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,IAAI,CAAC,IAAI,wBAAwB,EAAE,CAAC,CAAC;QAClD,CAAC;QAED,OAAO;YACL,IAAI,EAAE,WAAW;YACjB,WAAW,EACT,QAAQ,CAAC,WAAW;gBACpB,uBAAuB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;YAClD,IAAI,EAAE,WAAW,CAAC,IAAI;YACtB,MAAM,EAAE,KAAK,EACX,OAAuB,EACvB,KAAa,EACsB,EAAE;gBACrC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;oBACxB,OAAO,CAAC,KAAK,CACX,gDAAgD,WAAW,4CAA4C,CACxG,CAAC;oBACF,OAAO;wBACL,IAAI,EAAE,eAAe;wBACrB,OAAO,EAAE,QAAQ,CAAC,MAAM,EAAE,iCAAiC;qBAC5D,CAAC;gBACJ,CAAC;gBAED,IAAI,CAAC;oBACH,IAAI,eAAe,GAAG,QAAQ,CAAC,MAAM,CAAC;oBACtC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;wBACnC,eAAe,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;oBACtE,CAAC;oBAED,OAAO;wBACL,IAAI,EAAE,eAAe;wBACrB,OAAO,EAAE,eAAe;qBACzB,CAAC;gBACJ,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,wCAAwC;oBACxC,IAAI,CAAC,YAAY,yBAAyB,EAAE,CAAC;wBAC3C,mDAAmD;wBACnD,OAAO;4BACL,IAAI,EAAE,wBAAwB;4BAC9B,iBAAiB,EAAE,CAAC,CAAC,iBAAiB;4BACtC,kBAAkB,EAAE;gCAClB,GAAG,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG;6BAC5B;yBACF,CAAC;oBACJ,CAAC;oBACD,mEAAmE;oBACnE,MAAM,CAAC,CAAC;gBACV,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { Config } from '@qwen-code/qwen-code-core';
|
|
7
|
+
import { SlashCommand } from '../ui/commands/types.js';
|
|
8
|
+
import { ICommandLoader } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Discovers and loads executable slash commands from prompts exposed by
|
|
11
|
+
* Model-Context-Protocol (MCP) servers.
|
|
12
|
+
*/
|
|
13
|
+
export declare class McpPromptLoader implements ICommandLoader {
|
|
14
|
+
private readonly config;
|
|
15
|
+
constructor(config: Config | null);
|
|
16
|
+
/**
|
|
17
|
+
* Loads all available prompts from all configured MCP servers and adapts
|
|
18
|
+
* them into executable SlashCommand objects.
|
|
19
|
+
*
|
|
20
|
+
* @param _signal An AbortSignal (unused for this synchronous loader).
|
|
21
|
+
* @returns A promise that resolves to an array of loaded SlashCommands.
|
|
22
|
+
*/
|
|
23
|
+
loadCommands(_signal: AbortSignal): Promise<SlashCommand[]>;
|
|
24
|
+
private parseArgs;
|
|
25
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { getErrorMessage, getMCPServerPrompts, } from '@qwen-code/qwen-code-core';
|
|
7
|
+
import { CommandKind, } from '../ui/commands/types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Discovers and loads executable slash commands from prompts exposed by
|
|
10
|
+
* Model-Context-Protocol (MCP) servers.
|
|
11
|
+
*/
|
|
12
|
+
export class McpPromptLoader {
|
|
13
|
+
config;
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.config = config;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Loads all available prompts from all configured MCP servers and adapts
|
|
19
|
+
* them into executable SlashCommand objects.
|
|
20
|
+
*
|
|
21
|
+
* @param _signal An AbortSignal (unused for this synchronous loader).
|
|
22
|
+
* @returns A promise that resolves to an array of loaded SlashCommands.
|
|
23
|
+
*/
|
|
24
|
+
loadCommands(_signal) {
|
|
25
|
+
const promptCommands = [];
|
|
26
|
+
if (!this.config) {
|
|
27
|
+
return Promise.resolve([]);
|
|
28
|
+
}
|
|
29
|
+
const mcpServers = this.config.getMcpServers() || {};
|
|
30
|
+
for (const serverName in mcpServers) {
|
|
31
|
+
const prompts = getMCPServerPrompts(this.config, serverName) || [];
|
|
32
|
+
for (const prompt of prompts) {
|
|
33
|
+
const commandName = `${prompt.name}`;
|
|
34
|
+
const newPromptCommand = {
|
|
35
|
+
name: commandName,
|
|
36
|
+
description: prompt.description || `Invoke prompt ${prompt.name}`,
|
|
37
|
+
kind: CommandKind.MCP_PROMPT,
|
|
38
|
+
subCommands: [
|
|
39
|
+
{
|
|
40
|
+
name: 'help',
|
|
41
|
+
description: 'Show help for this prompt',
|
|
42
|
+
kind: CommandKind.MCP_PROMPT,
|
|
43
|
+
action: async () => {
|
|
44
|
+
if (!prompt.arguments || prompt.arguments.length === 0) {
|
|
45
|
+
return {
|
|
46
|
+
type: 'message',
|
|
47
|
+
messageType: 'info',
|
|
48
|
+
content: `Prompt "${prompt.name}" has no arguments.`,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
let helpMessage = `Arguments for "${prompt.name}":\n\n`;
|
|
52
|
+
if (prompt.arguments && prompt.arguments.length > 0) {
|
|
53
|
+
helpMessage += `You can provide arguments by name (e.g., --argName="value") or by position.\n\n`;
|
|
54
|
+
helpMessage += `e.g., ${prompt.name} ${prompt.arguments?.map((_) => `"foo"`)} is equivalent to ${prompt.name} ${prompt.arguments?.map((arg) => `--${arg.name}="foo"`)}\n\n`;
|
|
55
|
+
}
|
|
56
|
+
for (const arg of prompt.arguments) {
|
|
57
|
+
helpMessage += ` --${arg.name}\n`;
|
|
58
|
+
if (arg.description) {
|
|
59
|
+
helpMessage += ` ${arg.description}\n`;
|
|
60
|
+
}
|
|
61
|
+
helpMessage += ` (required: ${arg.required ? 'yes' : 'no'})\n\n`;
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
type: 'message',
|
|
65
|
+
messageType: 'info',
|
|
66
|
+
content: helpMessage,
|
|
67
|
+
};
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
action: async (context, args) => {
|
|
72
|
+
if (!this.config) {
|
|
73
|
+
return {
|
|
74
|
+
type: 'message',
|
|
75
|
+
messageType: 'error',
|
|
76
|
+
content: 'Config not loaded.',
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
const promptInputs = this.parseArgs(args, prompt.arguments);
|
|
80
|
+
if (promptInputs instanceof Error) {
|
|
81
|
+
return {
|
|
82
|
+
type: 'message',
|
|
83
|
+
messageType: 'error',
|
|
84
|
+
content: promptInputs.message,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
const mcpServers = this.config.getMcpServers() || {};
|
|
89
|
+
const mcpServerConfig = mcpServers[serverName];
|
|
90
|
+
if (!mcpServerConfig) {
|
|
91
|
+
return {
|
|
92
|
+
type: 'message',
|
|
93
|
+
messageType: 'error',
|
|
94
|
+
content: `MCP server config not found for '${serverName}'.`,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const result = await prompt.invoke(promptInputs);
|
|
98
|
+
if (result.error) {
|
|
99
|
+
return {
|
|
100
|
+
type: 'message',
|
|
101
|
+
messageType: 'error',
|
|
102
|
+
content: `Error invoking prompt: ${result.error}`,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
if (!result.messages?.[0]?.content?.text) {
|
|
106
|
+
return {
|
|
107
|
+
type: 'message',
|
|
108
|
+
messageType: 'error',
|
|
109
|
+
content: 'Received an empty or invalid prompt response from the server.',
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
type: 'submit_prompt',
|
|
114
|
+
content: JSON.stringify(result.messages[0].content.text),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
return {
|
|
119
|
+
type: 'message',
|
|
120
|
+
messageType: 'error',
|
|
121
|
+
content: `Error: ${getErrorMessage(error)}`,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
completion: async (_, partialArg) => {
|
|
126
|
+
if (!prompt || !prompt.arguments) {
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
const suggestions = [];
|
|
130
|
+
const usedArgNames = new Set((partialArg.match(/--([^=]+)/g) || []).map((s) => s.substring(2)));
|
|
131
|
+
for (const arg of prompt.arguments) {
|
|
132
|
+
if (!usedArgNames.has(arg.name)) {
|
|
133
|
+
suggestions.push(`--${arg.name}=""`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return suggestions;
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
promptCommands.push(newPromptCommand);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return Promise.resolve(promptCommands);
|
|
143
|
+
}
|
|
144
|
+
parseArgs(userArgs, promptArgs) {
|
|
145
|
+
const argValues = {};
|
|
146
|
+
const promptInputs = {};
|
|
147
|
+
// arg parsing: --key="value" or --key=value
|
|
148
|
+
const namedArgRegex = /--([^=]+)=(?:"((?:\\.|[^"\\])*)"|([^ ]*))/g;
|
|
149
|
+
let match;
|
|
150
|
+
const remainingArgs = [];
|
|
151
|
+
let lastIndex = 0;
|
|
152
|
+
while ((match = namedArgRegex.exec(userArgs)) !== null) {
|
|
153
|
+
const key = match[1];
|
|
154
|
+
const value = match[2] ?? match[3]; // Quoted or unquoted value
|
|
155
|
+
argValues[key] = value;
|
|
156
|
+
// Capture text between matches as potential positional args
|
|
157
|
+
if (match.index > lastIndex) {
|
|
158
|
+
remainingArgs.push(userArgs.substring(lastIndex, match.index).trim());
|
|
159
|
+
}
|
|
160
|
+
lastIndex = namedArgRegex.lastIndex;
|
|
161
|
+
}
|
|
162
|
+
// Capture any remaining text after the last named arg
|
|
163
|
+
if (lastIndex < userArgs.length) {
|
|
164
|
+
remainingArgs.push(userArgs.substring(lastIndex).trim());
|
|
165
|
+
}
|
|
166
|
+
const positionalArgs = remainingArgs.join(' ').split(/ +/);
|
|
167
|
+
if (!promptArgs) {
|
|
168
|
+
return promptInputs;
|
|
169
|
+
}
|
|
170
|
+
for (const arg of promptArgs) {
|
|
171
|
+
if (argValues[arg.name]) {
|
|
172
|
+
promptInputs[arg.name] = argValues[arg.name];
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const unfilledArgs = promptArgs.filter((arg) => arg.required && !promptInputs[arg.name]);
|
|
176
|
+
const missingArgs = [];
|
|
177
|
+
for (let i = 0; i < unfilledArgs.length; i++) {
|
|
178
|
+
if (positionalArgs.length > i && positionalArgs[i]) {
|
|
179
|
+
promptInputs[unfilledArgs[i].name] = positionalArgs[i];
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
missingArgs.push(unfilledArgs[i].name);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (missingArgs.length > 0) {
|
|
186
|
+
const missingArgNames = missingArgs.map((name) => `--${name}`).join(', ');
|
|
187
|
+
return new Error(`Missing required argument(s): ${missingArgNames}`);
|
|
188
|
+
}
|
|
189
|
+
return promptInputs;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=McpPromptLoader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"McpPromptLoader.js","sourceRoot":"","sources":["../../../src/services/McpPromptLoader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { IPromptProcessor } from './types.js';
|
|
7
|
+
import { CommandContext } from '../../ui/commands/types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Replaces all instances of `{{args}}` in a prompt with the user-provided
|
|
10
|
+
* argument string.
|
|
11
|
+
*/
|
|
12
|
+
export declare class ShorthandArgumentProcessor implements IPromptProcessor {
|
|
13
|
+
process(prompt: string, context: CommandContext): Promise<string>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Appends the user's full command invocation to the prompt if arguments are
|
|
17
|
+
* provided, allowing the model to perform its own argument parsing.
|
|
18
|
+
*/
|
|
19
|
+
export declare class DefaultArgumentProcessor implements IPromptProcessor {
|
|
20
|
+
process(prompt: string, context: CommandContext): Promise<string>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { SHORTHAND_ARGS_PLACEHOLDER } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Replaces all instances of `{{args}}` in a prompt with the user-provided
|
|
9
|
+
* argument string.
|
|
10
|
+
*/
|
|
11
|
+
export class ShorthandArgumentProcessor {
|
|
12
|
+
async process(prompt, context) {
|
|
13
|
+
return prompt.replaceAll(SHORTHAND_ARGS_PLACEHOLDER, context.invocation.args);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Appends the user's full command invocation to the prompt if arguments are
|
|
18
|
+
* provided, allowing the model to perform its own argument parsing.
|
|
19
|
+
*/
|
|
20
|
+
export class DefaultArgumentProcessor {
|
|
21
|
+
async process(prompt, context) {
|
|
22
|
+
if (context.invocation.args) {
|
|
23
|
+
return `${prompt}\n\n${context.invocation.raw}`;
|
|
24
|
+
}
|
|
25
|
+
return prompt;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=argumentProcessor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"argumentProcessor.js","sourceRoot":"","sources":["../../../../src/services/prompt-processors/argumentProcessor.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAoB,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAG1E;;;GAGG;AACH,MAAM,OAAO,0BAA0B;IACrC,KAAK,CAAC,OAAO,CAAC,MAAc,EAAE,OAAuB;QACnD,OAAO,MAAM,CAAC,UAAU,CACtB,0BAA0B,EAC1B,OAAO,CAAC,UAAW,CAAC,IAAI,CACzB,CAAC;IACJ,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,wBAAwB;IACnC,KAAK,CAAC,OAAO,CAAC,MAAc,EAAE,OAAuB;QACnD,IAAI,OAAO,CAAC,UAAW,CAAC,IAAI,EAAE,CAAC;YAC7B,OAAO,GAAG,MAAM,OAAO,OAAO,CAAC,UAAW,CAAC,GAAG,EAAE,CAAC;QACnD,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { CommandContext } from '../../ui/commands/types.js';
|
|
7
|
+
import { IPromptProcessor } from './types.js';
|
|
8
|
+
export declare class ConfirmationRequiredError extends Error {
|
|
9
|
+
commandsToConfirm: string[];
|
|
10
|
+
constructor(message: string, commandsToConfirm: string[]);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Finds all instances of shell command injections (`!{...}`) in a prompt,
|
|
14
|
+
* executes them, and replaces the injection site with the command's output.
|
|
15
|
+
*
|
|
16
|
+
* This processor ensures that only allowlisted commands are executed. If a
|
|
17
|
+
* disallowed command is found, it halts execution and reports an error.
|
|
18
|
+
*/
|
|
19
|
+
export declare class ShellProcessor implements IPromptProcessor {
|
|
20
|
+
private readonly commandName;
|
|
21
|
+
/**
|
|
22
|
+
* A regular expression to find all instances of `!{...}`. The inner
|
|
23
|
+
* capture group extracts the command itself.
|
|
24
|
+
*/
|
|
25
|
+
private static readonly SHELL_INJECTION_REGEX;
|
|
26
|
+
/**
|
|
27
|
+
* @param commandName The name of the custom command being executed, used
|
|
28
|
+
* for logging and error messages.
|
|
29
|
+
*/
|
|
30
|
+
constructor(commandName: string);
|
|
31
|
+
process(prompt: string, context: CommandContext): Promise<string>;
|
|
32
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { checkCommandPermissions, ShellExecutionService, } from '@qwen-code/qwen-code-core';
|
|
7
|
+
export class ConfirmationRequiredError extends Error {
|
|
8
|
+
commandsToConfirm;
|
|
9
|
+
constructor(message, commandsToConfirm) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.commandsToConfirm = commandsToConfirm;
|
|
12
|
+
this.name = 'ConfirmationRequiredError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Finds all instances of shell command injections (`!{...}`) in a prompt,
|
|
17
|
+
* executes them, and replaces the injection site with the command's output.
|
|
18
|
+
*
|
|
19
|
+
* This processor ensures that only allowlisted commands are executed. If a
|
|
20
|
+
* disallowed command is found, it halts execution and reports an error.
|
|
21
|
+
*/
|
|
22
|
+
export class ShellProcessor {
|
|
23
|
+
commandName;
|
|
24
|
+
/**
|
|
25
|
+
* A regular expression to find all instances of `!{...}`. The inner
|
|
26
|
+
* capture group extracts the command itself.
|
|
27
|
+
*/
|
|
28
|
+
static SHELL_INJECTION_REGEX = /!\{([^}]*)\}/g;
|
|
29
|
+
/**
|
|
30
|
+
* @param commandName The name of the custom command being executed, used
|
|
31
|
+
* for logging and error messages.
|
|
32
|
+
*/
|
|
33
|
+
constructor(commandName) {
|
|
34
|
+
this.commandName = commandName;
|
|
35
|
+
}
|
|
36
|
+
async process(prompt, context) {
|
|
37
|
+
const { config, sessionShellAllowlist } = {
|
|
38
|
+
...context.services,
|
|
39
|
+
...context.session,
|
|
40
|
+
};
|
|
41
|
+
const commandsToExecute = [];
|
|
42
|
+
const commandsToConfirm = new Set();
|
|
43
|
+
const matches = [...prompt.matchAll(ShellProcessor.SHELL_INJECTION_REGEX)];
|
|
44
|
+
if (matches.length === 0) {
|
|
45
|
+
return prompt; // No shell commands, nothing to do.
|
|
46
|
+
}
|
|
47
|
+
// Discover all commands and check permissions.
|
|
48
|
+
for (const match of matches) {
|
|
49
|
+
const command = match[1].trim();
|
|
50
|
+
const { allAllowed, disallowedCommands, blockReason, isHardDenial } = checkCommandPermissions(command, config, sessionShellAllowlist);
|
|
51
|
+
if (!allAllowed) {
|
|
52
|
+
// If it's a hard denial, this is a non-recoverable security error.
|
|
53
|
+
if (isHardDenial) {
|
|
54
|
+
throw new Error(`${this.commandName} cannot be run. ${blockReason || 'A shell command in this custom command is explicitly blocked in your config settings.'}`);
|
|
55
|
+
}
|
|
56
|
+
// Add each soft denial disallowed command to the set for confirmation.
|
|
57
|
+
disallowedCommands.forEach((uc) => commandsToConfirm.add(uc));
|
|
58
|
+
}
|
|
59
|
+
commandsToExecute.push({ fullMatch: match[0], command });
|
|
60
|
+
}
|
|
61
|
+
// If any commands require confirmation, throw a special error to halt the
|
|
62
|
+
// pipeline and trigger the UI flow.
|
|
63
|
+
if (commandsToConfirm.size > 0) {
|
|
64
|
+
throw new ConfirmationRequiredError('Shell command confirmation required', Array.from(commandsToConfirm));
|
|
65
|
+
}
|
|
66
|
+
// Execute all commands (only runs if no confirmation was needed).
|
|
67
|
+
let processedPrompt = prompt;
|
|
68
|
+
for (const { fullMatch, command } of commandsToExecute) {
|
|
69
|
+
const { result } = ShellExecutionService.execute(command, config.getTargetDir(), () => { }, // No streaming needed.
|
|
70
|
+
new AbortController().signal);
|
|
71
|
+
const executionResult = await result;
|
|
72
|
+
processedPrompt = processedPrompt.replace(fullMatch, executionResult.output);
|
|
73
|
+
}
|
|
74
|
+
return processedPrompt;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=shellProcessor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shellProcessor.js","sourceRoot":"","sources":["../../../../src/services/prompt-processors/shellProcessor.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,2BAA2B,CAAC;AAKnC,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IAGzC;IAFT,YACE,OAAe,EACR,iBAA2B;QAElC,KAAK,CAAC,OAAO,CAAC,CAAC;QAFR,sBAAiB,GAAjB,iBAAiB,CAAU;QAGlC,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;IAC1C,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,OAAO,cAAc;IAWI;IAV7B;;;OAGG;IACK,MAAM,CAAU,qBAAqB,GAAG,eAAe,CAAC;IAEhE;;;OAGG;IACH,YAA6B,WAAmB;QAAnB,gBAAW,GAAX,WAAW,CAAQ;IAAG,CAAC;IAEpD,KAAK,CAAC,OAAO,CAAC,MAAc,EAAE,OAAuB;QACnD,MAAM,EAAE,MAAM,EAAE,qBAAqB,EAAE,GAAG;YACxC,GAAG,OAAO,CAAC,QAAQ;YACnB,GAAG,OAAO,CAAC,OAAO;SACnB,CAAC;QACF,MAAM,iBAAiB,GAAkD,EAAE,CAAC;QAC5E,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAU,CAAC;QAE5C,MAAM,OAAO,GAAG,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,qBAAqB,CAAC,CAAC,CAAC;QAC3E,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,MAAM,CAAC,CAAC,oCAAoC;QACrD,CAAC;QAED,+CAA+C;QAC/C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAChC,MAAM,EAAE,UAAU,EAAE,kBAAkB,EAAE,WAAW,EAAE,YAAY,EAAE,GACjE,uBAAuB,CAAC,OAAO,EAAE,MAAO,EAAE,qBAAqB,CAAC,CAAC;YAEnE,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,mEAAmE;gBACnE,IAAI,YAAY,EAAE,CAAC;oBACjB,MAAM,IAAI,KAAK,CACb,GAAG,IAAI,CAAC,WAAW,mBAAmB,WAAW,IAAI,uFAAuF,EAAE,CAC/I,CAAC;gBACJ,CAAC;gBAED,uEAAuE;gBACvE,kBAAkB,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;YAChE,CAAC;YACD,iBAAiB,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;QAC3D,CAAC;QAED,0EAA0E;QAC1E,oCAAoC;QACpC,IAAI,iBAAiB,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,yBAAyB,CACjC,qCAAqC,EACrC,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAC9B,CAAC;QACJ,CAAC;QAED,kEAAkE;QAClE,IAAI,eAAe,GAAG,MAAM,CAAC;QAC7B,KAAK,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,iBAAiB,EAAE,CAAC;YACvD,MAAM,EAAE,MAAM,EAAE,GAAG,qBAAqB,CAAC,OAAO,CAC9C,OAAO,EACP,MAAO,CAAC,YAAY,EAAE,EACtB,GAAG,EAAE,GAAE,CAAC,EAAE,uBAAuB;YACjC,IAAI,eAAe,EAAE,CAAC,MAAM,CAC7B,CAAC;YAEF,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC;YACrC,eAAe,GAAG,eAAe,CAAC,OAAO,CACvC,SAAS,EACT,eAAe,CAAC,MAAM,CACvB,CAAC;QACJ,CAAC;QAED,OAAO,eAAe,CAAC;IACzB,CAAC"}
|