Qwen Code Companion Plugin: Спецификация интерфейса
Последнее обновление: 15 сентября 2025 г.
Этот документ определяет контракт для создания компаньон-плагина, который активирует режим IDE для Qwen Code. Для VS Code эти возможности (встроенное сравнение, осведомленность о контексте) предоставляются официальным расширением (маркетплейс ). Данная спецификация предназначена для участников, желающих реализовать аналогичную функциональность в других редакторах, таких как JetBrains IDE, Sublime Text и т.д.
I. Интерфейс взаимодействия
Qwen Code и плагин IDE обмениваются данными через локальный канал взаимодействия.
1. Транспортный уровень: MCP поверх HTTP
Плагин ОБЯЗАН запустить локальный HTTP-сервер, реализующий Model Context Protocol (MCP).
- Протокол: Сервер должен быть корректным MCP-сервером. Рекомендуется использовать существующий MCP SDK для вашего языка, если он доступен.
- Конечная точка: Сервер должен предоставлять одну конечную точку (например,
/mcp) для всего MCP-взаимодействия. - Порт: Сервер ОБЯЗАН прослушивать динамически назначенный порт (т.е. слушать порт
0).
2. Механизм обнаружения: Блокировочный файл
Чтобы Qwen Code мог подключиться, ему необходимо узнать, какой порт использует ваш сервер. Плагин ОБЯЗАН обеспечить это, создав «блокировочный файл» и установив переменную окружения с портом.
-
Как CLI находит файл: CLI считывает порт из
QWEN_CODE_IDE_SERVER_PORT, затем читает~/.qwen/ide/<PORT>.lock(существуют устаревшие запасные варианты для старых расширений; см. примечание ниже). -
Расположение файла: Файл должен быть создан в определённом каталоге:
~/.qwen/ide/. Ваш плагин должен создать этот каталог, если он не существует. -
Соглашение об именовании файлов: Имя файла критически важно и ОБЯЗАНО соответствовать шаблону:
<PORT>.lock<PORT>: Порт, на котором работает ваш MCP-сервер.
-
Содержимое файла и проверка рабочей области: Файл ОБЯЗАН содержать JSON-объект следующей структуры:
{ "port": 12345, "workspacePath": "/path/to/project1:/path/to/project2", "authToken": "a-very-secret-token", "ppid": 1234, "ideName": "VS Code" }port(number, required): Порт MCP-сервера.workspacePath(string, required): Список всех открытых корневых путей рабочей области, разделённых разделителем путей, специфичным для ОС (:для Linux/macOS,;для Windows). CLI использует этот путь, чтобы убедиться, что он запущен в той же папке проекта, которая открыта в IDE. Если текущий рабочий каталог CLI не является подкаталогомworkspacePath, соединение будет отклонено. Ваш плагин ОБЯЗАН предоставлять корректные абсолютные пути к корням открытых рабочих областей.authToken(string, required): Секретный токен для защиты соединения. CLI будет включать этот токен в заголовокAuthorization: Bearer <token>во всех запросах.ppid(number, required): Идентификатор родительского процесса IDE.ideName(string, required): Удобочитаемое имя IDE (например,VS Code,JetBrains IDE).
-
Аутентификация: Для защиты соединения плагин ОБЯЗАН сгенерировать уникальный секретный токен и включить его в файл обнаружения. Затем CLI будет включать этот токен в заголовок
Authorizationдля всех запросов к MCP-серверу (например,Authorization: Bearer a-very-secret-token). Ваш сервер ОБЯЗАН проверять этот токен при каждом запросе и отклонять любые неавторизованные. -
Переменные окружения (обязательно): Ваш плагин ОБЯЗАН установить
QWEN_CODE_IDE_SERVER_PORTво встроенном терминале, чтобы CLI мог найти соответствующий файл<PORT>.lock.
Примечание об устаревших версиях: Для расширений старше v0.5.1 Qwen Code может использовать запасной вариант — чтение JSON-файлов в системном временном каталоге с именами qwen-code-ide-server-<PID>.json или qwen-code-ide-server-<PORT>.json. Новые интеграции не должны полагаться на эти устаревшие файлы.
II. Интерфейс контекста
Для обеспечения осведомленности о контексте плагин МОЖЕТ предоставлять CLI информацию в реальном времени о действиях пользователя в IDE.
Уведомление ide/contextUpdate
Плагин МОЖЕТ отправлять уведомление ide/contextUpdate notification в CLI всякий раз, когда контекст пользователя меняется.
-
События-триггеры: Это уведомление следует отправлять (с рекомендуемым подавлением 50 мс) при:
- Открытии, закрытии или фокусировке файла.
- Изменении позиции курсора или выделения текста пользователя в активном файле.
-
Полезная нагрузка (
IdeContext): Параметры уведомления ОБЯЗАНЫ быть объектомIdeContext:interface IdeContext { workspaceState?: { openFiles?: File[]; isTrusted?: boolean; }; } interface File { // Абсолютный путь к файлу path: string; // Временная метка последней фокусировки (Unix timestamp) для упорядочивания timestamp: number; // True, если это текущий сфокусированный файл isActive?: boolean; cursor?: { // Номер строки (начиная с 1) line: number; // Номер символа (начиная с 1) character: number; }; // Текст, выделенный пользователем в данный момент selectedText?: string; }Примечание: Список
openFilesдолжен включать только файлы, существующие на диске. Виртуальные файлы (например, несохранённые файлы без пути, страницы настроек редактора) ОБЯЗАНЫ быть исключены.
Как CLI использует этот контекст
Получив объект IdeContext, CLI выполняет несколько шагов нормализации и усечения перед отправкой информации модели.
- Упорядочивание файлов: CLI использует поле
timestampдля определения наиболее недавно использованных файлов. Он сортирует списокopenFilesна основе этого значения. Поэтому ваш плагин ОБЯЗАН предоставлять точную временную метку Unix для момента последней фокусировки файла. - Активный файл: CLI считает только самый последний файл (после сортировки) «активным». Он игнорирует флаг
isActiveво всех остальных файлах и очищает их поляcursorиselectedText. Ваш плагин должен сосредоточиться на установкеisActive: trueи предоставлении информации о курсоре/выделении только для текущего сфокусированного файла. - Усечение: Для управления лимитом токенов CLI усекает как список файлов (до 10 файлов), так и
selectedText(до 16 КБ).
Хотя CLI выполняет финальное усечение, настоятельно рекомендуется, чтобы ваш плагин также ограничивал объем отправляемого контекста.
III. Интерфейс сравнения (diff)
Для поддержки интерактивных изменений кода плагин МОЖЕТ предоставлять интерфейс сравнения. Это позволяет CLI запрашивать открытие в IDE представления diff с предлагаемыми изменениями файла. Пользователь может просматривать, редактировать и в итоге принять или отклонить эти изменения непосредственно в IDE.
Инструмент openDiff
Плагин ОБЯЗАН зарегистрировать инструмент openDiff на своём MCP-сервере.
-
Описание: Этот инструмент даёт указание IDE открыть редактируемое представление diff для определённого файла.
-
Запрос (
OpenDiffRequest): Инструмент вызывается через запросtools/call. Полеargumentsвнутриparamsзапроса ОБЯЗАНО быть объектомOpenDiffRequest.interface OpenDiffRequest { // Абсолютный путь к файлу для сравнения. filePath: string; // Предлагаемое новое содержимое файла. newContent: string; } -
Ответ (
CallToolResult): Инструмент ОБЯЗАН немедленно вернутьCallToolResultдля подтверждения запроса и сообщения, было ли представление diff успешно открыто.- При успехе: Если представление diff успешно открыто, ответ ОБЯЗАН содержать пустое содержимое (т.е.
content: []). - При ошибке: Если ошибка помешала открытию представления diff, ответ ОБЯЗАН иметь
isError: trueи включать блокTextContentв массивcontentс описанием ошибки.
Фактический результат diff (принятие или отклонение) передается асинхронно через уведомления.
- При успехе: Если представление diff успешно открыто, ответ ОБЯЗАН содержать пустое содержимое (т.е.
Инструмент closeDiff
Плагин ОБЯЗАН зарегистрировать инструмент closeDiff на своём MCP-сервере.
-
Описание: Этот инструмент даёт указание IDE закрыть открытое представление diff для определённого файла.
-
Запрос (
CloseDiffRequest): Инструмент вызывается через запросtools/call. Полеargumentsвнутриparamsзапроса ОБЯЗАНО быть объектомCloseDiffRequest.interface CloseDiffRequest { // Абсолютный путь к файлу, для которого нужно закрыть представление diff. filePath: string; } -
Ответ (
CallToolResult): Инструмент ОБЯЗАН вернутьCallToolResult.- При успехе: Если представление diff успешно закрыто, ответ ОБЯЗАН включать один блок TextContent в массиве content, содержащий финальное содержимое файла перед закрытием.
- При ошибке: Если ошибка помешала закрытию представления diff, ответ ОБЯЗАН иметь
isError: trueи включать блокTextContentв массивеcontentс описанием ошибки.
Уведомление ide/diffAccepted
Когда пользователь принимает изменения в представлении diff (например, нажатием кнопки «Применить» или «Сохранить»), плагин ОБЯЗАН отправить уведомление ide/diffAccepted в CLI.
-
Полезная нагрузка: Параметры уведомления ОБЯЗАНЫ включать путь к файлу и финальное содержимое файла. Содержимое может отличаться от исходного
newContent, если пользователь внёс ручные правки в представлении diff.{ // Абсолютный путь к сравниваемому файлу. filePath: string; // Полное содержимое файла после принятия. content: string; }
Уведомление ide/diffRejected
Когда пользователь отклоняет изменения (например, закрывает представление diff без принятия), плагин ОБЯЗАН отправить уведомление ide/diffRejected в CLI.
-
Полезная нагрузка: Параметры уведомления ОБЯЗАНЫ включать путь к файлу отклонённого diff.
{ // Абсолютный путь к сравниваемому файлу. filePath: string; }
IV. Интерфейс жизненного цикла
Плагин ОБЯЗАН корректно управлять своими ресурсами и файлом обнаружения в соответствии с жизненным циклом IDE.
- При активации (запуск IDE / включение плагина):
- Запустить MCP-сервер.
- Создать файл обнаружения.
- При деактивации (выключение IDE / отключение плагина):
- Остановить MCP-сервер.
- Удалить файл обнаружения.