パッケージ概要
このモノレポには、2つの主要なパッケージが含まれています:@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 パッケージとして公開されます。これにより、必要に応じて他のプロジェクトでスタンドアロンのパッケージとして利用できます。dist フォルダー内のすべてのトランスパイル済み JavaScript コードがパッケージに含まれます。
リリースプロセス
本プロジェクトでは、すべてのパッケージが適切にバージョン管理・公開されるよう、構造化されたリリースプロセスを採用しています。このプロセスは、可能な限り自動化されるよう設計されています。
リリース手順
リリースは、release.yml GitHub Actions ワークフローによって管理されます。パッチまたはホットフィックスの手動リリースを行うには、以下の手順に従ってください。
- リポジトリの Actions タブに移動します。
- 一覧から Release ワークフローを選択します。
- Run workflow ドロップダウンボタンをクリックします。
- 必須入力項目を入力します:
- Version: リリースする正確なバージョン(例:
v0.2.1)。 - Ref: リリース元のブランチまたはコミット SHA(デフォルトは
main)。 - Dry Run: ワークフローを実行して公開せずにテストする場合は
trueのままにし、本番リリースを実行する場合はfalseに設定します。
- Version: リリースする正確なバージョン(例:
- Run workflow をクリックします。
リリースの種類
本プロジェクトでは、複数種類のリリースをサポートしています。
安定版リリース(Stable Releases)
本番環境での使用を目的とした通常の安定版リリースです。
プレビュー版リリース(Preview Releases)
次期機能への早期アクセスを可能にするため、毎週火曜日 23:59 UTC に配信されるプレビュー版リリースです。
夜間ビルド版(Nightly Releases)
最新の開発版をテストするため、UTC 時間で毎日深夜 0 時に自動的にリリースされます。
自動化されたリリーススケジュール
- 夜間ビルド版(Nightly): UTC 時間で毎日深夜 0 時
- プレビュー版(Preview): UTC 時間で毎週火曜日 23:59
- 安定版(Stable): メンテナーが手動でトリガーするリリース
各リリースタイプの使用方法
各タイプの最新版をインストールするには、以下のようにします:
# 安定版(デフォルト)
npm install -g @qwen-code/qwen-code
# プレビュー版
npm install -g @qwen-code/qwen-code@preview
# 夜間ビルド版
npm install -g @qwen-code/qwen-code@nightlyリリース手順の詳細
スケジュールされたリリースまたは手動によるリリースは、以下の手順に従います。
- 指定されたコード(
mainブランチの最新版、または特定のコミット)をチェックアウトします。 - すべての依存関係をインストールします。
preflightチェックおよび統合テストのフルセットを実行します。- すべてのテストが成功した場合、リリースの種類に基づいて適切なバージョン番号を算出します。
- パッケージをビルドし、適切な dist-tag を付けて npm に公開します。
- 当該バージョン向けの GitHub Release を作成します。
エラー処理
リリースワークフローのいずれかのステップで失敗した場合、自動的にリポジトリに新しい Issue を作成し、ラベルとして bug と、失敗の種類に応じたラベル(例:nightly-failure、preview-failure)が付与されます。この Issue には、デバッグを容易にするため、失敗したワークフロー実行へのリンクが含まれます。
リリース検証
新しいリリースをプッシュした後は、パッケージが期待通りに動作することを確認するためにスモークテストを実行する必要があります。これは、パッケージをローカルにインストールし、それらが正しく機能していることを保証する一連のテストを実行することで行います。
rcタグやdevタグでない場合:npx -y @qwen-code/qwen-code@latest --versionを実行して、プッシュが期待通りに完了したかを検証します。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ブランチ上の元のコミットを正しく指しています。これは極めて重要です。このタグをチェックアウトする誰もが、実際に公開されたコードと完全に一致するものを取得できます。 - ブランチ (
release-vX.Y.Z-patch.1):このブランチは、タグ付けされたコミットの上に新しいコミットを 1 つ追加した状態です。その新しいコミットには、package.json(およびpackage-lock.jsonなどの関連ファイル)におけるバージョン番号の変更のみが含まれます。
この分離は望ましいものです。これにより、リリース固有のバージョンアップが main ブランチの履歴に反映されるのを、あなたが明示的にマージすることを決めるまで防ぐことができます。
これは極めて重要な判断であり、その判断はリリースの性質に完全に依存します。
安定版パッチおよび緊急修正のマージバック
安定版パッチまたは緊急修正リリースを行う際は、release-<tag> ブランチを main にマージバックするのがほとんど常に推奨されます。
- なぜですか? 主な理由は、
mainのpackage.jsonに記載されたバージョン番号を更新するためです。古いコミットから v1.2.1 をリリースしたにもかかわらず、そのバージョン番号の更新をmainにマージしなかった場合、mainブランチのpackage.jsonには依然として"version": "1.2.0"と記載されたままになります。次に、次の機能リリース(v1.3.0)の作業を開始する開発者は、誤った古いバージョン番号が記載されたコードベースからブランチを作成することになり、混乱を招き、後で手動でのバージョンアップが必要になる可能性があります。 - 手順:
release-v1.2.1ブランチが作成され、パッケージが正常に公開された後、release-v1.2.1をmainへマージするプルリクエストを開きます。このプルリクエストには、単一のコミット——「chore: bump version to v1.2.1」——のみが含まれます。これは、最新のリリースバージョンとmainブランチの状態を確実に同期させる、明確かつシンプルな統合プロセスです。
プレリリース(RC、ベータ、開発版)のマージは行わない
通常、プレリリース用のリリースブランチを main にマージしません。
- 理由: プレリリース版(例:v1.3.0-rc.1、v1.3.0-rc.2)は、定義上安定しておらず一時的なものです。リリース候補版のための一連のバージョンアップが
mainブランチの履歴に混入することを避けたいからです。mainのpackage.jsonには最新の安定版のバージョンが記載されるべきであり、RC のバージョンではありません。 - 手順:
release-v1.3.0-rc.1ブランチを作成し、npm publish --tag rcを実行した後、そのブランチの役目は終了します。単に削除すればよいだけです。RC のコードは既にmain(または機能ブランチ)上に存在するため、機能的なコードは失われません。このリリースブランチは、単にバージョン番号を付与するための一時的な手段に過ぎません。
ローカルでのテストおよび検証:パッケージングおよび公開プロセスの変更
NPM への実際の公開や GitHub 上でのパブリックリリースの作成を伴わずにリリースプロセスをテストする必要がある場合、GitHub の UI からワークフローを手動でトリガーできます。
- リポジトリの Actions タブ に移動します。
- 「Run workflow」ドロップダウンをクリックします。
dry_runオプションがチェックされた状態(true)のままにします。- 「Run workflow」ボタンをクリックします。
これにより、リリースプロセス全体が実行されますが、npm publish および gh release create ステップはスキップされます。ワークフローログを確認して、すべてが期待通りに動作していることを確認できます。
パッケージングおよび公開プロセスに対する変更をコミットする前に、必ずローカルでテストを行うことが重要です。これにより、パッケージが正しく公開され、ユーザーがインストールした際にも期待通りに動作することを保証できます。
変更内容を検証するには、公開プロセスのダミー実行(dry run)を実行できます。これにより、パッケージを npm レジストリに実際に公開することなく、公開プロセスをシミュレートできます。
npm_package_version=9.9.9 SANDBOX_IMAGE_REGISTRY="registry" SANDBOX_IMAGE_NAME="thename" npm run publish:npm --dry-runこのコマンドは以下の処理を行います:
- すべてのパッケージをビルドします。
- すべての prepublish スクリプトを実行します。
- npm に公開される予定のパッケージ tarball を作成します。
- 公開される予定のパッケージの概要を出力します。
その後、生成された 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:ソースコードのビルド
- 実行内容:
packages/core/srcおよびpackages/cli/src内の TypeScript ソースコードを JavaScript にコンパイルします。 - ファイルの移動先:
packages/core/src/**/*.ts→ コンパイル後 →packages/core/dist/packages/cli/src/**/*.ts→ コンパイル後 →packages/cli/dist/
- 目的:開発中に記述された TypeScript コードを、Node.js で実行可能な純粋な JavaScript に変換する必要があります。
coreパッケージはcliパッケージに依存しているため、まずcoreをビルドします。
ステージ 3:最終公開用パッケージのバンドルおよび構築
これは、ファイルの移動・変換を行い、公開用の最終状態に整える最も重要なステージです。このプロセスでは、最新のバンドル技術を用いて最終パッケージを作成します。
-
バンドルの作成:
- 実行内容:
prepare-package.jsスクリプトが、クリーンな配布用パッケージをdistディレクトリ内に生成します。 - 主な変換処理:
README.mdおよびLICENSEをdist/にコピー- 国際化対応のため
localesフォルダーをコピー - 必要最小限の依存関係のみを含む、配布用のクリーンな
package.jsonを作成 - 配布用依存関係を最小限に保つ(ランタイム依存関係はバンドルしない)
node-ptyのオプション依存関係は維持
- 実行内容:
-
JavaScript バンドルの作成:
- 実行内容:
packages/core/distおよびpackages/cli/distからビルド済みの JavaScript を、esbuildを用いて単一の実行可能 JavaScript ファイルにバンドルします。 - 出力先:
dist/cli.js - 目的:アプリケーションコードをすべて含む、最適化された単一ファイルを作成します。これにより、インストール時の複雑な依存解決を不要とし、パッケージを簡素化します。
- 実行内容:
-
静的ファイルおよび補助ファイルのコピー:
- 実行内容:ソースコードには含まれないものの、パッケージの正しく動作または適切な説明のために必須となるファイルを
distディレクトリにコピーします。 - ファイルの移動先:
README.md→dist/README.mdLICENSE→dist/LICENSElocales/→dist/locales/- ベンダーファイル →
dist/vendor/
- 目的:
README.mdおよびLICENSEは、あらゆる NPM パッケージに含めるべき標準ファイルです。localesは国際化機能をサポートします。- ベンダーファイルには、必要なランタイム依存関係が含まれます。
- 実行内容:ソースコードには含まれないものの、パッケージの正しく動作または適切な説明のために必須となるファイルを
ステージ 4:NPM への公開
- 実行内容:ルートの
distディレクトリ内でnpm publishコマンドを実行します。 - 目的:
distディレクトリ内でnpm publishを実行することで、ステージ 3 で厳密に構築したファイルのみが NPM レジストリにアップロードされます。これにより、ソースコード、テストファイル、開発用設定などが誤って公開されるのを防ぎ、ユーザーにとってクリーンで最小限のパッケージを提供できます。
このプロセスにより、最終的に公開される成果物は、開発ワークスペースの単なるコピーではなく、目的に特化し、クリーンで効率的なプロジェクト表現となります。
NPM ワークスペース
このプロジェクトでは、NPM ワークスペース を使用して、このモノレポ内のパッケージを管理しています。これにより、依存関係の管理や複数のパッケージに対するスクリプト実行を、プロジェクトのルートから一元的に行えるようになり、開発が簡素化されます。
動作原理
ルートの package.json ファイルで、このプロジェクトのワークスペースが定義されています:
{
"workspaces": ["packages/*"]
}これは、packages ディレクトリ内のすべてのフォルダーが、ワークスペースの一部として管理される個別のパッケージであることを NPM に指示します。
ワークスペースのメリット
- 依存関係管理の簡素化: プロジェクトのルートから
npm installを実行すると、ワークスペース内のすべてのパッケージの依存関係が一括でインストールされ、相互にリンクされます。これにより、各パッケージのディレクトリ内で個別にnpm installを実行する必要がなくなります。 - 自動リンク機能: ワークスペース内のパッケージは互いに依存関係を持つことができます。
npm installを実行すると、NPM がパッケージ間で自動的にシンボリックリンクを作成します。そのため、あるパッケージを変更した場合、その変更は依存している他のパッケージですぐに利用可能になります。 - スクリプト実行の簡素化:
--workspaceフラグを使用することで、プロジェクトのルートから任意のパッケージ内のスクリプトを実行できます。たとえば、cliパッケージ内のbuildスクリプトを実行するには、npm run build --workspace @qwen-code/qwen-codeを実行します。