Обзор пакетов
Этот монорепозиторий содержит два основных пакета: @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 workflow release.yml . Чтобы выполнить ручной релиз для патча или хотфикса:
- Перейдите на вкладку Actions репозитория.
- Выберите Release workflow из списка.
- Нажмите на выпадающую кнопку Run workflow.
- Заполните необходимые поля:
- Version: точная версия для релиза (например,
v0.2.1). - Ref: ветка или SHA коммита, с которой делать релиз (по умолчанию
main). - Dry Run: оставьте
true, чтобы протестировать workflow без публикации, или установитеfalseдля реального релиза.
- Version: точная версия для релиза (например,
- Нажмите Run workflow.
Типы релизов
Проект поддерживает несколько типов релизов:
Стабильные релизы
Обычные стабильные релизы для использования в production.
Preview-релизы
Еженедельные preview-релизы каждый вторник в 23:59 UTC для раннего доступа к будущим функциям.
Nightly-релизы
Ежедневные nightly-релизы в полночь UTC для тестирования самых новых изменений.
Расписание автоматических релизов
- Nightly: каждый день в полночь UTC
- Preview: каждый вторник в 23:59 UTC
- Stable: ручные релизы, инициируемые мейнтейнерами
Как использовать разные типы релизов
Чтобы установить последнюю версию каждого типа:
# Stable (по умолчанию)
npm install -g @qwen-code/qwen-code
# Preview
npm install -g @qwen-code/qwen-code@preview
# Nightly
npm install -g @qwen-code/qwen-code@nightlyДетали процесса релиза
Каждый запланированный или ручной релиз выполняется по следующим шагам:
- Выполняется checkout указанного кода (последняя версия из ветки
mainили конкретный коммит). - Устанавливаются все зависимости.
- Запускается полный набор
preflightпроверок и интеграционных тестов. - Если все тесты успешны, вычисляется соответствующий номер версии на основе типа релиза.
- Сборка и публикация пакетов в npm с соответствующим dist-tag.
- Создание GitHub Release для этой версии.
Обработка сбоев
Если какой-либо шаг workflow релиза завершается неудачей, автоматически создаётся новый issue в репозитории с метками bug и меткой сбоя, специфичной для типа (например, nightly-failure, preview-failure). Issue будет содержать ссылку на неудачный запуск workflow для упрощения отладки.
Валидация релиза
После публикации нового релиза следует выполнить smoke-тестирование, чтобы убедиться, что пакеты работают корректно. Это можно сделать, установив пакеты локально и запустив набор тестов.
npx -y @qwen-code/qwen-code@latest --version— проверить, что пуш прошёл успешно (если вы не использовали rc или dev тег)npx -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> - Рекомендуется выполнить smoke-тестирование с базовым прогоном нескольких команд и инструментов LLM, чтобы убедиться, что пакеты работают ожидаемым образом. В будущем мы более формализуем этот процесс.
Когда нужно сливать изменения версии, а когда нет?
Описанный выше шаблон создания патч-релизов или хотфиксов из текущих или старых коммитов оставляет репозиторий в следующем состоянии:
- Тег (
vX.Y.Z-patch.1): Этот тег правильно указывает на исходный коммит в main, содержащий стабильный код, который вы планировали выпустить. Это критически важно. Любой, кто проверит этот тег, получит именно тот код, который был опубликован. - Ветка (
release-vX.Y.Z-patch.1): Эта ветка содержит один новый коммит поверх тегированного коммита. Этот новый коммит содержит только изменение номера версии в package.json (и других связанных файлах, например package-lock.json).
Такое разделение — хорошая практика. Оно сохраняет историю вашей ветки main чистой от релиз-специфичных версионных бампов до тех пор, пока вы не решите их слить.
Это критическое решение, и оно полностью зависит от характера релиза.
Сливайте обратно для стабильных патчей и хотфиксов
Почти всегда следует сливать ветку release-<tag> обратно в main для любого стабильного патча или хотфикса.
- Почему? Основная причина — обновление версии в package.json ветки main. Если вы выпустили v1.2.1 из старого коммита, но никогда не сливаете бамп версии обратно, то в package.json ветки main по-прежнему будет указано
"version": "1.2.0". Следующий разработчик, который начнёт работу над следующим функциональным релизом (v1.3.0), будет создавать ветку из кодовой базы с некорректным, старым номером версии. Это приводит к путанице и требует ручного бампа версии позже. - Процесс: После создания ветки release-v1.2.1 и успешной публикации пакета следует открыть pull request на слияние release-v1.2.1 в main. Этот PR будет содержать один коммит: “chore: bump version to v1.2.1”. Это чистое, простое слияние, которое поддерживает вашу ветку main в актуальном состоянии с последней выпущенной версией.
НЕ сливайте обратно для пре-релизов (RC, Beta, Dev)
Обычно не следует сливать релизные ветки для пре-релизов обратно в main.
- Почему? Пре-релизные версии (например, v1.3.0-rc.1, v1.3.0-rc.2) по определению не являются стабильными и временны. Вы не хотите загромождать историю своей ветки main серией версионных бампов для кандидатов в релиз. package.json в main должен отражать последнюю стабильную версию, а не RC.
- Процесс: Создаётся ветка release-v1.3.0-rc.1, происходит npm publish —tag rc, а затем… ветка выполнила свою задачу. Её можно просто удалить. Код для RC уже находится в main (или в функциональной ветке), поэтому никакой функциональный код не теряется. Релизная ветка была лишь временным средством для номера версии.
Локальное тестирование и валидация изменений в процессе упаковки и публикации
Если вам нужно протестировать процесс релиза без фактической публикации в NPM или создания публичного GitHub Release, вы можете вручную запустить workflow из интерфейса GitHub.
- Перейдите на вкладку Actions репозитория.
- Нажмите на выпадающий список “Run workflow”.
- Оставьте опцию
dry_runотмеченной (true). - Нажмите кнопку “Run workflow”.
Это запустит весь процесс релиза, но пропустит шаги npm publish и gh release create. Вы можете просмотреть логи workflow, чтобы убедиться, что всё работает ожидаемым образом.
Крайне важно тестировать любые изменения в процессе упаковки и публикации локально перед их коммитом. Это гарантирует, что пакеты будут опубликованы корректно и будут работать должным образом при установке пользователем.
Чтобы проверить ваши изменения, вы можете выполнить сухой прогон процесса публикации. Он имитирует публикацию, не отправляя пакеты в npm registry.
npm_package_version=9.9.9 SANDBOX_IMAGE_REGISTRY="registry" SANDBOX_IMAGE_NAME="thename" npm run publish:npm --dry-runЭта команда сделает следующее:
- Соберёт все пакеты.
- Выполнит все prepublish скрипты.
- Создаёт tarball’ы пакетов, которые были бы опубликованы в npm.
- Выведет сводку пакетов, которые были бы опубликованы.
Затем вы можете проверить сгенерированные tarball’ы, чтобы убедиться, что они содержат правильные файлы и что файлы package.json обновлены корректно. Tarball’ы будут созданы в корне каждого каталога пакета (например, 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: Сборка (bundling) и формирование финального публикуемого пакета
Это самый важный этап, на котором файлы перемещаются и преобразуются в финальное состояние для публикации. Процесс использует современные техники сборки для создания итогового пакета.
-
Создание бандла:
- Что происходит: Скрипт prepare-package.js создаёт чистый дистрибутивный пакет в каталоге
dist. - Ключевые преобразования:
- Копирует README.md и LICENSE в dist/
- Копирует папку locales для интернационализации
- Создаёт чистый package.json для дистрибутива, содержащий только необходимые зависимости
- Минимизирует зависимости дистрибутива (без встроенных runtime-зависимостей)
- Сохраняет опциональные зависимости для node-pty
- Что происходит: Скрипт prepare-package.js создаёт чистый дистрибутивный пакет в каталоге
-
Создание JavaScript-бандла:
- Что происходит: Собранный JavaScript из packages/core/dist и packages/cli/dist объединяется в единый исполняемый JS-файл с помощью esbuild.
- Расположение файла: dist/cli.js
- Почему: Это создаёт единственный оптимизированный файл, содержащий весь необходимый код приложения. Это упрощает пакет, устраняя необходимость в сложном разрешении зависимостей во время установки.
-
Копирование статических и вспомогательных файлов:
- Что происходит: Основные файлы, которые не являются частью исходного кода, но необходимы для правильной работы пакета или его описания, копируются в каталог
dist. - Перемещение файлов:
- README.md -> dist/README.md
- LICENSE -> dist/LICENSE
- locales/ -> dist/locales/
- Файлы вендоров -> dist/vendor/
- Почему:
- README.md и LICENSE — стандартные файлы, которые должны быть включены в любой NPM-пакет.
- Locales поддерживают функции интернационализации.
- Файлы вендоров содержат необходимые runtime-зависимости.
- Что происходит: Основные файлы, которые не являются частью исходного кода, но необходимы для правильной работы пакета или его описания, копируются в каталог
Этап 4: Публикация в NPM
- Что происходит: Команда
npm publishзапускается из корневого каталогаdist. - Почему: Запуская npm publish из каталога
dist, мы гарантируем, что в NPM registry будут загружены только те файлы, которые мы тщательно собрали на Этапе 3. Это предотвращает случайную публикацию исходного кода, тестовых файлов или конфигураций разработки, в результате чего пользователи получают чистый и минимальный пакет.
Этот процесс гарантирует, что финальный опубликованный артефакт представляет собой целенаправленное, чистое и эффективное представление проекта, а не прямую копию рабочего пространства разработки.
NPM Workspaces
В этом проекте используются NPM Workspaces для управления пакетами в рамках монорепозитория. Это упрощает разработку, позволяя управлять зависимостями и запускать скрипты для нескольких пакетов из корня проекта.
Как это работает
Корневой файл package.json определяет workspaces для этого проекта:
{
"workspaces": ["packages/*"]
}Это сообщает NPM, что любая папка внутри каталога packages является отдельным пакетом, который должен управляться как часть workspace.
Преимущества Workspaces
- Упрощённое управление зависимостями: Выполнение
npm installиз корня проекта установит все зависимости для всех пакетов в workspace и свяжет их вместе. Это означает, что вам не нужно запускатьnpm installв каждом каталоге пакета. - Автоматическая привязка: Пакеты внутри workspace могут зависеть друг от друга. При выполнении
npm installNPM автоматически создаёт симлинки между пакетами. Это означает, что когда вы вносите изменения в один пакет, эти изменения немедленно становятся доступны другим пакетам, которые от него зависят. - Упрощённое выполнение скриптов: Вы можете запускать скрипты в любом пакете из корня проекта, используя флаг
--workspace. Например, чтобы запустить скриптbuildв пакетеcli, вы можете выполнитьnpm run build --workspace @qwen-code/qwen-code.