Обзор пакета
Этот монорепозиторий содержит два основных пакета: @qwen-code/qwen-code и @qwen-code/qwen-code-core.
@qwen-code/qwen-code
Это основной пакет для Qwen Code. Он отвечает за пользовательский интерфейс, разбор команд и весь другой функционал, взаимодействующий с пользователем.
При публикации этого пакета он собирается в один исполняемый файл. Эта сборка включает все зависимости пакета, включая @qwen-code/qwen-code-core. Это означает, что независимо от того, устанавливает ли пользователь пакет с помощью npm install -g @qwen-code/qwen-code или запускает его напрямую с помощью npx @qwen-code/qwen-code, он использует этот единственный, самодостаточный исполняемый файл.
@qwen-code/qwen-code-core
Этот пакет содержит основную логику для CLI. Он отвечает за выполнение API-запросов к настроенным провайдерам, обработку аутентификации и управление локальным кэшем.
Этот пакет не собирается в бандл. При публикации он выпускается как стандартный пакет Node.js со своими собственными зависимостями. Это позволяет использовать его как отдельный пакет в других проектах, если это необходимо. Весь транспилированный JS-код в папке dist включён в пакет.
Процесс релиза
Этот проект следует структурированному процессу релиза, чтобы гарантировать правильное управление версиями и публикацию всех пакетов. Процесс максимально автоматизирован.
Как выполнить релиз
Релизы управляются через рабочий процесс GitHub Actions release.yml . Чтобы выполнить ручной релиз патча или хотфикса:
- Перейдите на вкладку Actions репозитория.
- Выберите рабочий процесс Release из списка.
- Нажмите кнопку выпадающего списка Run workflow.
- Заполните необходимые поля:
- Version: точная версия для релиза (например,
v0.2.1). - Ref: ветка или SHA коммита, из которого выполняется релиз (по умолчанию
main). - Dry Run: оставьте значение
true, чтобы протестировать рабочий процесс без публикации, или установитеfalse, чтобы выполнить реальный релиз.
- Version: точная версия для релиза (например,
- Нажмите Run workflow.
Типы релизов
Проект поддерживает несколько типов релизов:
Стабильные релизы
Обычные стабильные релизы для использования в продакшене.
Предварительные релизы
Еженедельные предварительные релизы каждый вторник в 23:59 по UTC для раннего доступа к новым функциям.
Ночные релизы
Ежедневные ночные релизы в полночь по UTC для тестирования на переднем крае разработки.
Автоматизированный график релизов
- Ночной: Каждый день в полночь по UTC
- Предварительный: Каждый вторник в 23:59 по UTC
- Стабильный: Ручные релизы, запускаемые сопровождающими
Как использовать различные типы релизов
Чтобы установить последнюю версию каждого типа:
# Стабильная (по умолчанию)
npm install -g @qwen-code/qwen-code
# Предварительная
npm install -g @qwen-code/qwen-code@preview
# Ночная
npm install -g @qwen-code/qwen-code@nightlyДетали процесса релиза
Каждый запланированный или ручной релиз проходит следующие шаги:
- Выполняет checkout указанного кода (последний из ветки
mainили конкретный коммит). - Устанавливает все зависимости.
- Запускает полный набор проверок
preflightи интеграционных тестов. - Если все тесты пройдены успешно, вычисляет подходящий номер версии на основе типа релиза.
- Собирает и публикует пакеты в npm с соответствующим dist-tag.
- Создает релиз GitHub для версии.
Обработка ошибок
Если какой-либо шаг в процессе релиза завершается неудачей, автоматически создается новая задача в репозитории с метками bug и специфичной для типа ошибки меткой (например, nightly-failure, preview-failure). В задаче будет содержаться ссылка на неудавшийся запуск workflow для упрощения отладки.
Валидация релиза
После публикации нового релиза необходимо провести дымовое тестирование, чтобы убедиться, что пакеты работают должным образом. Это можно сделать, установив пакеты локально и запустив набор тестов для проверки их корректной работы.
npx -y @qwen-code/qwen-code@latest --version— чтобы убедиться, что пуш прошёл успешно, если вы не использовали теги rc или devnpx -y @qwen-code/qwen-code@<release tag> --version— чтобы проверить правильность отправленного тега- Это разрушительно для локальной среды:
npm uninstall @qwen-code/qwen-code && npm uninstall -g @qwen-code/qwen-code && npm cache clean --force && npm install @qwen-code/qwen-code@<version> - Рекомендуется выполнить базовое дымовое тестирование, включающее несколько команд и инструментов LLM, чтобы убедиться, что пакеты работают как ожидалось. В будущем мы формализуем этот процесс.
Когда сливать изменения версии, а когда нет?
Описанный выше подход к созданию патч- или хотфикс-релизов из текущих или более старых коммитов оставляет репозиторий в следующем состоянии:
- Тег (
vX.Y.Z-patch.1): Этот тег правильно указывает на оригинальный коммит в веткеmain, который содержит стабильный код, предназначенный для релиза. Это важно. Любой, кто перейдет к этому тегу, получит точную копию опубликованного кода. - Ветка (
release-vX.Y.Z-patch.1): Эта ветка содержит один новый коммит поверх тегированного коммита. Новый коммит включает только изменение номера версии вpackage.json(и других связанных файлах, таких какpackage-lock.json).
Такое разделение полезно. Оно позволяет сохранить историю основной ветки без специфичных для релиза изменений номеров версий до тех пор, пока вы явно не решите их слить.
Это ключевое решение, и оно полностью зависит от характера самого релиза.
Обратное слияние для стабильных патчей и хотфиксов
Почти всегда необходимо объединять ветку release-<tag> обратно в main для любого
стабильного патча или релиза с хотфиксом.
- Почему? Основная причина — обновление версии в package.json ветки main. Если вы выпускаете v1.2.1 из более старого коммита, но никогда не объединяете увеличение версии обратно, package.json вашей основной ветки все еще будет содержать “version”: “1.2.0”. Следующий разработчик, который начнет работу над следующим фича-релизом (v1.3.0), будет отталкиваться от кодовой базы с некорректным, устаревшим номером версии. Это приводит к путанице и требует ручного увеличения версии позже.
- Процесс: После создания ветки release-v1.2.1 и успешной публикации пакета, вы должны открыть пул-реквест на слияние release-v1.2.1 в main. Этот PR будет содержать всего один коммит: “chore: bump version to v1.2.1”. Это чистая, простая интеграция, которая поддерживает вашу основную ветку в актуальном состоянии с последней выпущенной версией.
Не выполняйте слияние обратно для предварительных релизов (RC, Beta, Dev)
Обычно вы не выполняете слияние веток релизов для предварительных релизов обратно в main.
- Почему? Предварительные версии (например, v1.3.0-rc.1, v1.3.0-rc.2) по определению не являются стабильными и временны. Вы не хотите засорять историю своей основной ветки серией изменений номеров версий для кандидатов в релизы. Файл package.json в main должен отражать последнюю стабильную версию релиза, а не RC.
- Процесс: Создается ветка release-v1.3.0-rc.1, происходит публикация npm publish —tag rc, и затем… ветка выполнила свою задачу. Вы можете просто удалить ее. Код для RC уже находится в main (или в ветке функций), поэтому никакой функциональный код не теряется. Ветка релиза была лишь временным средством для номера версии.
Локальное тестирование и валидация: Изменения в процессе упаковки и публикации
Если вам нужно протестировать процесс релиза без фактической публикации в NPM или создания публичного релиза на GitHub, вы можете запустить рабочий процесс вручную через интерфейс GitHub.
- Перейдите на вкладку Actions репозитория.
- Нажмите на выпадающий список «Run workflow».
- Оставьте опцию
dry_runотмеченной (true). - Нажмите кнопку «Run workflow».
Это запустит весь процесс релиза, но пропустит шаги npm publish и gh release create. Вы можете изучить логи рабочего процесса, чтобы убедиться, что всё работает как ожидалось.
Крайне важно тестировать любые изменения в процессе упаковки и публикации локально перед их коммитом. Это гарантирует, что пакеты будут опубликованы корректно и будут работать должным образом при установке пользователем.
Чтобы проверить ваши изменения, вы можете выполнить пробный запуск процесса публикации. При этом процесс будет смоделирован, но сами пакеты не будут опубликованы в реестре npm.
npm_package_version=9.9.9 SANDBOX_IMAGE_REGISTRY="registry" SANDBOX_IMAGE_NAME="thename" npm run publish:npm --dry-runЭта команда выполнит следующие действия:
- Соберёт все пакеты.
- Запустит все скрипты предварительной публикации.
- Создаст tar-архивы пакетов, которые должны быть опубликованы в npm.
- Выведет сводку по пакетам, которые должны быть опубликованы.
После этого вы можете проверить сгенерированные tar-архивы, чтобы убедиться, что они содержат правильные файлы, а файлы package.json обновлены корректно. Архивы будут созданы в корневой директории каждого пакета (например, packages/cli/qwen-code-0.1.6.tgz).
Выполнив пробный запуск, вы можете быть уверены, что ваши изменения в процессе упаковки корректны и пакеты будут успешно опубликованы.
Подробное описание релиза
Основная цель процесса релиза — взять исходный код из директории packages/, собрать его и создать чистый, самодостаточный пакет во временной директории dist в корне проекта. Именно содержимое этой директории dist публикуется в NPM.
Вот ключевые этапы:
Этап 1: Предварительные проверки и управление версиями
- Что происходит: Перед перемещением любых файлов процесс убеждается, что проект находится в хорошем состоянии. Это включает запуск тестов, линтинга и проверки типов (npm run preflight). Номер версии в корневом package.json и в packages/cli/package.json обновляется до новой версии релиза.
- Зачем: Это гарантирует, что в релиз попадёт только качественный и рабочий код. Управление версиями — первый шаг к обозначению нового релиза.
Этап 2: Сборка исходного кода
- Что происходит: Исходный код на TypeScript из packages/core/src и packages/cli/src компилируется в JavaScript.
- Перемещение файлов:
- packages/core/src/*/.ts -> компилируется в -> packages/core/dist/
- packages/cli/src/*/.ts -> компилируется в -> packages/cli/dist/
- Зачем: Код на TypeScript, написанный во время разработки, должен быть преобразован в обычный JavaScript, который может выполнить Node.js. Пакет core собирается первым, так как пакет cli зависит от него.
Этап 3: Бандлинг и сборка финального публикуемого пакета
Это самый важный этап, на котором файлы перемещаются и преобразуются в своё окончательное состояние для публикации. Процесс использует современные методы бандлинга для создания финального пакета.
-
Создание бандла:
- Что происходит: Скрипт prepare-package.js создаёт чистый дистрибутив в директории
dist. - Основные преобразования:
- Копируются README.md и LICENSE в dist/
- Копируется папка locales для поддержки интернационализации
- Создаётся чистый package.json для дистрибутива с минимальным набором зависимостей
- Включаются зависимости времени выполнения, такие как tiktoken
- Сохраняются необязательные зависимости для node-pty
- Что происходит: Скрипт prepare-package.js создаёт чистый дистрибутив в директории
-
Создаётся JavaScript-бандл:
- Что происходит: Собранный JavaScript из packages/core/dist и packages/cli/dist объединяется в один исполняемый файл с помощью esbuild.
- Расположение файла: dist/cli.js
- Зачем: Это создаёт один оптимизированный файл, содержащий весь необходимый код приложения. Такой подход упрощает пакет, устраняя необходимость сложного разрешения зависимостей при установке.
-
Копирование статических и вспомогательных файлов:
- Что происходит: Необходимые файлы, которые не являются частью исходного кода, но требуются для корректной работы или описания пакета, копируются в директорию
dist. - Перемещение файлов:
- README.md -> dist/README.md
- LICENSE -> dist/LICENSE
- locales/ -> dist/locales/
- Файлы поставщиков -> dist/vendor/
- Зачем:
- README.md и LICENSE — стандартные файлы, которые должны присутствовать в любом NPM-пакете.
- Папка locales обеспечивает поддержку интернационализации
- Файлы поставщиков содержат необходимые зависимости времени выполнения
- Что происходит: Необходимые файлы, которые не являются частью исходного кода, но требуются для корректной работы или описания пакета, копируются в директорию
Этап 4: Публикация в NPM
- Что происходит: Команда npm publish выполняется из корневой директории
dist. - Зачем: Выполняя npm publish из директории
dist, мы загружаем в реестр NPM только те файлы, которые были тщательно собраны на этапе 3. Это предотвращает случайную публикацию исходного кода, тестовых файлов или конфигураций разработки, обеспечивая чистый и минималистичный пакет для пользователей.
Этот процесс гарантирует, что финальный опубликованный артефакт будет целенаправленно созданным, чистым и эффективным представлением проекта, а не простой копией рабочего окружения разработки.
Рабочие области NPM
Этот проект использует рабочие области NPM для управления пакетами в этом монорепозитории. Это упрощает разработку, позволяя нам управлять зависимостями и запускать скрипты в нескольких пакетах из корня проекта.
Как это работает
Корневой файл package.json определяет рабочие области для этого проекта:
{
"workspaces": ["packages/*"]
}Это указывает NPM, что любая папка внутри директории packages является отдельным пакетом, который должен управляться как часть рабочей области.
Преимущества рабочих областей
- Упрощенное управление зависимостями: Запуск
npm installиз корня проекта установит все зависимости для всех пакетов в рабочей области и свяжет их между собой. Это означает, что вам не нужно запускатьnpm installв каждой директории пакета. - Автоматическая связь: Пакеты внутри рабочей области могут зависеть друг от друга. При запуске
npm installNPM автоматически создаст символические ссылки между пакетами. Это означает, что при внесении изменений в один пакет эти изменения сразу становятся доступны другим пакетам, которые от него зависят. - Упрощенный запуск скриптов: Вы можете запускать скрипты в любом пакете из корня проекта, используя флаг
--workspace. Например, чтобы запустить скриптbuildв пакетеcli, вы можете выполнить командуnpm run build --workspace @qwen-code/qwen-code.