Обзор пакетов
Этот монорепозиторий содержит два основных пакета: @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 со своими собственными зависимостями. Это позволяет использовать его как автономный пакет в других проектах при необходимости. В пакет включается весь транспилированный JavaScript-код из папки dist.
Процесс выпуска версий
В этом проекте используется структурированный процесс выпуска версий для обеспечения корректного версионирования и публикации всех пакетов. Данный процесс максимально автоматизирован.
Как выпустить релиз
Релизы управляются через рабочий процесс GitHub Actions release.yml . Чтобы выполнить ручной релиз для исправления или срочного обновления:
- Перейдите на вкладку Actions (Действия) репозитория.
- Выберите рабочий процесс Release (Релиз) из списка.
- Нажмите кнопку раскрывающегося меню Run workflow (Запустить рабочий процесс).
- Заполните обязательные поля:
- Version (Версия): точная версия для выпуска (например,
v0.2.1). - Ref (Ссылка): ветка или хеш коммита, из которой выполняется релиз (по умолчанию —
main). - Dry Run (Тестовый запуск): оставьте значение
true, чтобы протестировать рабочий процесс без публикации, или установитеfalse, чтобы выполнить реальный релиз.
- Version (Версия): точная версия для выпуска (например,
- Нажмите Run workflow (Запустить рабочий процесс).
Типы релизов
Проект поддерживает несколько типов релизов:
Стабильные релизы
Регулярные стабильные релизы для использования в продакшене.
Предварительные релизы
Еженедельные предварительные релизы по вторникам в 23:59 UTC для раннего доступа к новым функциям.
Еженощные релизы
Ежедневные еженощные релизы в 00:00 по UTC для тестирования самых свежих изменений в разработке.
Автоматическое расписание релизов
- Еженощный: каждый день в 00:00 по UTC
- Предварительный (Preview): каждый вторник в 23:59 по UTC
- Стабильный (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Подробности процесса выпуска
Каждый запланированный или ручной выпуск выполняется в следующем порядке:
- Извлекает указанный код (последнюю версию из ветки
mainили конкретный коммит). - Устанавливает все зависимости.
- Запускает полный набор проверок
preflightи интеграционных тестов. - Если все тесты пройдены успешно, вычисляется соответствующий номер версии на основе типа выпуска.
- Собирает пакеты и публикует их в npm с соответствующим тегом дистрибуции (
dist-tag). - Создаёт релиз в GitHub для этой версии.
Обработка сбоев
Если какой-либо шаг в рабочем процессе выпуска завершится неудачно, автоматически создаётся новая задача (issue) в репозитории с метками bug и меткой, специфичной для типа сбоя (например, nightly-failure, preview-failure). В задаче будет содержаться ссылка на неудачный запуск рабочего процесса для удобства отладки.
Проверка релиза
После публикации нового релиза необходимо выполнить дымовое тестирование, чтобы убедиться, что пакеты работают корректно. Для этого установите пакеты локально и запустите набор тестов, проверяющих их работоспособность.
npx -y @qwen-code/qwen-code@latest --version— проверьте, что публикация прошла успешно (если вы не публикуете версиюrcилиdev);npx -y @qwen-code/qwen-code@<тег_релиза> --version— проверьте, что тег был опубликован корректно;- Это приведёт к удалению пакета в локальной среде:
npm uninstall @qwen-code/qwen-code && npm uninstall -g @qwen-code/qwen-code && npm cache clean --force && npm install @qwen-code/qwen-code@<версия>; - Рекомендуется провести дымовое тестирование, выполнив базовый сценарий с несколькими командами LLM и инструментами, чтобы убедиться в ожидаемой работоспособности пакетов. В будущем мы формализуем этот процесс.
Когда следует объединять изменение версии, а когда — нет?
Приведённый выше подход к созданию патч- или «горячих» исправлений из текущих или более старых коммитов оставляет репозиторий в следующем состоянии:
- Тег (
vX.Y.Z-patch.1): Этот тег корректно указывает на исходный коммит в веткеmain, содержащий стабильный код, который вы намеревались выпустить. Это крайне важно: любой, кто выполняетcheckoutэтого тега, получает именно тот код, который был опубликован. - Ветка (
release-vX.Y.Z-patch.1): Эта ветка содержит один новый коммит поверх помеченного коммита. В этом новом коммите изменяется только номер версии в файлеpackage.json(и других связанных файлах, например,package-lock.json).
Такое разделение полезно: оно сохраняет историю основной ветки main чистой от изменений номеров версий, связанных с релизами, до тех пор, пока вы не примете решение объединить их.
Это ключевое решение, и оно полностью зависит от характера выпускаемой версии.
Объединение обратно для стабильных исправлений и срочных исправлений
Для любого выпуска стабильного исправления или срочного исправления вы почти всегда должны объединить ветку release-<tag> обратно в main.
- Почему? Основная причина — обновление версии в файле
package.jsonосновной ветки. Если вы выпустили версиюv1.2.1из более старого коммита, но не объединили повышение версии обратно, в файлеpackage.jsonосновной ветки по-прежнему будет указано"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». Это чистая и простая интеграция, которая поддерживает основную ветку в актуальном состоянии с последней выпущенной версией.
НЕ СЛИВАЙТЕ ОБРАТНО ВЕТКИ ДЛЯ ПРЕДВАРИТЕЛЬНЫХ ВЫПУСКОВ (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Эта команда выполнит следующие действия:
- Сборку всех пакетов.
- Запуск всех скриптов prepublish.
- Создание 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для дистрибуции, содержащий только необходимые зависимости - Поддерживает минимальный набор зависимостей для дистрибуции (без зависимостей среды выполнения, включённых в сборку)
- Сохраняет опциональные зависимости для
node-pty
- Копирует файлы
- Что происходит: Скрипт
-
Создание JavaScript-сборки:
- Что происходит: Скомпилированный JavaScript из каталогов
packages/core/distиpackages/cli/distобъединяется в один исполняемый JavaScript-файл с помощьюesbuild. - Расположение файла:
dist/cli.js - Зачем это нужно: Это создаёт единый оптимизированный файл, содержащий весь необходимый код приложения. Такой подход упрощает пакет, устраняя необходимость сложного разрешения зависимостей во время установки.
- Что происходит: Скомпилированный JavaScript из каталогов
-
Копирование статических и вспомогательных файлов:
- Что происходит: Копируются важные файлы, не являющиеся частью исходного кода, но необходимые для корректной работы пакета или его надлежащего описания.
- Перемещение файлов:
README.md→dist/README.mdLICENSE→dist/LICENSElocales/→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.