From c630d78806ae9ad8ba854ac9ac7ce897127191cc Mon Sep 17 00:00:00 2001 From: nrslib <38722970+nrslib@users.noreply.github.com> Date: Sun, 22 Feb 2026 10:50:50 +0900 Subject: [PATCH] refactor: rename ensemble to repertoire across codebase --- CHANGELOG.md | 2 +- docs/CHANGELOG.ja.md | 14 +-- docs/README.ja.md | 6 +- docs/cli-reference.ja.md | 14 +-- docs/cli-reference.md | 14 +-- docs/{ensemble.ja.md => repertoire.ja.md} | 50 ++++---- docs/{ensemble.md => repertoire.md} | 50 ++++---- e2e/specs/piece-selection-branches.e2e.ts | 10 +- ...ble-real.e2e.ts => repertoire-real.e2e.ts} | 54 ++++---- .../{ensemble.e2e.ts => repertoire.e2e.ts} | 118 +++++++++--------- .../faceted-prompting/scope-ref.test.ts | 44 +++---- ...-helpers.ts => repertoire-test-helpers.ts} | 2 +- src/__tests__/piece-category-config.test.ts | 30 ++--- src/__tests__/pieceLoader.test.ts | 38 +++--- ...st.ts => repertoire-atomic-update.test.ts} | 10 +- ...st.ts => repertoire-ref-integrity.test.ts} | 42 +++---- ...t.ts => repertoire-scope-resolver.test.ts} | 86 ++++++------- .../atomic-update.test.ts | 2 +- .../file-filter.test.ts | 4 +- .../github-ref-resolver.test.ts | 2 +- .../github-spec.test.ts | 2 +- .../{ensemble => repertoire}/list.test.ts | 74 +++++------ .../lock-file.test.ts | 8 +- .../pack-summary.test.ts | 2 +- .../package-facet-resolution.test.ts | 68 +++++----- .../remove-reference-check.test.ts | 4 +- .../{ensemble => repertoire}/remove.test.ts | 24 ++-- .../repertoire-paths.test.ts} | 52 ++++---- .../takt-repertoire-config.test.ts} | 96 +++++++------- .../tar-parser.test.ts | 2 +- src/__tests__/selectAndExecute-autoPr.test.ts | 8 +- ...test.ts => takt-repertoire-schema.test.ts} | 30 ++--- src/app/cli/commands.ts | 30 ++--- src/commands/{ensemble => repertoire}/add.ts | 48 +++---- src/commands/{ensemble => repertoire}/list.ts | 10 +- .../{ensemble => repertoire}/remove.ts | 14 +-- src/faceted-prompting/scope.ts | 18 +-- src/features/ensemble/constants.ts | 6 - .../{ensemble => repertoire}/atomic-update.ts | 0 src/features/repertoire/constants.ts | 12 ++ .../{ensemble => repertoire}/file-filter.ts | 8 +- .../github-ref-resolver.ts | 2 +- .../{ensemble => repertoire}/github-spec.ts | 2 +- src/features/{ensemble => repertoire}/list.ts | 34 ++--- .../{ensemble => repertoire}/lock-file.ts | 6 +- .../{ensemble => repertoire}/pack-summary.ts | 0 .../{ensemble => repertoire}/remove.ts | 4 +- .../takt-repertoire-config.ts} | 36 +++--- .../{ensemble => repertoire}/tar-parser.ts | 0 src/infra/config/loaders/agentLoader.ts | 4 +- src/infra/config/loaders/pieceCategories.ts | 14 +-- src/infra/config/loaders/pieceParser.ts | 4 +- src/infra/config/loaders/pieceResolver.ts | 32 ++--- src/infra/config/loaders/resource-resolver.ts | 52 ++++---- src/infra/config/paths.ts | 23 ++-- src/shared/prompt/confirm.ts | 2 +- 56 files changed, 665 insertions(+), 658 deletions(-) rename docs/{ensemble.ja.md => repertoire.ja.md} (68%) rename docs/{ensemble.md => repertoire.md} (66%) rename e2e/specs/{ensemble-real.e2e.ts => repertoire-real.e2e.ts} (71%) rename e2e/specs/{ensemble.e2e.ts => repertoire.e2e.ts} (66%) rename src/__tests__/helpers/{ensemble-test-helpers.ts => repertoire-test-helpers.ts} (87%) rename src/__tests__/{ensemble-atomic-update.test.ts => repertoire-atomic-update.test.ts} (94%) rename src/__tests__/{ensemble-ref-integrity.test.ts => repertoire-ref-integrity.test.ts} (67%) rename src/__tests__/{ensemble-scope-resolver.test.ts => repertoire-scope-resolver.test.ts} (74%) rename src/__tests__/{ensemble => repertoire}/atomic-update.test.ts (98%) rename src/__tests__/{ensemble => repertoire}/file-filter.test.ts (98%) rename src/__tests__/{ensemble => repertoire}/github-ref-resolver.test.ts (97%) rename src/__tests__/{ensemble => repertoire}/github-spec.test.ts (97%) rename src/__tests__/{ensemble => repertoire}/list.test.ts (67%) rename src/__tests__/{ensemble => repertoire}/lock-file.test.ts (95%) rename src/__tests__/{ensemble => repertoire}/pack-summary.test.ts (99%) rename src/__tests__/{ensemble => repertoire}/package-facet-resolution.test.ts (73%) rename src/__tests__/{ensemble => repertoire}/remove-reference-check.test.ts (94%) rename src/__tests__/{ensemble => repertoire}/remove.test.ts (82%) rename src/__tests__/{ensemble/ensemble-paths.test.ts => repertoire/repertoire-paths.test.ts} (78%) rename src/__tests__/{ensemble/takt-pack-config.test.ts => repertoire/takt-repertoire-config.test.ts} (78%) rename src/__tests__/{ensemble => repertoire}/tar-parser.test.ts (98%) rename src/__tests__/{takt-pack-schema.test.ts => takt-repertoire-schema.test.ts} (67%) rename src/commands/{ensemble => repertoire}/add.ts (79%) rename src/commands/{ensemble => repertoire}/list.ts (56%) rename src/commands/{ensemble => repertoire}/remove.ts (75%) delete mode 100644 src/features/ensemble/constants.ts rename src/features/{ensemble => repertoire}/atomic-update.ts (100%) create mode 100644 src/features/repertoire/constants.ts rename src/features/{ensemble => repertoire}/file-filter.ts (94%) rename src/features/{ensemble => repertoire}/github-ref-resolver.ts (95%) rename src/features/{ensemble => repertoire}/github-spec.ts (96%) rename src/features/{ensemble => repertoire}/list.ts (65%) rename src/features/{ensemble => repertoire}/lock-file.ts (90%) rename src/features/{ensemble => repertoire}/pack-summary.ts (100%) rename src/features/{ensemble => repertoire}/remove.ts (97%) rename src/features/{ensemble/takt-pack-config.ts => repertoire/takt-repertoire-config.ts} (79%) rename src/features/{ensemble => repertoire}/tar-parser.ts (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e24a41..cbffe48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,7 +30,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Internal -- Comprehensive ensemble test suite: atomic-update, ensemble-paths, file-filter, github-ref-resolver, github-spec, list, lock-file, pack-summary, package-facet-resolution, remove-reference-check, remove, takt-pack-config, tar-parser, takt-pack-schema +- Comprehensive ensemble test suite: atomic-update, ensemble-paths, file-filter, github-ref-resolver, github-spec, list, lock-file, pack-summary, package-facet-resolution, remove-reference-check, remove, takt-ensemble-config, tar-parser, takt-ensemble-schema - Added `src/faceted-prompting/scope.ts` for @scope reference parsing, validation, and resolution - Added scope-ref tests for the faceted-prompting module - Added `inputWait.ts` for shared input-wait state to suppress worker pool log noise diff --git a/docs/CHANGELOG.ja.md b/docs/CHANGELOG.ja.md index ae203ae..5c7d9b4 100644 --- a/docs/CHANGELOG.ja.md +++ b/docs/CHANGELOG.ja.md @@ -10,10 +10,10 @@ ### Added -- **Ensemble パッケージシステム** (`takt ensemble add/remove/list`): GitHub から外部 TAKT パッケージをインポート・管理 — `takt ensemble add github:{owner}/{repo}@{ref}` でパッケージを `~/.takt/ensemble/` にダウンロード。アトミックなインストール、バージョン互換チェック、ロックファイル生成、確認前のパッケージ内容サマリ表示に対応 -- **@scope 参照**: piece YAML のファセット参照で `@{owner}/{repo}/{facet-name}` 構文をサポート — インストール済み ensemble パッケージのファセットを直接参照可能(例: `persona: @nrslib/takt-fullstack/expert-coder`) -- **4層ファセット解決**: 3層(project → user → builtin)から4層(package-local → project → user → builtin)に拡張 — ensemble パッケージのピースは自パッケージ内のファセットを最優先で解決 -- **ピース選択に ensemble カテゴリ追加**: インストール済みの ensemble パッケージがピース選択 UI の「ensemble」カテゴリにサブカテゴリとして自動表示 +- **Repertoire パッケージシステム** (`takt repertoire add/remove/list`): GitHub から外部 TAKT パッケージをインポート・管理 — `takt repertoire add github:{owner}/{repo}@{ref}` でパッケージを `~/.takt/repertoire/` にダウンロード。アトミックなインストール、バージョン互換チェック、ロックファイル生成、確認前のパッケージ内容サマリ表示に対応 +- **@scope 参照**: piece YAML のファセット参照で `@{owner}/{repo}/{facet-name}` 構文をサポート — インストール済み repertoire パッケージのファセットを直接参照可能(例: `persona: @nrslib/takt-fullstack/expert-coder`) +- **4層ファセット解決**: 3層(project → user → builtin)から4層(package-local → project → user → builtin)に拡張 — repertoire パッケージのピースは自パッケージ内のファセットを最優先で解決 +- **ピース選択に repertoire カテゴリ追加**: インストール済みの repertoire パッケージがピース選択 UI の「repertoire」カテゴリにサブカテゴリとして自動表示 - **implement/fix インストラクションにビルドゲート追加**: `implement` と `fix` のビルトインインストラクションでテスト実行前にビルド(型チェック)の実行を必須化 ### Changed @@ -22,15 +22,15 @@ ### Fixed -- オーバーライドピースの検証が ensemble スコープを含むリゾルバー経由で実行されるよう修正 +- オーバーライドピースの検証が repertoire スコープを含むリゾルバー経由で実行されるよう修正 - `takt export-cc` が新しい `builtins/{lang}/facets/` ディレクトリ構造からファセットを読み込むよう修正 -- `confirm()` プロンプトがパイプ経由の stdin に対応(例: `echo "y" | takt ensemble add ...`) +- `confirm()` プロンプトがパイプ経由の stdin に対応(例: `echo "y" | takt repertoire add ...`) - イテレーション入力待ち中の `poll_tick` デバッグログ連続出力を抑制 - ピースリゾルバーの `stat()` 呼び出しでアクセス不能エントリ時にクラッシュせずエラーハンドリング ### Internal -- Ensemble テストスイート: atomic-update, ensemble-paths, file-filter, github-ref-resolver, github-spec, list, lock-file, pack-summary, package-facet-resolution, remove-reference-check, remove, takt-pack-config, tar-parser, takt-pack-schema +- Repertoire テストスイート: atomic-update, repertoire-paths, file-filter, github-ref-resolver, github-spec, list, lock-file, pack-summary, package-facet-resolution, remove-reference-check, remove, takt-repertoire-config, tar-parser, takt-repertoire-schema - `src/faceted-prompting/scope.ts` を追加(@scope 参照のパース・バリデーション・解決) - faceted-prompting モジュールの scope-ref テストを追加 - `inputWait.ts` を追加(ワーカープールのログノイズ抑制のための入力待ち状態共有) diff --git a/docs/README.ja.md b/docs/README.ja.md index 82df398..8329d44 100644 --- a/docs/README.ja.md +++ b/docs/README.ja.md @@ -156,7 +156,7 @@ movements: | `takt #N` | GitHub Issue をタスクとして実行します | | `takt switch` | 使う piece を切り替えます | | `takt eject` | ビルトインの piece/persona をコピーしてカスタマイズできます | -| `takt ensemble add` | GitHub から ensemble パッケージをインストールします | +| `takt repertoire add` | GitHub から repertoire パッケージをインストールします | 全コマンド・オプションは [CLI Reference](./cli-reference.ja.md) を参照してください。 @@ -225,7 +225,7 @@ takt --pipeline --task "バグを修正して" --auto-pr ├── config.yaml # プロバイダー、モデル、言語など ├── pieces/ # ユーザー定義の piece ├── facets/ # ユーザー定義のファセット(personas, policies, knowledge など) -└── ensemble/ # インストール済み ensemble パッケージ +└── repertoire/ # インストール済み repertoire パッケージ .takt/ # プロジェクトレベル ├── config.yaml # プロジェクト設定 @@ -261,7 +261,7 @@ await engine.run(); | [Agent Guide](./agents.md) | カスタムエージェントの設定 | | [Builtin Catalog](./builtin-catalog.ja.md) | ビルトイン piece・persona の一覧 | | [Faceted Prompting](./faceted-prompting.ja.md) | プロンプト設計の方法論 | -| [Ensemble Packages](./ensemble.ja.md) | パッケージのインストール・共有 | +| [Repertoire Packages](./repertoire.ja.md) | パッケージのインストール・共有 | | [Task Management](./task-management.ja.md) | タスクの追加・実行・隔離 | | [CI/CD Integration](./ci-cd.ja.md) | GitHub Actions・パイプラインモード | | [Changelog](../CHANGELOG.md) ([日本語](./CHANGELOG.ja.md)) | バージョン履歴 | diff --git a/docs/cli-reference.ja.md b/docs/cli-reference.ja.md index 72a45df..da942bc 100644 --- a/docs/cli-reference.ja.md +++ b/docs/cli-reference.ja.md @@ -300,25 +300,25 @@ takt metrics review takt metrics review --since 7d ``` -### takt ensemble +### takt repertoire -Ensemble パッケージ(GitHub 上の外部 TAKT パッケージ)を管理します。 +Repertoire パッケージ(GitHub 上の外部 TAKT パッケージ)を管理します。 ```bash # GitHub からパッケージをインストール -takt ensemble add github:{owner}/{repo}@{ref} +takt repertoire add github:{owner}/{repo}@{ref} # デフォルトブランチからインストール -takt ensemble add github:{owner}/{repo} +takt repertoire add github:{owner}/{repo} # インストール済みパッケージを一覧表示 -takt ensemble list +takt repertoire list # パッケージを削除 -takt ensemble remove @{owner}/{repo} +takt repertoire remove @{owner}/{repo} ``` -インストールされたパッケージは `~/.takt/ensemble/` に保存され、ピース選択やファセット解決で利用可能になります。 +インストールされたパッケージは `~/.takt/repertoire/` に保存され、ピース選択やファセット解決で利用可能になります。 ### takt purge diff --git a/docs/cli-reference.md b/docs/cli-reference.md index d43a832..c9a87cc 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -300,25 +300,25 @@ takt metrics review takt metrics review --since 7d ``` -### takt ensemble +### takt repertoire -Manage ensemble packages (external TAKT packages from GitHub). +Manage repertoire packages (external TAKT packages from GitHub). ```bash # Install a package from GitHub -takt ensemble add github:{owner}/{repo}@{ref} +takt repertoire add github:{owner}/{repo}@{ref} # Install from default branch -takt ensemble add github:{owner}/{repo} +takt repertoire add github:{owner}/{repo} # List installed packages -takt ensemble list +takt repertoire list # Remove a package -takt ensemble remove @{owner}/{repo} +takt repertoire remove @{owner}/{repo} ``` -Installed packages are stored in `~/.takt/ensemble/` and their pieces/facets become available in piece selection and facet resolution. +Installed packages are stored in `~/.takt/repertoire/` and their pieces/facets become available in piece selection and facet resolution. ### takt purge diff --git a/docs/ensemble.ja.md b/docs/repertoire.ja.md similarity index 68% rename from docs/ensemble.ja.md rename to docs/repertoire.ja.md index 61b75f3..06316e1 100644 --- a/docs/ensemble.ja.md +++ b/docs/repertoire.ja.md @@ -1,34 +1,34 @@ -# Ensemble パッケージ +# Repertoire パッケージ -[English](./ensemble.md) +[English](./repertoire.md) -Ensemble パッケージを使うと、GitHub リポジトリから TAKT のピースやファセットをインストール・共有できます。 +Repertoire パッケージを使うと、GitHub リポジトリから TAKT のピースやファセットをインストール・共有できます。 ## クイックスタート ```bash # パッケージをインストール -takt ensemble add github:nrslib/takt-fullstack +takt repertoire add github:nrslib/takt-fullstack # 特定バージョンを指定してインストール -takt ensemble add github:nrslib/takt-fullstack@v1.0.0 +takt repertoire add github:nrslib/takt-fullstack@v1.0.0 # インストール済みパッケージを一覧表示 -takt ensemble list +takt repertoire list # パッケージを削除 -takt ensemble remove @nrslib/takt-fullstack +takt repertoire remove @nrslib/takt-fullstack ``` [GitHub CLI](https://cli.github.com/) (`gh`) のインストールと認証が必要です。 ## パッケージ構造 -TAKT パッケージは `takt-package.yaml` マニフェストとコンテンツディレクトリを持つ GitHub リポジトリです。 +TAKT パッケージは `takt-repertoire.yaml` マニフェストとコンテンツディレクトリを持つ GitHub リポジトリです。 ``` -my-takt-package/ - takt-package.yaml # マニフェスト(.takt/takt-package.yaml でも可) +my-takt-repertoire/ + takt-repertoire.yaml # マニフェスト(.takt/takt-repertoire.yaml でも可) facets/ personas/ expert-coder.md @@ -44,7 +44,7 @@ my-takt-package/ `facets/` と `pieces/` ディレクトリのみがインポートされます。その他のファイルは無視されます。 -### takt-package.yaml +### takt-repertoire.yaml マニフェストは、リポジトリ内のパッケージコンテンツの場所を TAKT に伝えます。 @@ -60,7 +60,7 @@ takt: min_version: 0.22.0 ``` -マニフェストはリポジトリルート(`takt-package.yaml`)または `.takt/` 内(`.takt/takt-package.yaml`)に配置できます。`.takt/` が優先的に検索されます。 +マニフェストはリポジトリルート(`takt-repertoire.yaml`)または `.takt/` 内(`.takt/takt-repertoire.yaml`)に配置できます。`.takt/` が優先的に検索されます。 | フィールド | 必須 | デフォルト | 説明 | |-----------|------|-----------|------| @@ -71,7 +71,7 @@ takt: ## インストール ```bash -takt ensemble add github:{owner}/{repo}@{ref} +takt repertoire add github:{owner}/{repo}@{ref} ``` `@{ref}` は省略可能です。省略した場合、リポジトリのデフォルトブランチが使用されます。 @@ -82,10 +82,10 @@ takt ensemble add github:{owner}/{repo}@{ref} 1. `gh api` 経由で GitHub から tarball をダウンロード 2. `facets/` と `pieces/` のファイルのみを展開(`.md`、`.yaml`、`.yml`) -3. `takt-package.yaml` マニフェストをバリデーション +3. `takt-repertoire.yaml` マニフェストをバリデーション 4. TAKT バージョン互換性チェック -5. `~/.takt/ensemble/@{owner}/{repo}/` にファイルをコピー -6. ロックファイル(`.takt-pack-lock.yaml`)を生成(ソース、ref、コミット SHA) +5. `~/.takt/repertoire/@{owner}/{repo}/` にファイルをコピー +6. ロックファイル(`.takt-repertoire-lock.yaml`)を生成(ソース、ref、コミット SHA) インストールはアトミックに行われます。途中で失敗しても中途半端な状態は残りません。 @@ -102,7 +102,7 @@ takt ensemble add github:{owner}/{repo}@{ref} ### ピース -インストールされたピースはピース選択 UI の「ensemble」カテゴリにパッケージごとのサブカテゴリとして表示されます。直接指定も可能です。 +インストールされたピースはピース選択 UI の「repertoire」カテゴリにパッケージごとのサブカテゴリとして表示されます。直接指定も可能です。 ```bash takt --piece @nrslib/takt-fullstack/expert @@ -122,9 +122,9 @@ movements: ### 4層ファセット解決 -ensemble パッケージのピースが名前(@scope なし)でファセットを解決する場合、次の順序で検索されます。 +repertoire パッケージのピースが名前(@scope なし)でファセットを解決する場合、次の順序で検索されます。 -1. **パッケージローカル**: `~/.takt/ensemble/@{owner}/{repo}/facets/{type}/` +1. **パッケージローカル**: `~/.takt/repertoire/@{owner}/{repo}/facets/{type}/` 2. **プロジェクト**: `.takt/facets/{type}/` 3. **ユーザー**: `~/.takt/facets/{type}/` 4. **ビルトイン**: `builtins/{lang}/facets/{type}/` @@ -136,7 +136,7 @@ ensemble パッケージのピースが名前(@scope なし)でファセッ ### 一覧表示 ```bash -takt ensemble list +takt repertoire list ``` インストール済みパッケージのスコープ、説明、ref、コミット SHA を表示します。 @@ -144,21 +144,21 @@ takt ensemble list ### 削除 ```bash -takt ensemble remove @{owner}/{repo} +takt repertoire remove @{owner}/{repo} ``` 削除前に、ユーザーやプロジェクトのピースがパッケージのファセットを参照していないかチェックし、影響がある場合は警告します。 ## ディレクトリ構造 -インストールされたパッケージは `~/.takt/ensemble/` に保存されます。 +インストールされたパッケージは `~/.takt/repertoire/` に保存されます。 ``` -~/.takt/ensemble/ +~/.takt/repertoire/ @nrslib/ takt-fullstack/ - takt-package.yaml # マニフェストのコピー - .takt-pack-lock.yaml # ロックファイル(ソース、ref、コミット) + takt-repertoire.yaml # マニフェストのコピー + .takt-repertoire-lock.yaml # ロックファイル(ソース、ref、コミット) facets/ personas/ policies/ diff --git a/docs/ensemble.md b/docs/repertoire.md similarity index 66% rename from docs/ensemble.md rename to docs/repertoire.md index 03b6aa7..3d3e78c 100644 --- a/docs/ensemble.md +++ b/docs/repertoire.md @@ -1,34 +1,34 @@ -# Ensemble Packages +# Repertoire Packages -[Japanese](./ensemble.ja.md) +[Japanese](./repertoire.ja.md) -Ensemble packages let you install and share TAKT pieces and facets from GitHub repositories. +Repertoire packages let you install and share TAKT pieces and facets from GitHub repositories. ## Quick Start ```bash # Install a package -takt ensemble add github:nrslib/takt-fullstack +takt repertoire add github:nrslib/takt-fullstack # Install a specific version -takt ensemble add github:nrslib/takt-fullstack@v1.0.0 +takt repertoire add github:nrslib/takt-fullstack@v1.0.0 # List installed packages -takt ensemble list +takt repertoire list # Remove a package -takt ensemble remove @nrslib/takt-fullstack +takt repertoire remove @nrslib/takt-fullstack ``` **Requirements:** [GitHub CLI](https://cli.github.com/) (`gh`) must be installed and authenticated. ## Package Structure -A TAKT package is a GitHub repository with a `takt-package.yaml` manifest and content directories: +A TAKT package is a GitHub repository with a `takt-repertoire.yaml` manifest and content directories: ``` -my-takt-package/ - takt-package.yaml # Package manifest (or .takt/takt-package.yaml) +my-takt-repertoire/ + takt-repertoire.yaml # Package manifest (or .takt/takt-repertoire.yaml) facets/ personas/ expert-coder.md @@ -44,7 +44,7 @@ my-takt-package/ Only `facets/` and `pieces/` directories are imported. Other files are ignored. -### takt-package.yaml +### takt-repertoire.yaml The manifest tells TAKT where to find the package content within the repository. @@ -60,7 +60,7 @@ takt: min_version: 0.22.0 ``` -The manifest can be placed at the repository root (`takt-package.yaml`) or inside `.takt/` (`.takt/takt-package.yaml`). The `.takt/` location is checked first. +The manifest can be placed at the repository root (`takt-repertoire.yaml`) or inside `.takt/` (`.takt/takt-repertoire.yaml`). The `.takt/` location is checked first. | Field | Required | Default | Description | |-------|----------|---------|-------------| @@ -71,7 +71,7 @@ The manifest can be placed at the repository root (`takt-package.yaml`) or insid ## Installation ```bash -takt ensemble add github:{owner}/{repo}@{ref} +takt repertoire add github:{owner}/{repo}@{ref} ``` The `@{ref}` is optional. Without it, the repository's default branch is used. @@ -82,10 +82,10 @@ Before installing, TAKT displays a summary of the package contents (facet counts 1. Downloads the tarball from GitHub via `gh api` 2. Extracts only `facets/` and `pieces/` files (`.md`, `.yaml`, `.yml`) -3. Validates the `takt-package.yaml` manifest +3. Validates the `takt-repertoire.yaml` manifest 4. Checks TAKT version compatibility -5. Copies files to `~/.takt/ensemble/@{owner}/{repo}/` -6. Generates a lock file (`.takt-pack-lock.yaml`) with source, ref, and commit SHA +5. Copies files to `~/.takt/repertoire/@{owner}/{repo}/` +6. Generates a lock file (`.takt-repertoire-lock.yaml`) with source, ref, and commit SHA Installation is atomic — if it fails partway, no partial state is left behind. @@ -102,7 +102,7 @@ Installation is atomic — if it fails partway, no partial state is left behind. ### Pieces -Installed pieces appear in the piece selection UI under the "ensemble" category, organized by package. You can also specify them directly: +Installed pieces appear in the piece selection UI under the "repertoire" category, organized by package. You can also specify them directly: ```bash takt --piece @nrslib/takt-fullstack/expert @@ -122,9 +122,9 @@ movements: ### 4-layer facet resolution -When a piece from an ensemble package resolves facets by name (without @scope), the resolution order is: +When a piece from a repertoire package resolves facets by name (without @scope), the resolution order is: -1. **Package-local**: `~/.takt/ensemble/@{owner}/{repo}/facets/{type}/` +1. **Package-local**: `~/.takt/repertoire/@{owner}/{repo}/facets/{type}/` 2. **Project**: `.takt/facets/{type}/` 3. **User**: `~/.takt/facets/{type}/` 4. **Builtin**: `builtins/{lang}/facets/{type}/` @@ -136,7 +136,7 @@ This means package pieces automatically find their own facets first, while still ### List ```bash -takt ensemble list +takt repertoire list ``` Shows installed packages with their scope, description, ref, and commit SHA. @@ -144,21 +144,21 @@ Shows installed packages with their scope, description, ref, and commit SHA. ### Remove ```bash -takt ensemble remove @{owner}/{repo} +takt repertoire remove @{owner}/{repo} ``` Before removing, TAKT checks if any user/project pieces reference the package's facets and warns about potential breakage. ## Directory Structure -Installed packages are stored under `~/.takt/ensemble/`: +Installed packages are stored under `~/.takt/repertoire/`: ``` -~/.takt/ensemble/ +~/.takt/repertoire/ @nrslib/ takt-fullstack/ - takt-package.yaml # Copy of the manifest - .takt-pack-lock.yaml # Lock file (source, ref, commit) + takt-repertoire.yaml # Copy of the manifest + .takt-repertoire-lock.yaml # Lock file (source, ref, commit) facets/ personas/ policies/ diff --git a/e2e/specs/piece-selection-branches.e2e.ts b/e2e/specs/piece-selection-branches.e2e.ts index 7299b58..92c8576 100644 --- a/e2e/specs/piece-selection-branches.e2e.ts +++ b/e2e/specs/piece-selection-branches.e2e.ts @@ -124,13 +124,13 @@ describe('E2E: Piece selection branch coverage', () => { expect(result.stdout).toContain('Piece completed'); }, 240_000); - it('should execute when --piece is an ensemble @scope name (resolver hit branch)', () => { - const pkgRoot = join(isolatedEnv.taktDir, 'ensemble', '@nrslib', 'takt-packages'); + it('should execute when --piece is a repertoire @scope name (resolver hit branch)', () => { + const pkgRoot = join(isolatedEnv.taktDir, 'repertoire', '@nrslib', 'takt-ensembles'); writeAgent(pkgRoot); writeMinimalPiece(join(pkgRoot, 'pieces', 'critical-thinking.yaml')); const result = runTaskWithPiece({ - piece: '@nrslib/takt-packages/critical-thinking', + piece: '@nrslib/takt-ensembles/critical-thinking', cwd: testRepo.path, env: isolatedEnv.env, }); @@ -142,13 +142,13 @@ describe('E2E: Piece selection branch coverage', () => { it('should fail fast with message when --piece is unknown (resolver miss branch)', () => { const result = runTaskWithPiece({ - piece: '@nrslib/takt-packages/not-found', + piece: '@nrslib/takt-ensembles/not-found', cwd: testRepo.path, env: isolatedEnv.env, }); expect(result.exitCode).toBe(0); - expect(result.stdout).toContain('Piece not found: @nrslib/takt-packages/not-found'); + expect(result.stdout).toContain('Piece not found: @nrslib/takt-ensembles/not-found'); expect(result.stdout).toContain('Cancelled'); }, 240_000); diff --git a/e2e/specs/ensemble-real.e2e.ts b/e2e/specs/repertoire-real.e2e.ts similarity index 71% rename from e2e/specs/ensemble-real.e2e.ts rename to e2e/specs/repertoire-real.e2e.ts index 90b3472..7f46fc0 100644 --- a/e2e/specs/ensemble-real.e2e.ts +++ b/e2e/specs/repertoire-real.e2e.ts @@ -39,9 +39,9 @@ function readYamlFile(path: string): T { return parseYaml(raw) as T; } -const FIXTURE_REPO = 'nrslib/takt-pack-fixture'; -const FIXTURE_REPO_SUBDIR = 'nrslib/takt-pack-fixture-subdir'; -const FIXTURE_REPO_FACETS_ONLY = 'nrslib/takt-pack-fixture-facets-only'; +const FIXTURE_REPO = 'nrslib/takt-ensemble-fixture'; +const FIXTURE_REPO_SUBDIR = 'nrslib/takt-ensemble-fixture-subdir'; +const FIXTURE_REPO_FACETS_ONLY = 'nrslib/takt-ensemble-fixture-facets-only'; const MISSING_MANIFEST_REPO = 'nrslib/takt'; const FIXTURE_REF = 'v1.0.0'; @@ -50,7 +50,7 @@ const canUseSubdirRepo = canAccessRepo(FIXTURE_REPO_SUBDIR) && canAccessRepoRef( const canUseFacetsOnlyRepo = canAccessRepo(FIXTURE_REPO_FACETS_ONLY) && canAccessRepoRef(FIXTURE_REPO_FACETS_ONLY, FIXTURE_REF); const canUseMissingManifestRepo = canAccessRepo(MISSING_MANIFEST_REPO); -describe('E2E: takt ensemble (real GitHub fixtures)', () => { +describe('E2E: takt repertoire (real GitHub fixtures)', () => { let isolatedEnv: IsolatedEnv; beforeEach(() => { @@ -67,7 +67,7 @@ describe('E2E: takt ensemble (real GitHub fixtures)', () => { it.skipIf(!canUseFixtureRepo)('should install fixture package from GitHub and create lock file', () => { const result = runTakt({ - args: ['ensemble', 'add', `github:${FIXTURE_REPO}@${FIXTURE_REF}`], + args: ['repertoire', 'add', `github:${FIXTURE_REPO}@${FIXTURE_REF}`], cwd: process.cwd(), env: isolatedEnv.env, input: 'y\n', @@ -78,14 +78,14 @@ describe('E2E: takt ensemble (real GitHub fixtures)', () => { expect(result.stdout).toContain(`📦 ${FIXTURE_REPO} @${FIXTURE_REF}`); expect(result.stdout).toContain('インストールしました'); - const packageDir = join(isolatedEnv.taktDir, 'ensemble', '@nrslib', 'takt-pack-fixture'); - expect(existsSync(join(packageDir, 'takt-package.yaml'))).toBe(true); - expect(existsSync(join(packageDir, '.takt-pack-lock.yaml'))).toBe(true); + const packageDir = join(isolatedEnv.taktDir, 'repertoire', '@nrslib', 'takt-ensemble-fixture'); + expect(existsSync(join(packageDir, 'takt-repertoire.yaml'))).toBe(true); + expect(existsSync(join(packageDir, '.takt-repertoire-lock.yaml'))).toBe(true); expect(existsSync(join(packageDir, 'facets'))).toBe(true); expect(existsSync(join(packageDir, 'pieces'))).toBe(true); - const lock = readYamlFile(join(packageDir, '.takt-pack-lock.yaml')); - expect(lock.source).toBe('github:nrslib/takt-pack-fixture'); + const lock = readYamlFile(join(packageDir, '.takt-repertoire-lock.yaml')); + expect(lock.source).toBe('github:nrslib/takt-ensemble-fixture'); expect(lock.ref).toBe(FIXTURE_REF); expect(lock.commit).toBeTypeOf('string'); expect(lock.commit!.length).toBeGreaterThanOrEqual(7); @@ -94,7 +94,7 @@ describe('E2E: takt ensemble (real GitHub fixtures)', () => { it.skipIf(!canUseFixtureRepo)('should list installed package after add', () => { const addResult = runTakt({ - args: ['ensemble', 'add', `github:${FIXTURE_REPO}@${FIXTURE_REF}`], + args: ['repertoire', 'add', `github:${FIXTURE_REPO}@${FIXTURE_REF}`], cwd: process.cwd(), env: isolatedEnv.env, input: 'y\n', @@ -103,19 +103,19 @@ describe('E2E: takt ensemble (real GitHub fixtures)', () => { expect(addResult.exitCode).toBe(0); const listResult = runTakt({ - args: ['ensemble', 'list'], + args: ['repertoire', 'list'], cwd: process.cwd(), env: isolatedEnv.env, timeout: 120_000, }); expect(listResult.exitCode).toBe(0); - expect(listResult.stdout).toContain('@nrslib/takt-pack-fixture'); + expect(listResult.stdout).toContain('@nrslib/takt-ensemble-fixture'); }, 240_000); it.skipIf(!canUseFixtureRepo)('should remove installed package with confirmation', () => { const addResult = runTakt({ - args: ['ensemble', 'add', `github:${FIXTURE_REPO}@${FIXTURE_REF}`], + args: ['repertoire', 'add', `github:${FIXTURE_REPO}@${FIXTURE_REF}`], cwd: process.cwd(), env: isolatedEnv.env, input: 'y\n', @@ -124,7 +124,7 @@ describe('E2E: takt ensemble (real GitHub fixtures)', () => { expect(addResult.exitCode).toBe(0); const removeResult = runTakt({ - args: ['ensemble', 'remove', '@nrslib/takt-pack-fixture'], + args: ['repertoire', 'remove', '@nrslib/takt-ensemble-fixture'], cwd: process.cwd(), env: isolatedEnv.env, input: 'y\n', @@ -132,13 +132,13 @@ describe('E2E: takt ensemble (real GitHub fixtures)', () => { }); expect(removeResult.exitCode).toBe(0); - const packageDir = join(isolatedEnv.taktDir, 'ensemble', '@nrslib', 'takt-pack-fixture'); + const packageDir = join(isolatedEnv.taktDir, 'repertoire', '@nrslib', 'takt-ensemble-fixture'); expect(existsSync(packageDir)).toBe(false); }, 240_000); it.skipIf(!canUseFixtureRepo)('should cancel installation when user answers N', () => { const result = runTakt({ - args: ['ensemble', 'add', `github:${FIXTURE_REPO}@${FIXTURE_REF}`], + args: ['repertoire', 'add', `github:${FIXTURE_REPO}@${FIXTURE_REF}`], cwd: process.cwd(), env: isolatedEnv.env, input: 'n\n', @@ -148,13 +148,13 @@ describe('E2E: takt ensemble (real GitHub fixtures)', () => { expect(result.exitCode).toBe(0); expect(result.stdout).toContain('キャンセルしました'); - const packageDir = join(isolatedEnv.taktDir, 'ensemble', '@nrslib', 'takt-pack-fixture'); + const packageDir = join(isolatedEnv.taktDir, 'repertoire', '@nrslib', 'takt-ensemble-fixture'); expect(existsSync(packageDir)).toBe(false); }, 240_000); it.skipIf(!canUseSubdirRepo)('should install subdir fixture package', () => { const result = runTakt({ - args: ['ensemble', 'add', `github:${FIXTURE_REPO_SUBDIR}@${FIXTURE_REF}`], + args: ['repertoire', 'add', `github:${FIXTURE_REPO_SUBDIR}@${FIXTURE_REF}`], cwd: process.cwd(), env: isolatedEnv.env, input: 'y\n', @@ -162,15 +162,15 @@ describe('E2E: takt ensemble (real GitHub fixtures)', () => { }); expect(result.exitCode).toBe(0); - const packageDir = join(isolatedEnv.taktDir, 'ensemble', '@nrslib', 'takt-pack-fixture-subdir'); - expect(existsSync(join(packageDir, 'takt-package.yaml'))).toBe(true); - expect(existsSync(join(packageDir, '.takt-pack-lock.yaml'))).toBe(true); + const packageDir = join(isolatedEnv.taktDir, 'repertoire', '@nrslib', 'takt-ensemble-fixture-subdir'); + expect(existsSync(join(packageDir, 'takt-repertoire.yaml'))).toBe(true); + expect(existsSync(join(packageDir, '.takt-repertoire-lock.yaml'))).toBe(true); expect(existsSync(join(packageDir, 'facets')) || existsSync(join(packageDir, 'pieces'))).toBe(true); }, 240_000); it.skipIf(!canUseFacetsOnlyRepo)('should install facets-only fixture package without requiring pieces directory', () => { const result = runTakt({ - args: ['ensemble', 'add', `github:${FIXTURE_REPO_FACETS_ONLY}@${FIXTURE_REF}`], + args: ['repertoire', 'add', `github:${FIXTURE_REPO_FACETS_ONLY}@${FIXTURE_REF}`], cwd: process.cwd(), env: isolatedEnv.env, input: 'y\n', @@ -178,14 +178,14 @@ describe('E2E: takt ensemble (real GitHub fixtures)', () => { }); expect(result.exitCode).toBe(0); - const packageDir = join(isolatedEnv.taktDir, 'ensemble', '@nrslib', 'takt-pack-fixture-facets-only'); + const packageDir = join(isolatedEnv.taktDir, 'repertoire', '@nrslib', 'takt-ensemble-fixture-facets-only'); expect(existsSync(join(packageDir, 'facets'))).toBe(true); expect(existsSync(join(packageDir, 'pieces'))).toBe(false); }, 240_000); - it.skipIf(!canUseMissingManifestRepo)('should fail when repository has no takt-package.yaml', () => { + it.skipIf(!canUseMissingManifestRepo)('should fail when repository has no takt-repertoire.yaml', () => { const result = runTakt({ - args: ['ensemble', 'add', `github:${MISSING_MANIFEST_REPO}`], + args: ['repertoire', 'add', `github:${MISSING_MANIFEST_REPO}`], cwd: process.cwd(), env: isolatedEnv.env, input: 'y\n', @@ -193,6 +193,6 @@ describe('E2E: takt ensemble (real GitHub fixtures)', () => { }); expect(result.exitCode).not.toBe(0); - expect(result.stdout).toContain('takt-package.yaml not found'); + expect(result.stdout).toContain('takt-repertoire.yaml not found'); }, 240_000); }); diff --git a/e2e/specs/ensemble.e2e.ts b/e2e/specs/repertoire.e2e.ts similarity index 66% rename from e2e/specs/ensemble.e2e.ts rename to e2e/specs/repertoire.e2e.ts index f449d11..aac3748 100644 --- a/e2e/specs/ensemble.e2e.ts +++ b/e2e/specs/repertoire.e2e.ts @@ -1,83 +1,83 @@ /** - * E2E tests for `takt ensemble` subcommands. + * E2E tests for `takt repertoire` subcommands. * - * All tests are marked as `it.todo()` because the `takt ensemble` command + * All tests are marked as `it.todo()` because the `takt repertoire` command * is not yet implemented. These serve as the specification skeleton; * fill in the callbacks when the implementation lands. * * GitHub fixture repos used: - * - github:nrslib/takt-pack-fixture (standard: facets/ + pieces/) - * - github:nrslib/takt-pack-fixture-subdir (path field specified) - * - github:nrslib/takt-pack-fixture-facets-only (facets only, no pieces/) + * - github:nrslib/takt-ensemble-fixture (standard: facets/ + pieces/) + * - github:nrslib/takt-ensemble-fixture-subdir (path field specified) + * - github:nrslib/takt-ensemble-fixture-facets-only (facets only, no pieces/) * */ import { describe, it } from 'vitest'; // --------------------------------------------------------------------------- -// E2E: takt ensemble add — 正常系 +// E2E: takt repertoire add — 正常系 // --------------------------------------------------------------------------- -describe('E2E: takt ensemble add (正常系)', () => { +describe('E2E: takt repertoire add (正常系)', () => { // E1: 標準パッケージのインポート // Given: 空の isolatedEnv - // When: takt ensemble add github:nrslib/takt-pack-fixture@v1.0.0、y 入力 - // Then: {taktDir}/ensemble/@nrslib/takt-pack-fixture/ に takt-pack.yaml, - // .takt-pack-lock.yaml, facets/, pieces/ が存在する + // When: takt repertoire add github:nrslib/takt-ensemble-fixture@v1.0.0、y 入力 + // Then: {taktDir}/repertoire/@nrslib/takt-ensemble-fixture/ に takt-repertoire.yaml, + // .takt-repertoire-lock.yaml, facets/, pieces/ が存在する it.todo('should install standard package and verify directory structure'); // E2: lock ファイルのフィールド確認 // Given: E1 完了後 - // When: .takt-pack-lock.yaml を読む + // When: .takt-repertoire-lock.yaml を読む // Then: source, ref, commit, imported_at フィールドがすべて存在する - it.todo('should generate .takt-pack-lock.yaml with source, ref, commit, imported_at'); + it.todo('should generate .takt-repertoire-lock.yaml with source, ref, commit, imported_at'); // E3: サブディレクトリ型パッケージのインポート // Given: 空の isolatedEnv - // When: takt ensemble add github:nrslib/takt-pack-fixture-subdir@v1.0.0、y 入力 + // When: takt repertoire add github:nrslib/takt-ensemble-fixture-subdir@v1.0.0、y 入力 // Then: path フィールドで指定されたサブディレクトリ配下のファイルのみコピーされる it.todo('should install subdir-type package and copy only path-specified files'); // E4: ファセットのみパッケージのインポート // Given: 空の isolatedEnv - // When: takt ensemble add github:nrslib/takt-pack-fixture-facets-only@v1.0.0、y 入力 + // When: takt repertoire add github:nrslib/takt-ensemble-fixture-facets-only@v1.0.0、y 入力 // Then: facets/ は存在し、pieces/ ディレクトリは存在しない it.todo('should install facets-only package without creating pieces/ directory'); // E4b: コミットSHA指定 // Given: 空の isolatedEnv - // When: takt ensemble add github:nrslib/takt-pack-fixture@{sha}、y 入力 - // Then: .takt-pack-lock.yaml の commit フィールドが指定した SHA と一致する + // When: takt repertoire add github:nrslib/takt-ensemble-fixture@{sha}、y 入力 + // Then: .takt-repertoire-lock.yaml の commit フィールドが指定した SHA と一致する it.todo('should populate lock file commit field with the specified commit SHA when installing by SHA'); // E5: インストール前サマリー表示 // Given: 空の isolatedEnv - // When: takt ensemble add github:nrslib/takt-pack-fixture@v1.0.0、N 入力(確認でキャンセル) - // Then: stdout に "📦 nrslib/takt-pack-fixture", "faceted:", "pieces:" が含まれる + // When: takt repertoire add github:nrslib/takt-ensemble-fixture@v1.0.0、N 入力(確認でキャンセル) + // Then: stdout に "📦 nrslib/takt-ensemble-fixture", "faceted:", "pieces:" が含まれる it.todo('should display pre-install summary with package name, faceted count, and pieces list'); // E6: 権限警告表示(edit: true ピース) // Given: edit: true を含むパッケージ - // When: ensemble add、N 入力 + // When: repertoire add、N 入力 // Then: stdout に ⚠ が含まれる it.todo('should display warning symbol when package contains piece with edit: true'); // E7: ユーザー確認 N で中断 // Given: 空の isolatedEnv - // When: ensemble add、N 入力 + // When: repertoire add、N 入力 // Then: インストールディレクトリが存在しない。exit code 0 it.todo('should abort installation when user answers N to confirmation prompt'); }); // --------------------------------------------------------------------------- -// E2E: takt ensemble add — 上書きシナリオ +// E2E: takt repertoire add — 上書きシナリオ // --------------------------------------------------------------------------- -describe('E2E: takt ensemble add (上書きシナリオ)', () => { +describe('E2E: takt repertoire add (上書きシナリオ)', () => { // E8: 既存パッケージの上書き警告表示 // Given: 1回目インストール済み - // When: 2回目 ensemble add - // Then: stdout に "⚠ パッケージ @nrslib/takt-pack-fixture は既にインストールされています" が含まれる + // When: 2回目 repertoire add + // Then: stdout に "⚠ パッケージ @nrslib/takt-ensemble-fixture は既にインストールされています" が含まれる it.todo('should display already-installed warning on second add'); // E9: 上書き y で原子的更新 @@ -93,80 +93,80 @@ describe('E2E: takt ensemble add (上書きシナリオ)', () => { it.todo('should keep existing package when user answers N to overwrite prompt'); // E11: 前回異常終了残留物(.tmp/)クリーンアップ - // Given: {ensembleDir}/@nrslib/takt-pack-fixture.tmp/ が既に存在する状態 - // When: ensemble add、y 入力 + // Given: {repertoireDir}/@nrslib/takt-ensemble-fixture.tmp/ が既に存在する状態 + // When: repertoire add、y 入力 // Then: インストールが正常完了する。exit code 0 it.todo('should clean up leftover .tmp/ directory from previous failed installation'); // E12: 前回異常終了残留物(.bak/)クリーンアップ - // Given: {ensembleDir}/@nrslib/takt-pack-fixture.bak/ が既に存在する状態 - // When: ensemble add、y 入力 + // Given: {repertoireDir}/@nrslib/takt-ensemble-fixture.bak/ が既に存在する状態 + // When: repertoire add、y 入力 // Then: インストールが正常完了する。exit code 0 it.todo('should clean up leftover .bak/ directory from previous failed installation'); }); // --------------------------------------------------------------------------- -// E2E: takt ensemble add — バリデーション・エラー系 +// E2E: takt repertoire add — バリデーション・エラー系 // --------------------------------------------------------------------------- -describe('E2E: takt ensemble add (バリデーション・エラー系)', () => { - // E13: takt-pack.yaml 不在リポジトリ - // Given: takt-pack.yaml のないリポジトリを指定 - // When: ensemble add +describe('E2E: takt repertoire add (バリデーション・エラー系)', () => { + // E13: takt-repertoire.yaml 不在リポジトリ + // Given: takt-repertoire.yaml のないリポジトリを指定 + // When: repertoire add // Then: exit code 非0。エラーメッセージ表示 - it.todo('should fail with error when repository has no takt-pack.yaml'); + it.todo('should fail with error when repository has no takt-repertoire.yaml'); // E14: path に絶対パス(/foo) - // Given: path: /foo の takt-pack.yaml - // When: ensemble add + // Given: path: /foo の takt-repertoire.yaml + // When: repertoire add // Then: exit code 非0 - it.todo('should reject takt-pack.yaml with absolute path in path field (/foo)'); + it.todo('should reject takt-repertoire.yaml with absolute path in path field (/foo)'); // E15: path に .. によるリポジトリ外参照 - // Given: path: ../outside の takt-pack.yaml - // When: ensemble add + // Given: path: ../outside の takt-repertoire.yaml + // When: repertoire add // Then: exit code 非0 - it.todo('should reject takt-pack.yaml with path traversal via ".." segments'); + it.todo('should reject takt-repertoire.yaml with path traversal via ".." segments'); // E16: 空パッケージ(facets/ も pieces/ もない) - // Given: facets/, pieces/ のどちらもない takt-pack.yaml - // When: ensemble add + // Given: facets/, pieces/ のどちらもない takt-repertoire.yaml + // When: repertoire add // Then: exit code 非0 it.todo('should reject package with neither facets/ nor pieces/ directory'); // E17: min_version 不正形式(1.0、セグメント不足) // Given: takt.min_version: "1.0" - // When: ensemble add + // When: repertoire add // Then: exit code 非0 - it.todo('should reject takt-pack.yaml with min_version "1.0" (missing patch segment)'); + it.todo('should reject takt-repertoire.yaml with min_version "1.0" (missing patch segment)'); // E18: min_version 不正形式(v1.0.0、v プレフィックス) // Given: takt.min_version: "v1.0.0" - // When: ensemble add + // When: repertoire add // Then: exit code 非0 - it.todo('should reject takt-pack.yaml with min_version "v1.0.0" (v prefix)'); + it.todo('should reject takt-repertoire.yaml with min_version "v1.0.0" (v prefix)'); // E19: min_version 不正形式(1.0.0-alpha、pre-release) // Given: takt.min_version: "1.0.0-alpha" - // When: ensemble add + // When: repertoire add // Then: exit code 非0 - it.todo('should reject takt-pack.yaml with min_version "1.0.0-alpha" (pre-release suffix)'); + it.todo('should reject takt-repertoire.yaml with min_version "1.0.0-alpha" (pre-release suffix)'); // E20: min_version が現在の TAKT より新しい // Given: takt.min_version: "999.0.0" - // When: ensemble add + // When: repertoire add // Then: exit code 非0。必要バージョンと現在バージョンが表示される it.todo('should fail with version mismatch message when min_version exceeds current takt version'); }); // --------------------------------------------------------------------------- -// E2E: takt ensemble remove +// E2E: takt repertoire remove // --------------------------------------------------------------------------- -describe('E2E: takt ensemble remove', () => { +describe('E2E: takt repertoire remove', () => { // E21: 正常削除 y // Given: パッケージインストール済み - // When: takt ensemble remove @nrslib/takt-pack-fixture、y 入力 + // When: takt repertoire remove @nrslib/takt-ensemble-fixture、y 入力 // Then: ディレクトリが削除される。@nrslib/ 配下が空なら @nrslib/ も削除 it.todo('should remove installed package directory when user answers y'); @@ -196,26 +196,26 @@ describe('E2E: takt ensemble remove', () => { }); // --------------------------------------------------------------------------- -// E2E: takt ensemble list +// E2E: takt repertoire list // --------------------------------------------------------------------------- -describe('E2E: takt ensemble list', () => { +describe('E2E: takt repertoire list', () => { // E26: インストール済みパッケージ一覧表示 // Given: パッケージ1件インストール済み - // When: takt ensemble list - // Then: "📦 インストール済みパッケージ:" と @nrslib/takt-pack-fixture、 + // When: takt repertoire list + // Then: "📦 インストール済みパッケージ:" と @nrslib/takt-ensemble-fixture、 // description、ref、commit 先頭7文字が表示される it.todo('should list installed packages with name, description, ref, and abbreviated commit'); // E27: 空状態での表示 - // Given: ensemble/ が空(パッケージなし) - // When: takt ensemble list + // Given: repertoire/ が空(パッケージなし) + // When: takt repertoire list // Then: パッケージなし相当のメッセージ。exit code 0 it.todo('should display empty-state message when no packages are installed'); // E28: 複数パッケージの一覧 // Given: 2件以上インストール済み - // When: takt ensemble list + // When: takt repertoire list // Then: すべてのパッケージが表示される it.todo('should list all installed packages when multiple packages exist'); }); diff --git a/src/__tests__/faceted-prompting/scope-ref.test.ts b/src/__tests__/faceted-prompting/scope-ref.test.ts index cf860a5..4d39088 100644 --- a/src/__tests__/faceted-prompting/scope-ref.test.ts +++ b/src/__tests__/faceted-prompting/scope-ref.test.ts @@ -4,7 +4,7 @@ * Covers: * - isScopeRef(): detects @{owner}/{repo}/{facet-name} format * - parseScopeRef(): parses components from scope reference - * - resolveScopeRef(): resolves to ~/.takt/ensemble/@{owner}/{repo}/facets/{facet-type}/{facet-name}.md + * - resolveScopeRef(): resolves to ~/.takt/repertoire/@{owner}/{repo}/facets/{facet-type}/{facet-name}.md * - facet-type mapping from field context (persona→personas, policy→policies, etc.) * - Name constraint validation (owner, repo, facet-name patterns) * - Case normalization (uppercase → lowercase) @@ -124,89 +124,89 @@ describe('parseScopeRef', () => { // --------------------------------------------------------------------------- describe('resolveScopeRef', () => { - let tempEnsembleDir: string; + let tempRepertoireDir: string; beforeEach(() => { - tempEnsembleDir = mkdtempSync(join(tmpdir(), 'takt-ensemble-')); + tempRepertoireDir = mkdtempSync(join(tmpdir(), 'takt-repertoire-')); }); afterEach(() => { - rmSync(tempEnsembleDir, { recursive: true, force: true }); + rmSync(tempRepertoireDir, { recursive: true, force: true }); }); it('should resolve persona scope ref to facets/personas/{name}.md', () => { - // Given: ensemble directory with the package's persona file - const facetDir = join(tempEnsembleDir, '@nrslib', 'takt-fullstack', 'facets', 'personas'); + // Given: repertoire directory with the package's persona file + const facetDir = join(tempRepertoireDir, '@nrslib', 'takt-fullstack', 'facets', 'personas'); mkdirSync(facetDir, { recursive: true }); writeFileSync(join(facetDir, 'expert-coder.md'), 'Expert coder persona'); const scopeRef: ScopeRef = { owner: 'nrslib', repo: 'takt-fullstack', name: 'expert-coder' }; // When: scope ref is resolved with facetType 'personas' - const result = resolveScopeRef(scopeRef, 'personas', tempEnsembleDir); + const result = resolveScopeRef(scopeRef, 'personas', tempRepertoireDir); // Then: resolved to the correct file path - expect(result).toBe(join(tempEnsembleDir, '@nrslib', 'takt-fullstack', 'facets', 'personas', 'expert-coder.md')); + expect(result).toBe(join(tempRepertoireDir, '@nrslib', 'takt-fullstack', 'facets', 'personas', 'expert-coder.md')); }); it('should resolve policy scope ref to facets/policies/{name}.md', () => { - // Given: ensemble directory with policy file - const facetDir = join(tempEnsembleDir, '@nrslib', 'takt-fullstack', 'facets', 'policies'); + // Given: repertoire directory with policy file + const facetDir = join(tempRepertoireDir, '@nrslib', 'takt-fullstack', 'facets', 'policies'); mkdirSync(facetDir, { recursive: true }); writeFileSync(join(facetDir, 'owasp-checklist.md'), 'OWASP content'); const scopeRef: ScopeRef = { owner: 'nrslib', repo: 'takt-fullstack', name: 'owasp-checklist' }; // When: scope ref is resolved with facetType 'policies' - const result = resolveScopeRef(scopeRef, 'policies', tempEnsembleDir); + const result = resolveScopeRef(scopeRef, 'policies', tempRepertoireDir); // Then: resolved to correct path - expect(result).toBe(join(tempEnsembleDir, '@nrslib', 'takt-fullstack', 'facets', 'policies', 'owasp-checklist.md')); + expect(result).toBe(join(tempRepertoireDir, '@nrslib', 'takt-fullstack', 'facets', 'policies', 'owasp-checklist.md')); }); it('should resolve knowledge scope ref to facets/knowledge/{name}.md', () => { - // Given: ensemble directory with knowledge file - const facetDir = join(tempEnsembleDir, '@nrslib', 'takt-security-facets', 'facets', 'knowledge'); + // Given: repertoire directory with knowledge file + const facetDir = join(tempRepertoireDir, '@nrslib', 'takt-security-facets', 'facets', 'knowledge'); mkdirSync(facetDir, { recursive: true }); writeFileSync(join(facetDir, 'vulnerability-patterns.md'), 'Vuln patterns'); const scopeRef: ScopeRef = { owner: 'nrslib', repo: 'takt-security-facets', name: 'vulnerability-patterns' }; // When: scope ref is resolved with facetType 'knowledge' - const result = resolveScopeRef(scopeRef, 'knowledge', tempEnsembleDir); + const result = resolveScopeRef(scopeRef, 'knowledge', tempRepertoireDir); // Then: resolved to correct path - expect(result).toBe(join(tempEnsembleDir, '@nrslib', 'takt-security-facets', 'facets', 'knowledge', 'vulnerability-patterns.md')); + expect(result).toBe(join(tempRepertoireDir, '@nrslib', 'takt-security-facets', 'facets', 'knowledge', 'vulnerability-patterns.md')); }); it('should resolve instructions scope ref to facets/instructions/{name}.md', () => { // Given: instruction file - const facetDir = join(tempEnsembleDir, '@acme', 'takt-backend', 'facets', 'instructions'); + const facetDir = join(tempRepertoireDir, '@acme', 'takt-backend', 'facets', 'instructions'); mkdirSync(facetDir, { recursive: true }); writeFileSync(join(facetDir, 'review-checklist.md'), 'Review steps'); const scopeRef: ScopeRef = { owner: 'acme', repo: 'takt-backend', name: 'review-checklist' }; // When: scope ref is resolved with facetType 'instructions' - const result = resolveScopeRef(scopeRef, 'instructions', tempEnsembleDir); + const result = resolveScopeRef(scopeRef, 'instructions', tempRepertoireDir); // Then: correct path - expect(result).toBe(join(tempEnsembleDir, '@acme', 'takt-backend', 'facets', 'instructions', 'review-checklist.md')); + expect(result).toBe(join(tempRepertoireDir, '@acme', 'takt-backend', 'facets', 'instructions', 'review-checklist.md')); }); it('should resolve output-contracts scope ref to facets/output-contracts/{name}.md', () => { // Given: output contract file - const facetDir = join(tempEnsembleDir, '@acme', 'takt-backend', 'facets', 'output-contracts'); + const facetDir = join(tempRepertoireDir, '@acme', 'takt-backend', 'facets', 'output-contracts'); mkdirSync(facetDir, { recursive: true }); writeFileSync(join(facetDir, 'review-report.md'), 'Report contract'); const scopeRef: ScopeRef = { owner: 'acme', repo: 'takt-backend', name: 'review-report' }; // When: scope ref is resolved with facetType 'output-contracts' - const result = resolveScopeRef(scopeRef, 'output-contracts', tempEnsembleDir); + const result = resolveScopeRef(scopeRef, 'output-contracts', tempRepertoireDir); // Then: correct path - expect(result).toBe(join(tempEnsembleDir, '@acme', 'takt-backend', 'facets', 'output-contracts', 'review-report.md')); + expect(result).toBe(join(tempRepertoireDir, '@acme', 'takt-backend', 'facets', 'output-contracts', 'review-report.md')); }); }); diff --git a/src/__tests__/helpers/ensemble-test-helpers.ts b/src/__tests__/helpers/repertoire-test-helpers.ts similarity index 87% rename from src/__tests__/helpers/ensemble-test-helpers.ts rename to src/__tests__/helpers/repertoire-test-helpers.ts index 8364159..fc12aac 100644 --- a/src/__tests__/helpers/ensemble-test-helpers.ts +++ b/src/__tests__/helpers/repertoire-test-helpers.ts @@ -1,5 +1,5 @@ import { join } from 'node:path'; -import type { ScanConfig } from '../../features/ensemble/remove.js'; +import type { ScanConfig } from '../../features/repertoire/remove.js'; /** * Build a ScanConfig for tests using tempDir as the root. diff --git a/src/__tests__/piece-category-config.test.ts b/src/__tests__/piece-category-config.test.ts index e451311..0b1c44e 100644 --- a/src/__tests__/piece-category-config.test.ts +++ b/src/__tests__/piece-category-config.test.ts @@ -72,7 +72,7 @@ function writeYaml(path: string, content: string): void { writeFileSync(path, content.trim() + '\n', 'utf-8'); } -function createPieceMap(entries: { name: string; source: 'builtin' | 'user' | 'project' | 'ensemble' }[]): +function createPieceMap(entries: { name: string; source: 'builtin' | 'user' | 'project' | 'repertoire' }[]): Map { const pieces = new Map(); for (const entry of entries) { @@ -442,11 +442,11 @@ describe('buildCategorizedPieces', () => { expect(paths).toEqual(['Parent / Child']); }); - it('should append ensemble category for @scope pieces', () => { + it('should append repertoire category for @scope pieces', () => { const allPieces = createPieceMap([ { name: 'default', source: 'builtin' }, - { name: '@nrslib/takt-pack/expert', source: 'ensemble' }, - { name: '@nrslib/takt-pack/reviewer', source: 'ensemble' }, + { name: '@nrslib/takt-ensemble/expert', source: 'repertoire' }, + { name: '@nrslib/takt-ensemble/reviewer', source: 'repertoire' }, ]); const config = { pieceCategories: [{ name: 'Main', pieces: ['default'], children: [] }], @@ -459,21 +459,21 @@ describe('buildCategorizedPieces', () => { const categorized = buildCategorizedPieces(allPieces, config, process.cwd()); - // ensemble category is appended - const ensembleCat = categorized.categories.find((c) => c.name === 'ensemble'); - expect(ensembleCat).toBeDefined(); - expect(ensembleCat!.children).toHaveLength(1); - expect(ensembleCat!.children[0]!.name).toBe('@nrslib/takt-pack'); - expect(ensembleCat!.children[0]!.pieces).toEqual( - expect.arrayContaining(['@nrslib/takt-pack/expert', '@nrslib/takt-pack/reviewer']), + // repertoire category is appended + const repertoireCat = categorized.categories.find((c) => c.name === 'repertoire'); + expect(repertoireCat).toBeDefined(); + expect(repertoireCat!.children).toHaveLength(1); + expect(repertoireCat!.children[0]!.name).toBe('@nrslib/takt-ensemble'); + expect(repertoireCat!.children[0]!.pieces).toEqual( + expect.arrayContaining(['@nrslib/takt-ensemble/expert', '@nrslib/takt-ensemble/reviewer']), ); // @scope pieces must not appear in Others const othersCat = categorized.categories.find((c) => c.name === 'Others'); - expect(othersCat?.pieces ?? []).not.toContain('@nrslib/takt-pack/expert'); + expect(othersCat?.pieces ?? []).not.toContain('@nrslib/takt-ensemble/expert'); }); - it('should not append ensemble category when no @scope pieces exist', () => { + it('should not append repertoire category when no @scope pieces exist', () => { const allPieces = createPieceMap([{ name: 'default', source: 'builtin' }]); const config = { pieceCategories: [{ name: 'Main', pieces: ['default'], children: [] }], @@ -486,7 +486,7 @@ describe('buildCategorizedPieces', () => { const categorized = buildCategorizedPieces(allPieces, config, process.cwd()); - const ensembleCat = categorized.categories.find((c) => c.name === 'ensemble'); - expect(ensembleCat).toBeUndefined(); + const repertoireCat = categorized.categories.find((c) => c.name === 'repertoire'); + expect(repertoireCat).toBeUndefined(); }); }); diff --git a/src/__tests__/pieceLoader.test.ts b/src/__tests__/pieceLoader.test.ts index 50ff071..677be57 100644 --- a/src/__tests__/pieceLoader.test.ts +++ b/src/__tests__/pieceLoader.test.ts @@ -189,7 +189,7 @@ movements: }); -describe('loadPieceByIdentifier with @scope ref (ensemble)', () => { +describe('loadPieceByIdentifier with @scope ref (repertoire)', () => { let tempDir: string; let configDir: string; const originalTaktConfigDir = process.env.TAKT_CONFIG_DIR; @@ -210,14 +210,14 @@ describe('loadPieceByIdentifier with @scope ref (ensemble)', () => { rmSync(configDir, { recursive: true, force: true }); }); - it('should load piece by @scope ref (ensemble)', () => { - // Given: ensemble package with a piece file - const piecesDir = join(configDir, 'ensemble', '@nrslib', 'takt-pack', 'pieces'); + it('should load piece by @scope ref (repertoire)', () => { + // Given: repertoire package with a piece file + const piecesDir = join(configDir, 'repertoire', '@nrslib', 'takt-ensemble', 'pieces'); mkdirSync(piecesDir, { recursive: true }); writeFileSync(join(piecesDir, 'expert.yaml'), SAMPLE_PIECE); // When: piece is loaded via @scope ref - const piece = loadPieceByIdentifier('@nrslib/takt-pack/expert', tempDir); + const piece = loadPieceByIdentifier('@nrslib/takt-ensemble/expert', tempDir); // Then: the piece is resolved correctly expect(piece).not.toBeNull(); @@ -225,19 +225,19 @@ describe('loadPieceByIdentifier with @scope ref (ensemble)', () => { }); it('should return null for non-existent @scope piece', () => { - // Given: ensemble dir exists but the requested piece does not - const piecesDir = join(configDir, 'ensemble', '@nrslib', 'takt-pack', 'pieces'); + // Given: repertoire dir exists but the requested piece does not + const piecesDir = join(configDir, 'repertoire', '@nrslib', 'takt-ensemble', 'pieces'); mkdirSync(piecesDir, { recursive: true }); // When: a non-existent piece is requested - const piece = loadPieceByIdentifier('@nrslib/takt-pack/no-such-piece', tempDir); + const piece = loadPieceByIdentifier('@nrslib/takt-ensemble/no-such-piece', tempDir); // Then: null is returned expect(piece).toBeNull(); }); }); -describe('loadAllPiecesWithSources with ensemble pieces', () => { +describe('loadAllPiecesWithSources with repertoire pieces', () => { let tempDir: string; let configDir: string; const originalTaktConfigDir = process.env.TAKT_CONFIG_DIR; @@ -258,28 +258,28 @@ describe('loadAllPiecesWithSources with ensemble pieces', () => { rmSync(configDir, { recursive: true, force: true }); }); - it('should include ensemble pieces with @scope qualified names', () => { - // Given: ensemble package with a piece file - const piecesDir = join(configDir, 'ensemble', '@nrslib', 'takt-pack', 'pieces'); + it('should include repertoire pieces with @scope qualified names', () => { + // Given: repertoire package with a piece file + const piecesDir = join(configDir, 'repertoire', '@nrslib', 'takt-ensemble', 'pieces'); mkdirSync(piecesDir, { recursive: true }); writeFileSync(join(piecesDir, 'expert.yaml'), SAMPLE_PIECE); // When: all pieces are loaded const pieces = loadAllPiecesWithSources(tempDir); - // Then: the ensemble piece is included with 'ensemble' source - expect(pieces.has('@nrslib/takt-pack/expert')).toBe(true); - expect(pieces.get('@nrslib/takt-pack/expert')!.source).toBe('ensemble'); + // Then: the repertoire piece is included with 'repertoire' source + expect(pieces.has('@nrslib/takt-ensemble/expert')).toBe(true); + expect(pieces.get('@nrslib/takt-ensemble/expert')!.source).toBe('repertoire'); }); - it('should not throw when ensemble dir does not exist', () => { - // Given: no ensemble dir created (configDir/ensemble does not exist) + it('should not throw when repertoire dir does not exist', () => { + // Given: no repertoire dir created (configDir/repertoire does not exist) // When: all pieces are loaded const pieces = loadAllPiecesWithSources(tempDir); // Then: no @scope pieces are present and no error thrown - const ensemblePieces = Array.from(pieces.keys()).filter((k) => k.startsWith('@')); - expect(ensemblePieces).toHaveLength(0); + const repertoirePieces = Array.from(pieces.keys()).filter((k) => k.startsWith('@')); + expect(repertoirePieces).toHaveLength(0); }); }); diff --git a/src/__tests__/ensemble-atomic-update.test.ts b/src/__tests__/repertoire-atomic-update.test.ts similarity index 94% rename from src/__tests__/ensemble-atomic-update.test.ts rename to src/__tests__/repertoire-atomic-update.test.ts index 29b1872..8b4f105 100644 --- a/src/__tests__/ensemble-atomic-update.test.ts +++ b/src/__tests__/repertoire-atomic-update.test.ts @@ -1,7 +1,7 @@ /** - * Unit tests for ensemble atomic installation/update sequence. + * Unit tests for repertoire atomic installation/update sequence. * - * Target: src/features/ensemble/atomic-update.ts + * Target: src/features/repertoire/atomic-update.ts * * Atomic update steps under test: * Step 0: Clean up leftover .tmp/ and .bak/ from previous failed runs @@ -23,9 +23,9 @@ import { cleanupResiduals, atomicReplace, type AtomicReplaceOptions, -} from '../features/ensemble/atomic-update.js'; +} from '../features/repertoire/atomic-update.js'; -describe('ensemble atomic install: leftover cleanup (Step 0)', () => { +describe('repertoire atomic install: leftover cleanup (Step 0)', () => { let tempDir: string; beforeEach(() => { @@ -69,7 +69,7 @@ describe('ensemble atomic install: leftover cleanup (Step 0)', () => { }); }); -describe('ensemble atomic install: failure recovery', () => { +describe('repertoire atomic install: failure recovery', () => { let tempDir: string; beforeEach(() => { diff --git a/src/__tests__/ensemble-ref-integrity.test.ts b/src/__tests__/repertoire-ref-integrity.test.ts similarity index 67% rename from src/__tests__/ensemble-ref-integrity.test.ts rename to src/__tests__/repertoire-ref-integrity.test.ts index ba25909..780d79c 100644 --- a/src/__tests__/ensemble-ref-integrity.test.ts +++ b/src/__tests__/repertoire-ref-integrity.test.ts @@ -1,7 +1,7 @@ /** - * Unit tests for ensemble reference integrity scanner. + * Unit tests for repertoire reference integrity scanner. * - * Target: src/features/ensemble/remove.ts (findScopeReferences) + * Target: src/features/repertoire/remove.ts (findScopeReferences) * * Scanner searches for @scope package references in: * - {root}/pieces/**\/*.yaml @@ -18,10 +18,10 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs'; import { join } from 'node:path'; import { tmpdir } from 'node:os'; -import { findScopeReferences } from '../features/ensemble/remove.js'; -import { makeScanConfig } from './helpers/ensemble-test-helpers.js'; +import { findScopeReferences } from '../features/repertoire/remove.js'; +import { makeScanConfig } from './helpers/repertoire-test-helpers.js'; -describe('ensemble reference integrity: detection', () => { +describe('repertoire reference integrity: detection', () => { let tempDir: string; beforeEach(() => { @@ -34,52 +34,52 @@ describe('ensemble reference integrity: detection', () => { // U29: ~/.takt/pieces/ の @scope 参照を検出 // Given: {root}/pieces/my-review.yaml に - // persona: "@nrslib/takt-pack-fixture/expert-coder" を含む - // When: findScopeReferences("@nrslib/takt-pack-fixture", config) + // persona: "@nrslib/takt-ensemble-fixture/expert-coder" を含む + // When: findScopeReferences("@nrslib/takt-ensemble-fixture", config) // Then: my-review.yaml が検出される it('should detect @scope reference in global pieces YAML', () => { const piecesDir = join(tempDir, 'pieces'); mkdirSync(piecesDir, { recursive: true }); const pieceFile = join(piecesDir, 'my-review.yaml'); - writeFileSync(pieceFile, 'persona: "@nrslib/takt-pack-fixture/expert-coder"'); + writeFileSync(pieceFile, 'persona: "@nrslib/takt-ensemble-fixture/expert-coder"'); - const refs = findScopeReferences('@nrslib/takt-pack-fixture', makeScanConfig(tempDir)); + const refs = findScopeReferences('@nrslib/takt-ensemble-fixture', makeScanConfig(tempDir)); expect(refs.some((r) => r.filePath === pieceFile)).toBe(true); }); // U30: {root}/preferences/piece-categories.yaml の @scope 参照を検出 - // Given: piece-categories.yaml に @nrslib/takt-pack-fixture/expert を含む - // When: findScopeReferences("@nrslib/takt-pack-fixture", config) + // Given: piece-categories.yaml に @nrslib/takt-ensemble-fixture/expert を含む + // When: findScopeReferences("@nrslib/takt-ensemble-fixture", config) // Then: piece-categories.yaml が検出される it('should detect @scope reference in global piece-categories.yaml', () => { const prefsDir = join(tempDir, 'preferences'); mkdirSync(prefsDir, { recursive: true }); const categoriesFile = join(prefsDir, 'piece-categories.yaml'); - writeFileSync(categoriesFile, 'categories:\n - "@nrslib/takt-pack-fixture/expert"'); + writeFileSync(categoriesFile, 'categories:\n - "@nrslib/takt-ensemble-fixture/expert"'); - const refs = findScopeReferences('@nrslib/takt-pack-fixture', makeScanConfig(tempDir)); + const refs = findScopeReferences('@nrslib/takt-ensemble-fixture', makeScanConfig(tempDir)); expect(refs.some((r) => r.filePath === categoriesFile)).toBe(true); }); // U31: {root}/.takt/pieces/ の @scope 参照を検出 // Given: プロジェクト {root}/.takt/pieces/proj.yaml に @scope 参照 - // When: findScopeReferences("@nrslib/takt-pack-fixture", config) + // When: findScopeReferences("@nrslib/takt-ensemble-fixture", config) // Then: proj.yaml が検出される it('should detect @scope reference in project-level pieces YAML', () => { const projectPiecesDir = join(tempDir, '.takt', 'pieces'); mkdirSync(projectPiecesDir, { recursive: true }); const projFile = join(projectPiecesDir, 'proj.yaml'); - writeFileSync(projFile, 'persona: "@nrslib/takt-pack-fixture/expert-coder"'); + writeFileSync(projFile, 'persona: "@nrslib/takt-ensemble-fixture/expert-coder"'); - const refs = findScopeReferences('@nrslib/takt-pack-fixture', makeScanConfig(tempDir)); + const refs = findScopeReferences('@nrslib/takt-ensemble-fixture', makeScanConfig(tempDir)); expect(refs.some((r) => r.filePath === projFile)).toBe(true); }); }); -describe('ensemble reference integrity: non-detection', () => { +describe('repertoire reference integrity: non-detection', () => { let tempDir: string; beforeEach(() => { @@ -92,28 +92,28 @@ describe('ensemble reference integrity: non-detection', () => { // U32: @scope なし参照は検出しない // Given: persona: "coder" のみ(@scope なし) - // When: findScopeReferences("@nrslib/takt-pack-fixture", config) + // When: findScopeReferences("@nrslib/takt-ensemble-fixture", config) // Then: 結果が空配列 it('should not detect plain name references without @scope prefix', () => { const piecesDir = join(tempDir, 'pieces'); mkdirSync(piecesDir, { recursive: true }); writeFileSync(join(piecesDir, 'plain.yaml'), 'persona: "coder"'); - const refs = findScopeReferences('@nrslib/takt-pack-fixture', makeScanConfig(tempDir)); + const refs = findScopeReferences('@nrslib/takt-ensemble-fixture', makeScanConfig(tempDir)); expect(refs).toHaveLength(0); }); // U33: 別スコープは検出しない // Given: persona: "@other/package/name" - // When: findScopeReferences("@nrslib/takt-pack-fixture", config) + // When: findScopeReferences("@nrslib/takt-ensemble-fixture", config) // Then: 結果が空配列 it('should not detect references to a different @scope package', () => { const piecesDir = join(tempDir, 'pieces'); mkdirSync(piecesDir, { recursive: true }); writeFileSync(join(piecesDir, 'other.yaml'), 'persona: "@other/package/name"'); - const refs = findScopeReferences('@nrslib/takt-pack-fixture', makeScanConfig(tempDir)); + const refs = findScopeReferences('@nrslib/takt-ensemble-fixture', makeScanConfig(tempDir)); expect(refs).toHaveLength(0); }); diff --git a/src/__tests__/ensemble-scope-resolver.test.ts b/src/__tests__/repertoire-scope-resolver.test.ts similarity index 74% rename from src/__tests__/ensemble-scope-resolver.test.ts rename to src/__tests__/repertoire-scope-resolver.test.ts index 02cef2c..d085005 100644 --- a/src/__tests__/ensemble-scope-resolver.test.ts +++ b/src/__tests__/repertoire-scope-resolver.test.ts @@ -1,5 +1,5 @@ /** - * Unit tests for ensemble @scope resolution and facet resolution chain. + * Unit tests for repertoire @scope resolution and facet resolution chain. * * Covers: * A. @scope reference resolution (src/faceted-prompting/scope.ts) @@ -8,7 +8,7 @@ * * @scope resolution rules: * "@{owner}/{repo}/{name}" in a facet field → - * {ensembleDir}/@{owner}/{repo}/facets/{type}/{name}.md + * {repertoireDir}/@{owner}/{repo}/facets/{type}/{name}.md * * Name constraints: * owner: /^[a-z0-9][a-z0-9-]*$/ (lowercase only after normalization) @@ -16,7 +16,7 @@ * facet/piece name: /^[a-z0-9][a-z0-9-]*$/ * * Facet resolution order (package piece): - * 1. package-local: {ensembleDir}/@{owner}/{repo}/facets/{type}/{facet}.md + * 1. package-local: {repertoireDir}/@{owner}/{repo}/facets/{type}/{facet}.md * 2. project: .takt/facets/{type}/{facet}.md * 3. user: ~/.takt/facets/{type}/{facet}.md * 4. builtin: builtins/{lang}/facets/{type}/{facet}.md @@ -55,45 +55,45 @@ describe('@scope reference resolution', () => { }); // U34: persona @scope 解決 - // Input: "@nrslib/takt-pack-fixture/expert-coder" (personas field) - // Expect: resolves to {ensembleDir}/@nrslib/takt-pack-fixture/facets/personas/expert-coder.md - it('should resolve persona @scope reference to ensemble faceted path', () => { - const ensembleDir = tempDir; - const ref = '@nrslib/takt-pack-fixture/expert-coder'; + // Input: "@nrslib/takt-ensemble-fixture/expert-coder" (personas field) + // Expect: resolves to {repertoireDir}/@nrslib/takt-ensemble-fixture/facets/personas/expert-coder.md + it('should resolve persona @scope reference to repertoire faceted path', () => { + const repertoireDir = tempDir; + const ref = '@nrslib/takt-ensemble-fixture/expert-coder'; const scopeRef = parseScopeRef(ref); - const resolved = resolveScopeRef(scopeRef, 'personas', ensembleDir); + const resolved = resolveScopeRef(scopeRef, 'personas', repertoireDir); - const expected = join(ensembleDir, '@nrslib', 'takt-pack-fixture', 'facets', 'personas', 'expert-coder.md'); + const expected = join(repertoireDir, '@nrslib', 'takt-ensemble-fixture', 'facets', 'personas', 'expert-coder.md'); expect(resolved).toBe(expected); }); // U35: policy @scope 解決 - // Input: "@nrslib/takt-pack-fixture/strict-coding" (policies field) - // Expect: resolves to {ensembleDir}/@nrslib/takt-pack-fixture/facets/policies/strict-coding.md - it('should resolve policy @scope reference to ensemble faceted path', () => { - const ensembleDir = tempDir; - const ref = '@nrslib/takt-pack-fixture/strict-coding'; + // Input: "@nrslib/takt-ensemble-fixture/strict-coding" (policies field) + // Expect: resolves to {repertoireDir}/@nrslib/takt-ensemble-fixture/facets/policies/strict-coding.md + it('should resolve policy @scope reference to repertoire faceted path', () => { + const repertoireDir = tempDir; + const ref = '@nrslib/takt-ensemble-fixture/strict-coding'; const scopeRef = parseScopeRef(ref); - const resolved = resolveScopeRef(scopeRef, 'policies', ensembleDir); + const resolved = resolveScopeRef(scopeRef, 'policies', repertoireDir); - const expected = join(ensembleDir, '@nrslib', 'takt-pack-fixture', 'facets', 'policies', 'strict-coding.md'); + const expected = join(repertoireDir, '@nrslib', 'takt-ensemble-fixture', 'facets', 'policies', 'strict-coding.md'); expect(resolved).toBe(expected); }); // U36: 大文字正規化 - // Input: "@NrsLib/Takt-Pack-Fixture/expert-coder" + // Input: "@NrsLib/Takt-Ensemble-Fixture/expert-coder" // Expect: owner and repo lowercase-normalized; name kept as-is (must already be lowercase per spec) it('should normalize uppercase @scope references to lowercase before resolving', () => { - const ensembleDir = tempDir; - const ref = '@NrsLib/Takt-Pack-Fixture/expert-coder'; + const repertoireDir = tempDir; + const ref = '@NrsLib/Takt-Ensemble-Fixture/expert-coder'; const scopeRef = parseScopeRef(ref); // owner and repo are normalized to lowercase expect(scopeRef.owner).toBe('nrslib'); - expect(scopeRef.repo).toBe('takt-pack-fixture'); + expect(scopeRef.repo).toBe('takt-ensemble-fixture'); - const resolved = resolveScopeRef(scopeRef, 'personas', ensembleDir); - const expected = join(ensembleDir, '@nrslib', 'takt-pack-fixture', 'facets', 'personas', 'expert-coder.md'); + const resolved = resolveScopeRef(scopeRef, 'personas', repertoireDir); + const expected = join(repertoireDir, '@nrslib', 'takt-ensemble-fixture', 'facets', 'personas', 'expert-coder.md'); expect(resolved).toBe(expected); }); @@ -101,13 +101,13 @@ describe('@scope reference resolution', () => { // Input: "@nonexistent/package/facet" // Expect: resolveFacetPath returns undefined (file not found at resolved path) it('should throw error when @scope reference points to non-existent package', () => { - const ensembleDir = tempDir; + const repertoireDir = tempDir; const ref = '@nonexistent/package/facet'; // resolveFacetPath returns undefined when the @scope file does not exist const result = resolveFacetPath(ref, 'personas', { lang: 'en', - ensembleDir, + repertoireDir, }); expect(result).toBeUndefined(); @@ -177,9 +177,9 @@ describe('facet resolution chain: package-local layer', () => { // When: パッケージ内ピースからファセット解決 // Then: package-local 層のファセットが返る it('should prefer package-local facet over project/user/builtin layers', () => { - const ensembleDir = join(tempDir, 'ensemble'); - const packagePiecesDir = join(ensembleDir, '@nrslib', 'takt-pack-fixture', 'pieces'); - const packageFacetDir = join(ensembleDir, '@nrslib', 'takt-pack-fixture', 'facets', 'personas'); + const repertoireDir = join(tempDir, 'repertoire'); + const packagePiecesDir = join(repertoireDir, '@nrslib', 'takt-ensemble-fixture', 'pieces'); + const packageFacetDir = join(repertoireDir, '@nrslib', 'takt-ensemble-fixture', 'facets', 'personas'); const projectFacetDir = join(tempDir, 'project', '.takt', 'facets', 'personas'); // Create both package-local and project facet files with the same name @@ -192,7 +192,7 @@ describe('facet resolution chain: package-local layer', () => { const candidateDirs = buildCandidateDirsWithPackage('personas', { lang: 'en', pieceDir: packagePiecesDir, - ensembleDir, + repertoireDir, projectDir: join(tempDir, 'project'), }); @@ -205,8 +205,8 @@ describe('facet resolution chain: package-local layer', () => { // When: ファセット解決 // Then: project 層のファセットが返る it('should fall back to project facet when package-local does not have it', () => { - const ensembleDir = join(tempDir, 'ensemble'); - const packagePiecesDir = join(ensembleDir, '@nrslib', 'takt-pack-fixture', 'pieces'); + const repertoireDir = join(tempDir, 'repertoire'); + const packagePiecesDir = join(repertoireDir, '@nrslib', 'takt-ensemble-fixture', 'pieces'); const projectFacetDir = join(tempDir, 'project', '.takt', 'facets', 'personas'); mkdirSync(packagePiecesDir, { recursive: true }); @@ -218,7 +218,7 @@ describe('facet resolution chain: package-local layer', () => { const resolved = resolveFacetPath('expert-coder', 'personas', { lang: 'en', pieceDir: packagePiecesDir, - ensembleDir, + repertoireDir, projectDir: join(tempDir, 'project'), }); @@ -230,9 +230,9 @@ describe('facet resolution chain: package-local layer', () => { // When: ファセット解決 // Then: package-local は無視。project → user → builtin の3層で解決 it('should not consult package-local layer for non-package pieces', () => { - const ensembleDir = join(tempDir, 'ensemble'); - const packageFacetDir = join(ensembleDir, '@nrslib', 'takt-pack-fixture', 'facets', 'personas'); - // Non-package pieceDir (not under ensembleDir) + const repertoireDir = join(tempDir, 'repertoire'); + const packageFacetDir = join(repertoireDir, '@nrslib', 'takt-ensemble-fixture', 'facets', 'personas'); + // Non-package pieceDir (not under repertoireDir) const globalPiecesDir = join(tempDir, 'global-pieces'); mkdirSync(packageFacetDir, { recursive: true }); @@ -242,7 +242,7 @@ describe('facet resolution chain: package-local layer', () => { const candidateDirs = buildCandidateDirsWithPackage('personas', { lang: 'en', pieceDir: globalPiecesDir, - ensembleDir, + repertoireDir, }); // Package-local dir should NOT be in candidates for non-package pieces @@ -252,14 +252,14 @@ describe('facet resolution chain: package-local layer', () => { describe('package piece detection', () => { // U46: パッケージ所属は pieceDir パスから判定 - // Given: pieceDir が {ensembleDir}/@nrslib/repo/pieces/ 配下 + // Given: pieceDir が {repertoireDir}/@nrslib/repo/pieces/ 配下 // When: isPackagePiece(pieceDir) 呼び出し // Then: true が返る - it('should return true for pieceDir under ensemble/@scope/repo/pieces/', () => { - const ensembleDir = '/home/user/.takt/ensemble'; - const pieceDir = '/home/user/.takt/ensemble/@nrslib/takt-pack-fixture/pieces'; + it('should return true for pieceDir under repertoire/@scope/repo/pieces/', () => { + const repertoireDir = '/home/user/.takt/repertoire'; + const pieceDir = '/home/user/.takt/repertoire/@nrslib/takt-ensemble-fixture/pieces'; - expect(isPackagePiece(pieceDir, ensembleDir)).toBe(true); + expect(isPackagePiece(pieceDir, repertoireDir)).toBe(true); }); // U47: 非パッケージ pieceDir は false @@ -267,9 +267,9 @@ describe('package piece detection', () => { // When: isPackagePiece(pieceDir) 呼び出し // Then: false が返る it('should return false for pieceDir under global pieces directory', () => { - const ensembleDir = '/home/user/.takt/ensemble'; + const repertoireDir = '/home/user/.takt/repertoire'; const pieceDir = '/home/user/.takt/pieces'; - expect(isPackagePiece(pieceDir, ensembleDir)).toBe(false); + expect(isPackagePiece(pieceDir, repertoireDir)).toBe(false); }); }); diff --git a/src/__tests__/ensemble/atomic-update.test.ts b/src/__tests__/repertoire/atomic-update.test.ts similarity index 98% rename from src/__tests__/ensemble/atomic-update.test.ts rename to src/__tests__/repertoire/atomic-update.test.ts index 2b8673a..9021d6d 100644 --- a/src/__tests__/ensemble/atomic-update.test.ts +++ b/src/__tests__/repertoire/atomic-update.test.ts @@ -15,7 +15,7 @@ import { cleanupResiduals, atomicReplace, type AtomicReplaceOptions, -} from '../../features/ensemble/atomic-update.js'; +} from '../../features/repertoire/atomic-update.js'; // --------------------------------------------------------------------------- // cleanupResiduals diff --git a/src/__tests__/ensemble/file-filter.test.ts b/src/__tests__/repertoire/file-filter.test.ts similarity index 98% rename from src/__tests__/ensemble/file-filter.test.ts rename to src/__tests__/repertoire/file-filter.test.ts index a49f94d..dcb236b 100644 --- a/src/__tests__/ensemble/file-filter.test.ts +++ b/src/__tests__/repertoire/file-filter.test.ts @@ -27,7 +27,7 @@ import { MAX_FILE_COUNT, ALLOWED_EXTENSIONS, ALLOWED_DIRS, -} from '../../features/ensemble/file-filter.js'; +} from '../../features/repertoire/file-filter.js'; // --------------------------------------------------------------------------- // isAllowedExtension @@ -39,7 +39,7 @@ describe('isAllowedExtension', () => { }); it('should allow .yaml files', () => { - expect(isAllowedExtension('takt-package.yaml')).toBe(true); + expect(isAllowedExtension('takt-repertoire.yaml')).toBe(true); }); it('should allow .yml files', () => { diff --git a/src/__tests__/ensemble/github-ref-resolver.test.ts b/src/__tests__/repertoire/github-ref-resolver.test.ts similarity index 97% rename from src/__tests__/ensemble/github-ref-resolver.test.ts rename to src/__tests__/repertoire/github-ref-resolver.test.ts index 0e79350..5016f5e 100644 --- a/src/__tests__/ensemble/github-ref-resolver.test.ts +++ b/src/__tests__/repertoire/github-ref-resolver.test.ts @@ -9,7 +9,7 @@ */ import { describe, it, expect, vi } from 'vitest'; -import { resolveRef } from '../../features/ensemble/github-ref-resolver.js'; +import { resolveRef } from '../../features/repertoire/github-ref-resolver.js'; describe('resolveRef', () => { it('should return specRef directly when provided', () => { diff --git a/src/__tests__/ensemble/github-spec.test.ts b/src/__tests__/repertoire/github-spec.test.ts similarity index 97% rename from src/__tests__/ensemble/github-spec.test.ts rename to src/__tests__/repertoire/github-spec.test.ts index b5792fb..a9f1e5f 100644 --- a/src/__tests__/ensemble/github-spec.test.ts +++ b/src/__tests__/repertoire/github-spec.test.ts @@ -5,7 +5,7 @@ */ import { describe, it, expect } from 'vitest'; -import { parseGithubSpec } from '../../features/ensemble/github-spec.js'; +import { parseGithubSpec } from '../../features/repertoire/github-spec.js'; describe('parseGithubSpec', () => { describe('happy path', () => { diff --git a/src/__tests__/ensemble/list.test.ts b/src/__tests__/repertoire/list.test.ts similarity index 67% rename from src/__tests__/ensemble/list.test.ts rename to src/__tests__/repertoire/list.test.ts index 8f12284..8cad43c 100644 --- a/src/__tests__/ensemble/list.test.ts +++ b/src/__tests__/repertoire/list.test.ts @@ -1,10 +1,10 @@ /** - * Tests for ensemble list display data retrieval. + * Tests for repertoire list display data retrieval. * * Covers: - * - readPackageInfo(): reads description from takt-package.yaml and ref/commit from .takt-pack-lock.yaml + * - readPackageInfo(): reads description from takt-repertoire.yaml and ref/commit from .takt-repertoire-lock.yaml * - commit is truncated to first 7 characters for display - * - listPackages(): enumerates all installed packages under ensemble/ + * - listPackages(): enumerates all installed packages under repertoire/ * - Multiple packages are correctly listed */ @@ -15,7 +15,7 @@ import { tmpdir } from 'node:os'; import { readPackageInfo, listPackages, -} from '../../features/ensemble/list.js'; +} from '../../features/repertoire/list.js'; // --------------------------------------------------------------------------- // readPackageInfo @@ -32,16 +32,16 @@ describe('readPackageInfo', () => { rmSync(tempDir, { recursive: true, force: true }); }); - it('should read description from takt-package.yaml', () => { - // Given: a package directory with takt-package.yaml and .takt-pack-lock.yaml + it('should read description from takt-repertoire.yaml', () => { + // Given: a package directory with takt-repertoire.yaml and .takt-repertoire-lock.yaml const packageDir = join(tempDir, '@nrslib', 'takt-fullstack'); mkdirSync(packageDir, { recursive: true }); writeFileSync( - join(packageDir, 'takt-package.yaml'), + join(packageDir, 'takt-repertoire.yaml'), 'description: フルスタック開発ワークフロー\n', ); writeFileSync( - join(packageDir, '.takt-pack-lock.yaml'), + join(packageDir, '.takt-repertoire-lock.yaml'), `source: github:nrslib/takt-fullstack ref: v1.2.0 commit: abc1234def5678 @@ -63,9 +63,9 @@ imported_at: 2026-02-20T12:00:00.000Z // Given: package with a long commit SHA const packageDir = join(tempDir, '@nrslib', 'takt-security-facets'); mkdirSync(packageDir, { recursive: true }); - writeFileSync(join(packageDir, 'takt-package.yaml'), 'description: Security facets\n'); + writeFileSync(join(packageDir, 'takt-repertoire.yaml'), 'description: Security facets\n'); writeFileSync( - join(packageDir, '.takt-pack-lock.yaml'), + join(packageDir, '.takt-repertoire-lock.yaml'), `source: github:nrslib/takt-security-facets ref: HEAD commit: def5678901234567 @@ -82,12 +82,12 @@ imported_at: 2026-02-20T12:00:00.000Z }); it('should handle package without description field', () => { - // Given: takt-package.yaml with no description + // Given: takt-repertoire.yaml with no description const packageDir = join(tempDir, '@acme', 'takt-backend'); mkdirSync(packageDir, { recursive: true }); - writeFileSync(join(packageDir, 'takt-package.yaml'), 'path: takt\n'); + writeFileSync(join(packageDir, 'takt-repertoire.yaml'), 'path: takt\n'); writeFileSync( - join(packageDir, '.takt-pack-lock.yaml'), + join(packageDir, '.takt-repertoire-lock.yaml'), `source: github:acme/takt-backend ref: v2.0.0 commit: 789abcdef0123 @@ -107,9 +107,9 @@ imported_at: 2026-01-15T08:30:00.000Z // Given: package imported from default branch const packageDir = join(tempDir, '@acme', 'no-tag-pkg'); mkdirSync(packageDir, { recursive: true }); - writeFileSync(join(packageDir, 'takt-package.yaml'), 'description: No tag\n'); + writeFileSync(join(packageDir, 'takt-repertoire.yaml'), 'description: No tag\n'); writeFileSync( - join(packageDir, '.takt-pack-lock.yaml'), + join(packageDir, '.takt-repertoire-lock.yaml'), `source: github:acme/no-tag-pkg ref: HEAD commit: aabbccddeeff00 @@ -128,8 +128,8 @@ imported_at: 2026-02-01T00:00:00.000Z // Given: package directory with no lock file const packageDir = join(tempDir, '@acme', 'no-lock-pkg'); mkdirSync(packageDir, { recursive: true }); - writeFileSync(join(packageDir, 'takt-package.yaml'), 'description: No lock\n'); - // .takt-pack-lock.yaml intentionally not created + writeFileSync(join(packageDir, 'takt-repertoire.yaml'), 'description: No lock\n'); + // .takt-repertoire-lock.yaml intentionally not created // When: package info is read const info = readPackageInfo(packageDir, '@acme/no-lock-pkg'); @@ -156,18 +156,18 @@ describe('listPackages', () => { }); function createPackage( - ensembleDir: string, + repertoireDir: string, owner: string, repo: string, description: string, ref: string, commit: string, ): void { - const packageDir = join(ensembleDir, `@${owner}`, repo); + const packageDir = join(repertoireDir, `@${owner}`, repo); mkdirSync(packageDir, { recursive: true }); - writeFileSync(join(packageDir, 'takt-package.yaml'), `description: ${description}\n`); + writeFileSync(join(packageDir, 'takt-repertoire.yaml'), `description: ${description}\n`); writeFileSync( - join(packageDir, '.takt-pack-lock.yaml'), + join(packageDir, '.takt-repertoire-lock.yaml'), `source: github:${owner}/${repo} ref: ${ref} commit: ${commit} @@ -176,15 +176,15 @@ imported_at: 2026-02-20T12:00:00.000Z ); } - it('should list all installed packages from ensemble directory', () => { - // Given: ensemble directory with 3 packages - const ensembleDir = join(tempDir, 'ensemble'); - createPackage(ensembleDir, 'nrslib', 'takt-fullstack', 'Fullstack workflow', 'v1.2.0', 'abc1234def5678'); - createPackage(ensembleDir, 'nrslib', 'takt-security-facets', 'Security facets', 'HEAD', 'def5678901234'); - createPackage(ensembleDir, 'acme-corp', 'takt-backend', 'Backend facets', 'v2.0.0', '789abcdef0123'); + it('should list all installed packages from repertoire directory', () => { + // Given: repertoire directory with 3 packages + const repertoireDir = join(tempDir, 'repertoire'); + createPackage(repertoireDir, 'nrslib', 'takt-fullstack', 'Fullstack workflow', 'v1.2.0', 'abc1234def5678'); + createPackage(repertoireDir, 'nrslib', 'takt-security-facets', 'Security facets', 'HEAD', 'def5678901234'); + createPackage(repertoireDir, 'acme-corp', 'takt-backend', 'Backend facets', 'v2.0.0', '789abcdef0123'); // When: packages are listed - const packages = listPackages(ensembleDir); + const packages = listPackages(repertoireDir); // Then: all 3 packages are returned expect(packages).toHaveLength(3); @@ -194,25 +194,25 @@ imported_at: 2026-02-20T12:00:00.000Z expect(scopes).toContain('@acme-corp/takt-backend'); }); - it('should return empty list when ensemble directory has no packages', () => { - // Given: empty ensemble directory - const ensembleDir = join(tempDir, 'ensemble'); - mkdirSync(ensembleDir, { recursive: true }); + it('should return empty list when repertoire directory has no packages', () => { + // Given: empty repertoire directory + const repertoireDir = join(tempDir, 'repertoire'); + mkdirSync(repertoireDir, { recursive: true }); // When: packages are listed - const packages = listPackages(ensembleDir); + const packages = listPackages(repertoireDir); // Then: empty list expect(packages).toHaveLength(0); }); it('should include correct commit (truncated to 7 chars) for each package', () => { - // Given: ensemble with one package - const ensembleDir = join(tempDir, 'ensemble'); - createPackage(ensembleDir, 'nrslib', 'takt-fullstack', 'Fullstack', 'v1.2.0', 'abc1234def5678'); + // Given: repertoire with one package + const repertoireDir = join(tempDir, 'repertoire'); + createPackage(repertoireDir, 'nrslib', 'takt-fullstack', 'Fullstack', 'v1.2.0', 'abc1234def5678'); // When: packages are listed - const packages = listPackages(ensembleDir); + const packages = listPackages(repertoireDir); // Then: commit is 7 chars const pkg = packages.find((p) => p.scope === '@nrslib/takt-fullstack')!; diff --git a/src/__tests__/ensemble/lock-file.test.ts b/src/__tests__/repertoire/lock-file.test.ts similarity index 95% rename from src/__tests__/ensemble/lock-file.test.ts rename to src/__tests__/repertoire/lock-file.test.ts index 9a7ab6c..423aa82 100644 --- a/src/__tests__/ensemble/lock-file.test.ts +++ b/src/__tests__/repertoire/lock-file.test.ts @@ -1,11 +1,11 @@ /** - * Tests for .takt-pack-lock.yaml generation and parsing. + * Tests for .takt-repertoire-lock.yaml generation and parsing. * * Covers: * - extractCommitSha: parse SHA from tarball directory name {owner}-{repo}-{sha}/ * - generateLockFile: produces correct fields (source, ref, commit, imported_at) * - ref defaults to "HEAD" when not specified - * - parseLockFile: reads .takt-pack-lock.yaml content + * - parseLockFile: reads .takt-repertoire-lock.yaml content */ import { describe, it, expect } from 'vitest'; @@ -13,7 +13,7 @@ import { extractCommitSha, generateLockFile, parseLockFile, -} from '../../features/ensemble/lock-file.js'; +} from '../../features/repertoire/lock-file.js'; // --------------------------------------------------------------------------- // extractCommitSha @@ -117,7 +117,7 @@ describe('generateLockFile', () => { // --------------------------------------------------------------------------- describe('parseLockFile', () => { - it('should parse a valid .takt-pack-lock.yaml string', () => { + it('should parse a valid .takt-repertoire-lock.yaml string', () => { // Given: lock file YAML content const yaml = `source: github:nrslib/takt-fullstack ref: v1.2.0 diff --git a/src/__tests__/ensemble/pack-summary.test.ts b/src/__tests__/repertoire/pack-summary.test.ts similarity index 99% rename from src/__tests__/ensemble/pack-summary.test.ts rename to src/__tests__/repertoire/pack-summary.test.ts index 0ced975..a4eae49 100644 --- a/src/__tests__/ensemble/pack-summary.test.ts +++ b/src/__tests__/repertoire/pack-summary.test.ts @@ -8,7 +8,7 @@ */ import { describe, it, expect } from 'vitest'; -import { summarizeFacetsByType, detectEditPieces, formatEditPieceWarnings } from '../../features/ensemble/pack-summary.js'; +import { summarizeFacetsByType, detectEditPieces, formatEditPieceWarnings } from '../../features/repertoire/pack-summary.js'; // --------------------------------------------------------------------------- // summarizeFacetsByType diff --git a/src/__tests__/ensemble/package-facet-resolution.test.ts b/src/__tests__/repertoire/package-facet-resolution.test.ts similarity index 73% rename from src/__tests__/ensemble/package-facet-resolution.test.ts rename to src/__tests__/repertoire/package-facet-resolution.test.ts index 80ff09c..9ed9c3f 100644 --- a/src/__tests__/ensemble/package-facet-resolution.test.ts +++ b/src/__tests__/repertoire/package-facet-resolution.test.ts @@ -2,7 +2,7 @@ * Tests for package-local facet resolution chain. * * Covers: - * - isPackagePiece(): detects if pieceDir is under ~/.takt/ensemble/@owner/repo/pieces/ + * - isPackagePiece(): detects if pieceDir is under ~/.takt/repertoire/@owner/repo/pieces/ * - getPackageFromPieceDir(): extracts @owner/repo from pieceDir path * - Package pieces use 4-layer chain: package-local → project → user → builtin * - Non-package pieces use 3-layer chain: project → user → builtin @@ -34,27 +34,27 @@ describe('isPackagePiece', () => { rmSync(tempDir, { recursive: true, force: true }); }); - it('should return true when pieceDir is under ensemble/@owner/repo/pieces/', () => { - // Given: pieceDir under the ensemble directory structure - const ensembleDir = join(tempDir, 'ensemble'); - const pieceDir = join(ensembleDir, '@nrslib', 'takt-fullstack', 'pieces'); + it('should return true when pieceDir is under repertoire/@owner/repo/pieces/', () => { + // Given: pieceDir under the repertoire directory structure + const repertoireDir = join(tempDir, 'repertoire'); + const pieceDir = join(repertoireDir, '@nrslib', 'takt-fullstack', 'pieces'); // When: checking if it is a package piece - const result = isPackagePiece(pieceDir, ensembleDir); + const result = isPackagePiece(pieceDir, repertoireDir); // Then: it is recognized as a package piece expect(result).toBe(true); }); it('should return false when pieceDir is under user global pieces directory', () => { - // Given: pieceDir in ~/.takt/pieces/ (not ensemble) + // Given: pieceDir in ~/.takt/pieces/ (not repertoire) const globalPiecesDir = join(tempDir, 'pieces'); mkdirSync(globalPiecesDir, { recursive: true }); - const ensembleDir = join(tempDir, 'ensemble'); + const repertoireDir = join(tempDir, 'repertoire'); // When: checking - const result = isPackagePiece(globalPiecesDir, ensembleDir); + const result = isPackagePiece(globalPiecesDir, repertoireDir); // Then: not a package piece expect(result).toBe(false); @@ -65,10 +65,10 @@ describe('isPackagePiece', () => { const projectPiecesDir = join(tempDir, '.takt', 'pieces'); mkdirSync(projectPiecesDir, { recursive: true }); - const ensembleDir = join(tempDir, 'ensemble'); + const repertoireDir = join(tempDir, 'repertoire'); // When: checking - const result = isPackagePiece(projectPiecesDir, ensembleDir); + const result = isPackagePiece(projectPiecesDir, repertoireDir); // Then: not a package piece expect(result).toBe(false); @@ -79,10 +79,10 @@ describe('isPackagePiece', () => { const builtinPiecesDir = join(tempDir, 'builtins', 'ja', 'pieces'); mkdirSync(builtinPiecesDir, { recursive: true }); - const ensembleDir = join(tempDir, 'ensemble'); + const repertoireDir = join(tempDir, 'repertoire'); // When: checking - const result = isPackagePiece(builtinPiecesDir, ensembleDir); + const result = isPackagePiece(builtinPiecesDir, repertoireDir); // Then: not a package piece expect(result).toBe(false); @@ -104,13 +104,13 @@ describe('getPackageFromPieceDir', () => { rmSync(tempDir, { recursive: true, force: true }); }); - it('should extract owner and repo from ensemble pieceDir', () => { - // Given: pieceDir under ensemble - const ensembleDir = join(tempDir, 'ensemble'); - const pieceDir = join(ensembleDir, '@nrslib', 'takt-fullstack', 'pieces'); + it('should extract owner and repo from repertoire pieceDir', () => { + // Given: pieceDir under repertoire + const repertoireDir = join(tempDir, 'repertoire'); + const pieceDir = join(repertoireDir, '@nrslib', 'takt-fullstack', 'pieces'); // When: package is extracted - const pkg = getPackageFromPieceDir(pieceDir, ensembleDir); + const pkg = getPackageFromPieceDir(pieceDir, repertoireDir); // Then: owner and repo are correct expect(pkg).not.toBeUndefined(); @@ -119,12 +119,12 @@ describe('getPackageFromPieceDir', () => { }); it('should return undefined for non-package pieceDir', () => { - // Given: pieceDir not under ensemble + // Given: pieceDir not under repertoire const pieceDir = join(tempDir, 'pieces'); - const ensembleDir = join(tempDir, 'ensemble'); + const repertoireDir = join(tempDir, 'repertoire'); // When: package is extracted - const pkg = getPackageFromPieceDir(pieceDir, ensembleDir); + const pkg = getPackageFromPieceDir(pieceDir, repertoireDir); // Then: undefined (not a package piece) expect(pkg).toBeUndefined(); @@ -148,25 +148,25 @@ describe('buildCandidateDirsWithPackage', () => { it('should include package-local dir as first candidate for package piece', () => { // Given: a package piece context - const ensembleDir = join(tempDir, 'ensemble'); - const pieceDir = join(ensembleDir, '@nrslib', 'takt-fullstack', 'pieces'); + const repertoireDir = join(tempDir, 'repertoire'); + const pieceDir = join(repertoireDir, '@nrslib', 'takt-fullstack', 'pieces'); const projectDir = join(tempDir, 'project'); - const context = { projectDir, lang: 'ja' as const, pieceDir, ensembleDir }; + const context = { projectDir, lang: 'ja' as const, pieceDir, repertoireDir }; // When: candidate directories are built const dirs = buildCandidateDirsWithPackage('personas', context); // Then: package-local dir is first - const expectedPackageLocal = join(ensembleDir, '@nrslib', 'takt-fullstack', 'facets', 'personas'); + const expectedPackageLocal = join(repertoireDir, '@nrslib', 'takt-fullstack', 'facets', 'personas'); expect(dirs[0]).toBe(expectedPackageLocal); }); it('should have 4 candidate dirs for package piece: package-local, project, user, builtin', () => { // Given: package piece context - const ensembleDir = join(tempDir, 'ensemble'); - const pieceDir = join(ensembleDir, '@nrslib', 'takt-fullstack', 'pieces'); + const repertoireDir = join(tempDir, 'repertoire'); + const pieceDir = join(repertoireDir, '@nrslib', 'takt-fullstack', 'pieces'); const projectDir = join(tempDir, 'project'); - const context = { projectDir, lang: 'ja' as const, pieceDir, ensembleDir }; + const context = { projectDir, lang: 'ja' as const, pieceDir, repertoireDir }; // When: candidate directories are built const dirs = buildCandidateDirsWithPackage('personas', context); @@ -176,14 +176,14 @@ describe('buildCandidateDirsWithPackage', () => { }); it('should have 3 candidate dirs for non-package piece: project, user, builtin', () => { - // Given: non-package piece context (no ensemble path) + // Given: non-package piece context (no repertoire path) const projectDir = join(tempDir, 'project'); const userPiecesDir = join(tempDir, 'pieces'); const context = { projectDir, lang: 'ja' as const, pieceDir: userPiecesDir, - ensembleDir: join(tempDir, 'ensemble'), + repertoireDir: join(tempDir, 'repertoire'), }; // When: candidate directories are built @@ -195,8 +195,8 @@ describe('buildCandidateDirsWithPackage', () => { it('should resolve package-local facet before project-level for package piece', () => { // Given: both package-local and project-level facet files exist - const ensembleDir = join(tempDir, 'ensemble'); - const pkgFacetDir = join(ensembleDir, '@nrslib', 'takt-fullstack', 'facets', 'personas'); + const repertoireDir = join(tempDir, 'repertoire'); + const pkgFacetDir = join(repertoireDir, '@nrslib', 'takt-fullstack', 'facets', 'personas'); mkdirSync(pkgFacetDir, { recursive: true }); writeFileSync(join(pkgFacetDir, 'expert-coder.md'), 'Package persona'); @@ -205,8 +205,8 @@ describe('buildCandidateDirsWithPackage', () => { mkdirSync(projectFacetDir, { recursive: true }); writeFileSync(join(projectFacetDir, 'expert-coder.md'), 'Project persona'); - const pieceDir = join(ensembleDir, '@nrslib', 'takt-fullstack', 'pieces'); - const context = { projectDir, lang: 'ja' as const, pieceDir, ensembleDir }; + const pieceDir = join(repertoireDir, '@nrslib', 'takt-fullstack', 'pieces'); + const context = { projectDir, lang: 'ja' as const, pieceDir, repertoireDir }; // When: candidate directories are built const dirs = buildCandidateDirsWithPackage('personas', context); diff --git a/src/__tests__/ensemble/remove-reference-check.test.ts b/src/__tests__/repertoire/remove-reference-check.test.ts similarity index 94% rename from src/__tests__/ensemble/remove-reference-check.test.ts rename to src/__tests__/repertoire/remove-reference-check.test.ts index 2eb8a7c..0b43bff 100644 --- a/src/__tests__/ensemble/remove-reference-check.test.ts +++ b/src/__tests__/repertoire/remove-reference-check.test.ts @@ -1,5 +1,5 @@ /** - * Tests for reference integrity check during ensemble remove. + * Tests for reference integrity check during repertoire remove. * * Covers: * - shouldRemoveOwnerDir(): returns true when owner dir has no other packages @@ -9,7 +9,7 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { mkdtempSync, mkdirSync, rmSync } from 'node:fs'; import { join } from 'node:path'; import { tmpdir } from 'node:os'; -import { shouldRemoveOwnerDir } from '../../features/ensemble/remove.js'; +import { shouldRemoveOwnerDir } from '../../features/repertoire/remove.js'; // --------------------------------------------------------------------------- // shouldRemoveOwnerDir diff --git a/src/__tests__/ensemble/remove.test.ts b/src/__tests__/repertoire/remove.test.ts similarity index 82% rename from src/__tests__/ensemble/remove.test.ts rename to src/__tests__/repertoire/remove.test.ts index e100eb9..0690672 100644 --- a/src/__tests__/ensemble/remove.test.ts +++ b/src/__tests__/repertoire/remove.test.ts @@ -1,5 +1,5 @@ /** - * Regression test for ensembleRemoveCommand scan configuration. + * Regression test for repertoireRemoveCommand scan configuration. * * Verifies that findScopeReferences is called with exactly the 3 spec-defined * scan locations: @@ -20,14 +20,14 @@ vi.mock('node:fs', () => ({ rmSync: vi.fn(), })); -vi.mock('../../features/ensemble/remove.js', () => ({ +vi.mock('../../features/repertoire/remove.js', () => ({ findScopeReferences: vi.fn().mockReturnValue([]), shouldRemoveOwnerDir: vi.fn().mockReturnValue(false), })); vi.mock('../../infra/config/paths.js', () => ({ - getEnsembleDir: vi.fn().mockReturnValue('/home/user/.takt/ensemble'), - getEnsemblePackageDir: vi.fn().mockReturnValue('/home/user/.takt/ensemble/@owner/repo'), + getRepertoireDir: vi.fn().mockReturnValue('/home/user/.takt/repertoire'), + getRepertoirePackageDir: vi.fn().mockReturnValue('/home/user/.takt/repertoire/@owner/repo'), getGlobalConfigDir: vi.fn().mockReturnValue('/home/user/.takt'), getGlobalPiecesDir: vi.fn().mockReturnValue('/home/user/.takt/pieces'), getProjectPiecesDir: vi.fn().mockReturnValue('/project/.takt/pieces'), @@ -46,21 +46,21 @@ vi.mock('../../shared/ui/index.js', () => ({ // Import after mocks are declared // --------------------------------------------------------------------------- -import { ensembleRemoveCommand } from '../../commands/ensemble/remove.js'; -import { findScopeReferences } from '../../features/ensemble/remove.js'; +import { repertoireRemoveCommand } from '../../commands/repertoire/remove.js'; +import { findScopeReferences } from '../../features/repertoire/remove.js'; // --------------------------------------------------------------------------- // Tests // --------------------------------------------------------------------------- -describe('ensembleRemoveCommand — scan configuration', () => { +describe('repertoireRemoveCommand — scan configuration', () => { beforeEach(() => { vi.mocked(findScopeReferences).mockReturnValue([]); }); it('should call findScopeReferences with exactly 2 piecesDirs and 1 categoriesFile', async () => { // When: remove command is invoked (confirm returns false → no deletion) - await ensembleRemoveCommand('@owner/repo'); + await repertoireRemoveCommand('@owner/repo'); // Then: findScopeReferences is called once expect(findScopeReferences).toHaveBeenCalledOnce(); @@ -76,7 +76,7 @@ describe('ensembleRemoveCommand — scan configuration', () => { it('should include global pieces dir in scan', async () => { // When: remove command is invoked - await ensembleRemoveCommand('@owner/repo'); + await repertoireRemoveCommand('@owner/repo'); const [, scanConfig] = vi.mocked(findScopeReferences).mock.calls[0]!; @@ -86,7 +86,7 @@ describe('ensembleRemoveCommand — scan configuration', () => { it('should include project pieces dir in scan', async () => { // When: remove command is invoked - await ensembleRemoveCommand('@owner/repo'); + await repertoireRemoveCommand('@owner/repo'); const [, scanConfig] = vi.mocked(findScopeReferences).mock.calls[0]!; @@ -96,7 +96,7 @@ describe('ensembleRemoveCommand — scan configuration', () => { it('should include preferences/piece-categories.yaml in categoriesFiles', async () => { // When: remove command is invoked - await ensembleRemoveCommand('@owner/repo'); + await repertoireRemoveCommand('@owner/repo'); const [, scanConfig] = vi.mocked(findScopeReferences).mock.calls[0]!; @@ -108,7 +108,7 @@ describe('ensembleRemoveCommand — scan configuration', () => { it('should pass the scope as the first argument to findScopeReferences', async () => { // When: remove command is invoked with a scope - await ensembleRemoveCommand('@owner/repo'); + await repertoireRemoveCommand('@owner/repo'); const [scope] = vi.mocked(findScopeReferences).mock.calls[0]!; diff --git a/src/__tests__/ensemble/ensemble-paths.test.ts b/src/__tests__/repertoire/repertoire-paths.test.ts similarity index 78% rename from src/__tests__/ensemble/ensemble-paths.test.ts rename to src/__tests__/repertoire/repertoire-paths.test.ts index 29af314..cd86caf 100644 --- a/src/__tests__/ensemble/ensemble-paths.test.ts +++ b/src/__tests__/repertoire/repertoire-paths.test.ts @@ -2,7 +2,7 @@ * Tests for facet directory path helpers in paths.ts — items 42–45. * * Verifies the `facets/` segment is present in all facet path results, - * and that getEnsembleFacetDir constructs the correct full ensemble path. + * and that getRepertoireFacetDir constructs the correct full repertoire path. */ import { describe, it, expect } from 'vitest'; @@ -10,8 +10,8 @@ import { getProjectFacetDir, getGlobalFacetDir, getBuiltinFacetDir, - getEnsembleFacetDir, - getEnsemblePackageDir, + getRepertoireFacetDir, + getRepertoirePackageDir, type FacetType, } from '../../infra/config/paths.js'; @@ -130,38 +130,38 @@ describe('getBuiltinFacetDir — facets/ prefix', () => { }); // --------------------------------------------------------------------------- -// getEnsembleFacetDir — item 45 (new function) +// getRepertoireFacetDir — item 45 (new function) // --------------------------------------------------------------------------- -describe('getEnsembleFacetDir — new path function', () => { - it('should return path containing ensemble/@{owner}/{repo}/facets/{type}', () => { +describe('getRepertoireFacetDir — new path function', () => { + it('should return path containing repertoire/@{owner}/{repo}/facets/{type}', () => { // Given: owner, repo, and facet type // When: path is built - const dir = getEnsembleFacetDir('nrslib', 'takt-fullstack', 'personas'); + const dir = getRepertoireFacetDir('nrslib', 'takt-fullstack', 'personas'); // Then: all segments are present const normalized = dir.replace(/\\/g, '/'); - expect(normalized).toContain('ensemble'); + expect(normalized).toContain('repertoire'); expect(normalized).toContain('@nrslib'); expect(normalized).toContain('takt-fullstack'); expect(normalized).toContain('facets'); expect(normalized).toContain('personas'); }); - it('should construct path as ~/.takt/ensemble/@{owner}/{repo}/facets/{type}', () => { + it('should construct path as ~/.takt/repertoire/@{owner}/{repo}/facets/{type}', () => { // Given: owner, repo, and facet type // When: path is built - const dir = getEnsembleFacetDir('nrslib', 'takt-fullstack', 'personas'); + const dir = getRepertoireFacetDir('nrslib', 'takt-fullstack', 'personas'); - // Then: full segment order is ensemble → @nrslib → takt-fullstack → facets → personas + // Then: full segment order is repertoire → @nrslib → takt-fullstack → facets → personas const normalized = dir.replace(/\\/g, '/'); - expect(normalized).toMatch(/ensemble\/@nrslib\/takt-fullstack\/facets\/personas/); + expect(normalized).toMatch(/repertoire\/@nrslib\/takt-fullstack\/facets\/personas/); }); it('should prepend @ before owner name in the path', () => { // Given: owner without @ prefix // When: path is built - const dir = getEnsembleFacetDir('myowner', 'myrepo', 'policies'); + const dir = getRepertoireFacetDir('myowner', 'myrepo', 'policies'); // Then: @ is included before owner in the path const normalized = dir.replace(/\\/g, '/'); @@ -172,46 +172,46 @@ describe('getEnsembleFacetDir — new path function', () => { // Given: all valid facet types for (const t of ALL_FACET_TYPES) { // When: path is built - const dir = getEnsembleFacetDir('owner', 'repo', t); + const dir = getRepertoireFacetDir('owner', 'repo', t); - // Then: path has correct ensemble structure with facet type + // Then: path has correct repertoire structure with facet type const normalized = dir.replace(/\\/g, '/'); - expect(normalized).toMatch(new RegExp(`ensemble/@owner/repo/facets/${t}`)); + expect(normalized).toMatch(new RegExp(`repertoire/@owner/repo/facets/${t}`)); } }); }); // --------------------------------------------------------------------------- -// getEnsemblePackageDir — item 46 +// getRepertoirePackageDir — item 46 // --------------------------------------------------------------------------- -describe('getEnsemblePackageDir', () => { - it('should return path containing ensemble/@{owner}/{repo}', () => { +describe('getRepertoirePackageDir', () => { + it('should return path containing repertoire/@{owner}/{repo}', () => { // Given: owner and repo // When: path is built - const dir = getEnsemblePackageDir('nrslib', 'takt-fullstack'); + const dir = getRepertoirePackageDir('nrslib', 'takt-fullstack'); // Then: all segments are present const normalized = dir.replace(/\\/g, '/'); - expect(normalized).toContain('ensemble'); + expect(normalized).toContain('repertoire'); expect(normalized).toContain('@nrslib'); expect(normalized).toContain('takt-fullstack'); }); - it('should construct path as ~/.takt/ensemble/@{owner}/{repo}', () => { + it('should construct path as ~/.takt/repertoire/@{owner}/{repo}', () => { // Given: owner and repo // When: path is built - const dir = getEnsemblePackageDir('nrslib', 'takt-fullstack'); + const dir = getRepertoirePackageDir('nrslib', 'takt-fullstack'); - // Then: full segment order is ensemble → @nrslib → takt-fullstack + // Then: full segment order is repertoire → @nrslib → takt-fullstack const normalized = dir.replace(/\\/g, '/'); - expect(normalized).toMatch(/ensemble\/@nrslib\/takt-fullstack$/); + expect(normalized).toMatch(/repertoire\/@nrslib\/takt-fullstack$/); }); it('should prepend @ before owner name in the path', () => { // Given: owner without @ prefix // When: path is built - const dir = getEnsemblePackageDir('myowner', 'myrepo'); + const dir = getRepertoirePackageDir('myowner', 'myrepo'); // Then: @ is included before owner in the path const normalized = dir.replace(/\\/g, '/'); diff --git a/src/__tests__/ensemble/takt-pack-config.test.ts b/src/__tests__/repertoire/takt-repertoire-config.test.ts similarity index 78% rename from src/__tests__/ensemble/takt-pack-config.test.ts rename to src/__tests__/repertoire/takt-repertoire-config.test.ts index 4968f08..30f5186 100644 --- a/src/__tests__/ensemble/takt-pack-config.test.ts +++ b/src/__tests__/repertoire/takt-repertoire-config.test.ts @@ -1,5 +1,5 @@ /** - * Tests for takt-package.yaml parsing and validation. + * Tests for takt-repertoire.yaml parsing and validation. * * Covers: * - Full field parsing (description, path, takt.min_version) @@ -14,23 +14,23 @@ import { mkdtempSync, mkdirSync, rmSync, symlinkSync, writeFileSync } from 'node import { join } from 'node:path'; import { tmpdir } from 'node:os'; import { - parseTaktPackConfig, - validateTaktPackPath, + parseTaktRepertoireConfig, + validateTaktRepertoirePath, validateMinVersion, isVersionCompatible, checkPackageHasContent, checkPackageHasContentWithContext, validateRealpathInsideRoot, - resolvePackConfigPath, -} from '../../features/ensemble/takt-pack-config.js'; + resolveRepertoireConfigPath, +} from '../../features/repertoire/takt-repertoire-config.js'; // --------------------------------------------------------------------------- -// parseTaktPackConfig +// parseTaktRepertoireConfig // --------------------------------------------------------------------------- -describe('parseTaktPackConfig', () => { +describe('parseTaktRepertoireConfig', () => { it('should parse all fields when present', () => { - // Given: a complete takt-package.yaml content + // Given: a complete takt-repertoire.yaml content const yaml = ` description: My package path: takt @@ -39,7 +39,7 @@ takt: `.trim(); // When: parsed - const config = parseTaktPackConfig(yaml); + const config = parseTaktRepertoireConfig(yaml); // Then: all fields are populated expect(config.description).toBe('My package'); @@ -48,11 +48,11 @@ takt: }); it('should default path to "." when omitted', () => { - // Given: takt-package.yaml with no path field + // Given: takt-repertoire.yaml with no path field const yaml = `description: No path field`; // When: parsed - const config = parseTaktPackConfig(yaml); + const config = parseTaktRepertoireConfig(yaml); // Then: path defaults to "." expect(config.path).toBe('.'); @@ -63,7 +63,7 @@ takt: const yaml = ''; // When: parsed - const config = parseTaktPackConfig(yaml); + const config = parseTaktRepertoireConfig(yaml); // Then: defaults are applied expect(config.path).toBe('.'); @@ -76,7 +76,7 @@ takt: const yaml = 'description: セキュリティレビュー用ファセット集'; // When: parsed - const config = parseTaktPackConfig(yaml); + const config = parseTaktRepertoireConfig(yaml); // Then: description is set, path defaults to "." expect(config.description).toBe('セキュリティレビュー用ファセット集'); @@ -88,7 +88,7 @@ takt: const yaml = 'path: pkg/takt'; // When: parsed - const config = parseTaktPackConfig(yaml); + const config = parseTaktRepertoireConfig(yaml); // Then: path is preserved as-is expect(config.path).toBe('pkg/takt'); @@ -96,49 +96,49 @@ takt: }); // --------------------------------------------------------------------------- -// validateTaktPackPath +// validateTaktRepertoirePath // --------------------------------------------------------------------------- -describe('validateTaktPackPath', () => { +describe('validateTaktRepertoirePath', () => { it('should accept "." (current directory)', () => { // Given: default path // When: validated // Then: no error thrown - expect(() => validateTaktPackPath('.')).not.toThrow(); + expect(() => validateTaktRepertoirePath('.')).not.toThrow(); }); it('should accept simple relative path "takt"', () => { - expect(() => validateTaktPackPath('takt')).not.toThrow(); + expect(() => validateTaktRepertoirePath('takt')).not.toThrow(); }); it('should accept nested relative path "pkg/takt"', () => { - expect(() => validateTaktPackPath('pkg/takt')).not.toThrow(); + expect(() => validateTaktRepertoirePath('pkg/takt')).not.toThrow(); }); it('should reject absolute path starting with "/"', () => { // Given: absolute path // When: validated // Then: throws an error - expect(() => validateTaktPackPath('/etc/passwd')).toThrow(); + expect(() => validateTaktRepertoirePath('/etc/passwd')).toThrow(); }); it('should reject path starting with "~"', () => { // Given: home-relative path - expect(() => validateTaktPackPath('~/takt')).toThrow(); + expect(() => validateTaktRepertoirePath('~/takt')).toThrow(); }); it('should reject path containing ".." segment', () => { // Given: path with directory traversal - expect(() => validateTaktPackPath('../outside')).toThrow(); + expect(() => validateTaktRepertoirePath('../outside')).toThrow(); }); it('should reject path with ".." in middle segment', () => { // Given: path with ".." embedded - expect(() => validateTaktPackPath('takt/../etc')).toThrow(); + expect(() => validateTaktRepertoirePath('takt/../etc')).toThrow(); }); it('should reject "../../etc" (multiple traversal)', () => { - expect(() => validateTaktPackPath('../../etc')).toThrow(); + expect(() => validateTaktRepertoirePath('../../etc')).toThrow(); }); }); @@ -234,7 +234,7 @@ describe('checkPackageHasContent', () => { let tempDir: string; beforeEach(() => { - tempDir = mkdtempSync(join(tmpdir(), 'takt-pack-content-')); + tempDir = mkdtempSync(join(tmpdir(), 'takt-repertoire-content-')); }); afterEach(() => { @@ -249,7 +249,7 @@ describe('checkPackageHasContent', () => { }); it('should include manifest/path/hint details in contextual error', () => { - const manifestPath = join(tempDir, '.takt', 'takt-package.yaml'); + const manifestPath = join(tempDir, '.takt', 'takt-repertoire.yaml'); expect(() => checkPackageHasContentWithContext(tempDir, { manifestPath, configuredPath: '.', @@ -344,10 +344,10 @@ describe('validateRealpathInsideRoot', () => { }); // --------------------------------------------------------------------------- -// resolvePackConfigPath (takt-package.yaml search order) +// resolveRepertoireConfigPath (takt-repertoire.yaml search order) // --------------------------------------------------------------------------- -describe('resolvePackConfigPath', () => { +describe('resolveRepertoireConfigPath', () => { let extractDir: string; beforeEach(() => { @@ -358,47 +358,47 @@ describe('resolvePackConfigPath', () => { rmSync(extractDir, { recursive: true, force: true }); }); - it('should return .takt/takt-package.yaml when only that path exists', () => { - // Given: only .takt/takt-package.yaml exists + it('should return .takt/takt-repertoire.yaml when only that path exists', () => { + // Given: only .takt/takt-repertoire.yaml exists const taktDir = join(extractDir, '.takt'); mkdirSync(taktDir, { recursive: true }); - writeFileSync(join(taktDir, 'takt-package.yaml'), 'description: dot-takt'); + writeFileSync(join(taktDir, 'takt-repertoire.yaml'), 'description: dot-takt'); // When: resolved - const result = resolvePackConfigPath(extractDir); + const result = resolveRepertoireConfigPath(extractDir); - // Then: .takt/takt-package.yaml is returned - expect(result).toBe(join(extractDir, '.takt', 'takt-package.yaml')); + // Then: .takt/takt-repertoire.yaml is returned + expect(result).toBe(join(extractDir, '.takt', 'takt-repertoire.yaml')); }); - it('should return root takt-package.yaml when only that path exists', () => { - // Given: only root takt-package.yaml exists - writeFileSync(join(extractDir, 'takt-package.yaml'), 'description: root'); + it('should return root takt-repertoire.yaml when only that path exists', () => { + // Given: only root takt-repertoire.yaml exists + writeFileSync(join(extractDir, 'takt-repertoire.yaml'), 'description: root'); // When: resolved - const result = resolvePackConfigPath(extractDir); + const result = resolveRepertoireConfigPath(extractDir); - // Then: root takt-package.yaml is returned - expect(result).toBe(join(extractDir, 'takt-package.yaml')); + // Then: root takt-repertoire.yaml is returned + expect(result).toBe(join(extractDir, 'takt-repertoire.yaml')); }); - it('should prefer .takt/takt-package.yaml when both paths exist', () => { - // Given: both .takt/takt-package.yaml and root takt-package.yaml exist + it('should prefer .takt/takt-repertoire.yaml when both paths exist', () => { + // Given: both .takt/takt-repertoire.yaml and root takt-repertoire.yaml exist const taktDir = join(extractDir, '.takt'); mkdirSync(taktDir, { recursive: true }); - writeFileSync(join(taktDir, 'takt-package.yaml'), 'description: dot-takt'); - writeFileSync(join(extractDir, 'takt-package.yaml'), 'description: root'); + writeFileSync(join(taktDir, 'takt-repertoire.yaml'), 'description: dot-takt'); + writeFileSync(join(extractDir, 'takt-repertoire.yaml'), 'description: root'); // When: resolved - const result = resolvePackConfigPath(extractDir); + const result = resolveRepertoireConfigPath(extractDir); - // Then: .takt/takt-package.yaml takes precedence - expect(result).toBe(join(extractDir, '.takt', 'takt-package.yaml')); + // Then: .takt/takt-repertoire.yaml takes precedence + expect(result).toBe(join(extractDir, '.takt', 'takt-repertoire.yaml')); }); it('should throw when neither path exists', () => { // Given: empty extract directory // When / Then: throws an error - expect(() => resolvePackConfigPath(extractDir)).toThrow('takt-package.yaml not found in'); + expect(() => resolveRepertoireConfigPath(extractDir)).toThrow('takt-repertoire.yaml not found in'); }); }); diff --git a/src/__tests__/ensemble/tar-parser.test.ts b/src/__tests__/repertoire/tar-parser.test.ts similarity index 98% rename from src/__tests__/ensemble/tar-parser.test.ts rename to src/__tests__/repertoire/tar-parser.test.ts index 4e8697c..017b322 100644 --- a/src/__tests__/ensemble/tar-parser.test.ts +++ b/src/__tests__/repertoire/tar-parser.test.ts @@ -11,7 +11,7 @@ */ import { describe, it, expect } from 'vitest'; -import { parseTarVerboseListing } from '../../features/ensemble/tar-parser.js'; +import { parseTarVerboseListing } from '../../features/repertoire/tar-parser.js'; // --------------------------------------------------------------------------- // Helpers to build realistic tar verbose lines diff --git a/src/__tests__/selectAndExecute-autoPr.test.ts b/src/__tests__/selectAndExecute-autoPr.test.ts index f66243b..bae7003 100644 --- a/src/__tests__/selectAndExecute-autoPr.test.ts +++ b/src/__tests__/selectAndExecute-autoPr.test.ts @@ -183,12 +183,12 @@ describe('resolveAutoPr default in selectAndExecuteTask', () => { expect(mockSelectPiece).toHaveBeenCalledWith('/project'); }); - it('should accept ensemble scoped piece override when it exists', async () => { - mockLoadPieceByIdentifier.mockReturnValueOnce({ name: '@nrslib/takt-packages/critical-thinking' } as never); + it('should accept repertoire scoped piece override when it exists', async () => { + mockLoadPieceByIdentifier.mockReturnValueOnce({ name: '@nrslib/takt-ensembles/critical-thinking' } as never); - const selected = await determinePiece('/project', '@nrslib/takt-packages/critical-thinking'); + const selected = await determinePiece('/project', '@nrslib/takt-ensembles/critical-thinking'); - expect(selected).toBe('@nrslib/takt-packages/critical-thinking'); + expect(selected).toBe('@nrslib/takt-ensembles/critical-thinking'); }); it('should fail task record when executeTask throws', async () => { diff --git a/src/__tests__/takt-pack-schema.test.ts b/src/__tests__/takt-repertoire-schema.test.ts similarity index 67% rename from src/__tests__/takt-pack-schema.test.ts rename to src/__tests__/takt-repertoire-schema.test.ts index 08272c1..eb6886c 100644 --- a/src/__tests__/takt-pack-schema.test.ts +++ b/src/__tests__/takt-repertoire-schema.test.ts @@ -1,7 +1,7 @@ /** - * Unit tests for takt-package.yaml schema validation. + * Unit tests for takt-repertoire.yaml schema validation. * - * Target: src/features/ensemble/takt-pack-config.ts + * Target: src/features/repertoire/takt-repertoire-config.ts * * Schema rules under test: * - description: optional @@ -13,46 +13,46 @@ import { describe, it, expect } from 'vitest'; import { - parseTaktPackConfig, - validateTaktPackPath, + parseTaktRepertoireConfig, + validateTaktRepertoirePath, validateMinVersion, -} from '../features/ensemble/takt-pack-config.js'; +} from '../features/repertoire/takt-repertoire-config.js'; -describe('takt-package.yaml schema: description field', () => { +describe('takt-repertoire.yaml schema: description field', () => { it('should accept schema without description field', () => { - const config = parseTaktPackConfig(''); + const config = parseTaktRepertoireConfig(''); expect(config.description).toBeUndefined(); }); }); -describe('takt-package.yaml schema: path field', () => { +describe('takt-repertoire.yaml schema: path field', () => { it('should default path to "." when not specified', () => { - const config = parseTaktPackConfig(''); + const config = parseTaktRepertoireConfig(''); expect(config.path).toBe('.'); }); it('should reject path starting with "/" (absolute path)', () => { - expect(() => validateTaktPackPath('/foo')).toThrow(); + expect(() => validateTaktRepertoirePath('/foo')).toThrow(); }); it('should reject path starting with "~" (tilde-absolute path)', () => { - expect(() => validateTaktPackPath('~/foo')).toThrow(); + expect(() => validateTaktRepertoirePath('~/foo')).toThrow(); }); it('should reject path with ".." segment traversing outside repository', () => { - expect(() => validateTaktPackPath('../outside')).toThrow(); + expect(() => validateTaktRepertoirePath('../outside')).toThrow(); }); it('should reject path with embedded ".." segments leading outside repository', () => { - expect(() => validateTaktPackPath('sub/../../../outside')).toThrow(); + expect(() => validateTaktRepertoirePath('sub/../../../outside')).toThrow(); }); it('should accept valid relative path "sub/dir"', () => { - expect(() => validateTaktPackPath('sub/dir')).not.toThrow(); + expect(() => validateTaktRepertoirePath('sub/dir')).not.toThrow(); }); }); -describe('takt-package.yaml schema: takt.min_version field', () => { +describe('takt-repertoire.yaml schema: takt.min_version field', () => { it('should accept min_version "0.5.0" (valid semver)', () => { expect(() => validateMinVersion('0.5.0')).not.toThrow(); }); diff --git a/src/app/cli/commands.ts b/src/app/cli/commands.ts index 0af8a18..187b39f 100644 --- a/src/app/cli/commands.ts +++ b/src/app/cli/commands.ts @@ -15,9 +15,9 @@ import { showCatalog } from '../../features/catalog/index.js'; import { computeReviewMetrics, formatReviewMetrics, parseSinceDuration, purgeOldEvents } from '../../features/analytics/index.js'; import { program, resolvedCwd } from './program.js'; import { resolveAgentOverrides } from './helpers.js'; -import { ensembleAddCommand } from '../../commands/ensemble/add.js'; -import { ensembleRemoveCommand } from '../../commands/ensemble/remove.js'; -import { ensembleListCommand } from '../../commands/ensemble/list.js'; +import { repertoireAddCommand } from '../../commands/repertoire/add.js'; +import { repertoireRemoveCommand } from '../../commands/repertoire/remove.js'; +import { repertoireListCommand } from '../../commands/repertoire/list.js'; program .command('run') @@ -177,29 +177,29 @@ program } }); -const ensemble = program - .command('ensemble') - .description('Manage ensemble packages'); +const repertoire = program + .command('repertoire') + .description('Manage repertoire packages'); -ensemble +repertoire .command('add') - .description('Install an ensemble package from GitHub') + .description('Install a repertoire package from GitHub') .argument('', 'Package spec (e.g. github:{owner}/{repo}@{ref})') .action(async (spec: string) => { - await ensembleAddCommand(spec); + await repertoireAddCommand(spec); }); -ensemble +repertoire .command('remove') - .description('Remove an installed ensemble package') + .description('Remove an installed repertoire package') .argument('', 'Package scope (e.g. @{owner}/{repo})') .action(async (scope: string) => { - await ensembleRemoveCommand(scope); + await repertoireRemoveCommand(scope); }); -ensemble +repertoire .command('list') - .description('List installed ensemble packages') + .description('List installed repertoire packages') .action(async () => { - await ensembleListCommand(); + await repertoireListCommand(); }); diff --git a/src/commands/ensemble/add.ts b/src/commands/repertoire/add.ts similarity index 79% rename from src/commands/ensemble/add.ts rename to src/commands/repertoire/add.ts index 8785ee8..29bdf65 100644 --- a/src/commands/ensemble/add.ts +++ b/src/commands/repertoire/add.ts @@ -1,9 +1,9 @@ /** - * takt ensemble add — install an ensemble package from GitHub. + * takt repertoire add — install a repertoire package from GitHub. * * Usage: - * takt ensemble add github:{owner}/{repo}@{ref} - * takt ensemble add github:{owner}/{repo} (uses default branch) + * takt repertoire add github:{owner}/{repo}@{ref} + * takt repertoire add github:{owner}/{repo} (uses default branch) */ import { mkdirSync, copyFileSync, existsSync, readFileSync, writeFileSync, rmSync } from 'node:fs'; @@ -12,24 +12,24 @@ import { tmpdir } from 'node:os'; import { execFileSync } from 'node:child_process'; import { createRequire } from 'node:module'; import { stringify as stringifyYaml } from 'yaml'; -import { getEnsemblePackageDir } from '../../infra/config/paths.js'; -import { parseGithubSpec } from '../../features/ensemble/github-spec.js'; +import { getRepertoirePackageDir } from '../../infra/config/paths.js'; +import { parseGithubSpec } from '../../features/repertoire/github-spec.js'; import { - parseTaktPackConfig, - validateTaktPackPath, + parseTaktRepertoireConfig, + validateTaktRepertoirePath, validateMinVersion, isVersionCompatible, checkPackageHasContentWithContext, validateRealpathInsideRoot, - resolvePackConfigPath, -} from '../../features/ensemble/takt-pack-config.js'; -import { collectCopyTargets } from '../../features/ensemble/file-filter.js'; -import { parseTarVerboseListing } from '../../features/ensemble/tar-parser.js'; -import { resolveRef } from '../../features/ensemble/github-ref-resolver.js'; -import { atomicReplace, cleanupResiduals } from '../../features/ensemble/atomic-update.js'; -import { generateLockFile, extractCommitSha } from '../../features/ensemble/lock-file.js'; -import { TAKT_PACKAGE_MANIFEST_FILENAME } from '../../features/ensemble/constants.js'; -import { summarizeFacetsByType, detectEditPieces, formatEditPieceWarnings } from '../../features/ensemble/pack-summary.js'; + resolveRepertoireConfigPath, +} from '../../features/repertoire/takt-repertoire-config.js'; +import { collectCopyTargets } from '../../features/repertoire/file-filter.js'; +import { parseTarVerboseListing } from '../../features/repertoire/tar-parser.js'; +import { resolveRef } from '../../features/repertoire/github-ref-resolver.js'; +import { atomicReplace, cleanupResiduals } from '../../features/repertoire/atomic-update.js'; +import { generateLockFile, extractCommitSha } from '../../features/repertoire/lock-file.js'; +import { TAKT_REPERTOIRE_MANIFEST_FILENAME, TAKT_REPERTOIRE_LOCK_FILENAME } from '../../features/repertoire/constants.js'; +import { summarizeFacetsByType, detectEditPieces, formatEditPieceWarnings } from '../../features/repertoire/pack-summary.js'; import { confirm } from '../../shared/prompt/index.js'; import { info, success } from '../../shared/ui/index.js'; import { createLogger, getErrorMessage } from '../../shared/utils/index.js'; @@ -37,9 +37,9 @@ import { createLogger, getErrorMessage } from '../../shared/utils/index.js'; const require = createRequire(import.meta.url); const { version: TAKT_VERSION } = require('../../../package.json') as { version: string }; -const log = createLogger('ensemble-add'); +const log = createLogger('repertoire-add'); -export async function ensembleAddCommand(spec: string): Promise { +export async function repertoireAddCommand(spec: string): Promise { const { owner, repo, ref: specRef } = parseGithubSpec(spec); try { @@ -93,11 +93,11 @@ export async function ensembleAddCommand(spec: string): Promise { ); } - const packConfigPath = resolvePackConfigPath(tmpExtractDir); + const packConfigPath = resolveRepertoireConfigPath(tmpExtractDir); const packConfigYaml = readFileSync(packConfigPath, 'utf-8'); - const config = parseTaktPackConfig(packConfigYaml); - validateTaktPackPath(config.path); + const config = parseTaktRepertoireConfig(packConfigYaml); + validateTaktRepertoirePath(config.path); if (config.takt?.min_version) { validateMinVersion(config.takt.min_version); @@ -157,7 +157,7 @@ export async function ensembleAddCommand(spec: string): Promise { return; } - const packageDir = getEnsemblePackageDir(owner, repo); + const packageDir = getRepertoirePackageDir(owner, repo); if (existsSync(packageDir)) { const overwrite = await confirm( @@ -180,7 +180,7 @@ export async function ensembleAddCommand(spec: string): Promise { mkdirSync(dirname(destFile), { recursive: true }); copyFileSync(target.absolutePath, destFile); } - copyFileSync(packConfigPath, join(packageDir, TAKT_PACKAGE_MANIFEST_FILENAME)); + copyFileSync(packConfigPath, join(packageDir, TAKT_REPERTOIRE_MANIFEST_FILENAME)); const lock = generateLockFile({ source: `github:${owner}/${repo}`, @@ -188,7 +188,7 @@ export async function ensembleAddCommand(spec: string): Promise { commitSha, importedAt: new Date(), }); - writeFileSync(join(packageDir, '.takt-pack-lock.yaml'), stringifyYaml(lock)); + writeFileSync(join(packageDir, TAKT_REPERTOIRE_LOCK_FILENAME), stringifyYaml(lock)); }, }); diff --git a/src/commands/ensemble/list.ts b/src/commands/repertoire/list.ts similarity index 56% rename from src/commands/ensemble/list.ts rename to src/commands/repertoire/list.ts index 4585ace..358f0c2 100644 --- a/src/commands/ensemble/list.ts +++ b/src/commands/repertoire/list.ts @@ -1,13 +1,13 @@ /** - * takt ensemble list — list installed ensemble packages. + * takt repertoire list — list installed repertoire packages. */ -import { getEnsembleDir } from '../../infra/config/paths.js'; -import { listPackages } from '../../features/ensemble/list.js'; +import { getRepertoireDir } from '../../infra/config/paths.js'; +import { listPackages } from '../../features/repertoire/list.js'; import { info } from '../../shared/ui/index.js'; -export async function ensembleListCommand(): Promise { - const packages = listPackages(getEnsembleDir()); +export async function repertoireListCommand(): Promise { + const packages = listPackages(getRepertoireDir()); if (packages.length === 0) { info('インストール済みパッケージはありません'); diff --git a/src/commands/ensemble/remove.ts b/src/commands/repertoire/remove.ts similarity index 75% rename from src/commands/ensemble/remove.ts rename to src/commands/repertoire/remove.ts index 2fbf152..23c6bb4 100644 --- a/src/commands/ensemble/remove.ts +++ b/src/commands/repertoire/remove.ts @@ -1,15 +1,15 @@ /** - * takt ensemble remove — remove an installed ensemble package. + * takt repertoire remove — remove an installed repertoire package. */ import { rmSync, existsSync } from 'node:fs'; import { join } from 'node:path'; -import { getEnsembleDir, getEnsemblePackageDir, getGlobalConfigDir, getGlobalPiecesDir, getProjectPiecesDir } from '../../infra/config/paths.js'; -import { findScopeReferences, shouldRemoveOwnerDir } from '../../features/ensemble/remove.js'; +import { getRepertoireDir, getRepertoirePackageDir, getGlobalConfigDir, getGlobalPiecesDir, getProjectPiecesDir } from '../../infra/config/paths.js'; +import { findScopeReferences, shouldRemoveOwnerDir } from '../../features/repertoire/remove.js'; import { confirm } from '../../shared/prompt/index.js'; import { info, success } from '../../shared/ui/index.js'; -export async function ensembleRemoveCommand(scope: string): Promise { +export async function repertoireRemoveCommand(scope: string): Promise { if (!scope.startsWith('@')) { throw new Error(`Invalid scope: "${scope}". Expected @{owner}/{repo}`); } @@ -21,8 +21,8 @@ export async function ensembleRemoveCommand(scope: string): Promise { const owner = withoutAt.slice(0, slashIdx); const repo = withoutAt.slice(slashIdx + 1); - const ensembleDir = getEnsembleDir(); - const packageDir = getEnsemblePackageDir(owner, repo); + const repertoireDir = getRepertoireDir(); + const packageDir = getRepertoirePackageDir(owner, repo); if (!existsSync(packageDir)) { throw new Error(`Package not found: ${scope}`); @@ -47,7 +47,7 @@ export async function ensembleRemoveCommand(scope: string): Promise { rmSync(packageDir, { recursive: true, force: true }); - const ownerDir = join(ensembleDir, `@${owner}`); + const ownerDir = join(repertoireDir, `@${owner}`); if (shouldRemoveOwnerDir(ownerDir, repo)) { rmSync(ownerDir, { recursive: true, force: true }); } diff --git a/src/faceted-prompting/scope.ts b/src/faceted-prompting/scope.ts index 6f856cd..310eae4 100644 --- a/src/faceted-prompting/scope.ts +++ b/src/faceted-prompting/scope.ts @@ -1,10 +1,10 @@ /** - * @scope reference resolution utilities for TAKT ensemble packages. + * @scope reference resolution utilities for TAKT repertoire packages. * * Provides: * - isScopeRef(): detect @{owner}/{repo}/{facet-name} format * - parseScopeRef(): parse and normalize components - * - resolveScopeRef(): build file path in ensemble directory + * - resolveScopeRef(): build file path in repertoire directory * - validateScopeOwner/Repo/FacetName(): name constraint validation */ @@ -51,22 +51,22 @@ export function parseScopeRef(ref: string): ScopeRef { } /** - * Resolve a scope reference to a file path in the ensemble directory. + * Resolve a scope reference to a file path in the repertoire directory. * - * Path: {ensembleDir}/@{owner}/{repo}/facets/{facetType}/{name}.md + * Path: {repertoireDir}/@{owner}/{repo}/facets/{facetType}/{name}.md * - * @param scopeRef - parsed scope reference - * @param facetType - e.g. "personas", "policies", "knowledge" - * @param ensembleDir - root ensemble directory (e.g. ~/.takt/ensemble) + * @param scopeRef - parsed scope reference + * @param facetType - e.g. "personas", "policies", "knowledge" + * @param repertoireDir - root repertoire directory (e.g. ~/.takt/repertoire) * @returns Absolute path to the facet file. */ export function resolveScopeRef( scopeRef: ScopeRef, facetType: string, - ensembleDir: string, + repertoireDir: string, ): string { return join( - ensembleDir, + repertoireDir, `@${scopeRef.owner}`, scopeRef.repo, 'facets', diff --git a/src/features/ensemble/constants.ts b/src/features/ensemble/constants.ts deleted file mode 100644 index 74ca440..0000000 --- a/src/features/ensemble/constants.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Shared constants for ensemble package manifest handling. - */ - -/** Manifest filename inside a package repository and installed package directory. */ -export const TAKT_PACKAGE_MANIFEST_FILENAME = 'takt-package.yaml'; diff --git a/src/features/ensemble/atomic-update.ts b/src/features/repertoire/atomic-update.ts similarity index 100% rename from src/features/ensemble/atomic-update.ts rename to src/features/repertoire/atomic-update.ts diff --git a/src/features/repertoire/constants.ts b/src/features/repertoire/constants.ts new file mode 100644 index 0000000..e472025 --- /dev/null +++ b/src/features/repertoire/constants.ts @@ -0,0 +1,12 @@ +/** + * Shared constants for repertoire package manifest handling. + */ + +/** Directory name for the repertoire packages dir (~/.takt/repertoire). */ +export const REPERTOIRE_DIR_NAME = 'repertoire'; + +/** Manifest filename inside a package repository and installed package directory. */ +export const TAKT_REPERTOIRE_MANIFEST_FILENAME = 'takt-repertoire.yaml'; + +/** Lock file filename inside an installed package directory. */ +export const TAKT_REPERTOIRE_LOCK_FILENAME = '.takt-repertoire-lock.yaml'; diff --git a/src/features/ensemble/file-filter.ts b/src/features/repertoire/file-filter.ts similarity index 94% rename from src/features/ensemble/file-filter.ts rename to src/features/repertoire/file-filter.ts index d921b56..919cfbe 100644 --- a/src/features/ensemble/file-filter.ts +++ b/src/features/repertoire/file-filter.ts @@ -1,5 +1,5 @@ /** - * File filtering for ensemble package copy operations. + * File filtering for repertoire package copy operations. * * Security constraints: * - Only .md, .yaml, .yml files are copied @@ -13,9 +13,9 @@ import { lstatSync, readdirSync, type Stats } from 'node:fs'; import { join, extname, relative } from 'node:path'; import { createLogger } from '../../shared/utils/debug.js'; -const log = createLogger('ensemble-file-filter'); +const log = createLogger('repertoire-file-filter'); -/** Allowed file extensions for ensemble package files. */ +/** Allowed file extensions for repertoire package files. */ export const ALLOWED_EXTENSIONS = ['.md', '.yaml', '.yml'] as const; /** Top-level directories that are copied from a package. */ @@ -107,7 +107,7 @@ function collectFromDir( * Symbolic links are skipped. Files over MAX_FILE_SIZE are skipped. * Throws if total file count exceeds MAX_FILE_COUNT. * - * @param packageRoot - absolute path to the package root (respects takt-package.yaml path) + * @param packageRoot - absolute path to the package root (respects takt-repertoire.yaml path) */ export function collectCopyTargets(packageRoot: string): CopyTarget[] { const targets: CopyTarget[] = []; diff --git a/src/features/ensemble/github-ref-resolver.ts b/src/features/repertoire/github-ref-resolver.ts similarity index 95% rename from src/features/ensemble/github-ref-resolver.ts rename to src/features/repertoire/github-ref-resolver.ts index 1107257..37f02dd 100644 --- a/src/features/ensemble/github-ref-resolver.ts +++ b/src/features/repertoire/github-ref-resolver.ts @@ -1,5 +1,5 @@ /** - * GitHub ref resolver for ensemble add command. + * GitHub ref resolver for repertoire add command. * * Resolves the ref for a GitHub package installation. * When the spec omits @{ref}, queries the GitHub API for the default branch. diff --git a/src/features/ensemble/github-spec.ts b/src/features/repertoire/github-spec.ts similarity index 96% rename from src/features/ensemble/github-spec.ts rename to src/features/repertoire/github-spec.ts index f97a2a3..6637b7a 100644 --- a/src/features/ensemble/github-spec.ts +++ b/src/features/repertoire/github-spec.ts @@ -1,5 +1,5 @@ /** - * GitHub package spec parser for ensemble add command. + * GitHub package spec parser for repertoire add command. * * Parses "github:{owner}/{repo}@{ref}" format into structured components. * The @{ref} part is optional; when omitted, ref is undefined and the caller diff --git a/src/features/ensemble/list.ts b/src/features/repertoire/list.ts similarity index 65% rename from src/features/ensemble/list.ts rename to src/features/repertoire/list.ts index bacbb6d..6fd3b50 100644 --- a/src/features/ensemble/list.ts +++ b/src/features/repertoire/list.ts @@ -1,18 +1,18 @@ /** - * Ensemble package listing. + * Repertoire package listing. * - * Scans the ensemble directory for installed packages and reads their + * Scans the repertoire directory for installed packages and reads their * metadata (description, ref, truncated commit SHA) for display. */ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'; import { join } from 'node:path'; -import { parseTaktPackConfig } from './takt-pack-config.js'; +import { parseTaktRepertoireConfig } from './takt-repertoire-config.js'; import { parseLockFile } from './lock-file.js'; -import { TAKT_PACKAGE_MANIFEST_FILENAME } from './constants.js'; +import { TAKT_REPERTOIRE_MANIFEST_FILENAME, TAKT_REPERTOIRE_LOCK_FILENAME } from './constants.js'; import { createLogger, getErrorMessage } from '../../shared/utils/index.js'; -const log = createLogger('ensemble-list'); +const log = createLogger('repertoire-list'); export interface PackageInfo { /** e.g. "@nrslib/takt-fullstack" */ @@ -30,13 +30,13 @@ export interface PackageInfo { * @param scope - e.g. "@nrslib/takt-fullstack" */ export function readPackageInfo(packageDir: string, scope: string): PackageInfo { - const packConfigPath = join(packageDir, TAKT_PACKAGE_MANIFEST_FILENAME); - const lockPath = join(packageDir, '.takt-pack-lock.yaml'); + const packConfigPath = join(packageDir, TAKT_REPERTOIRE_MANIFEST_FILENAME); + const lockPath = join(packageDir, TAKT_REPERTOIRE_LOCK_FILENAME); const configYaml = existsSync(packConfigPath) ? readFileSync(packConfigPath, 'utf-8') : ''; - const config = parseTaktPackConfig(configYaml); + const config = parseTaktRepertoireConfig(configYaml); const lockYaml = existsSync(lockPath) ? readFileSync(lockPath, 'utf-8') @@ -52,25 +52,25 @@ export function readPackageInfo(packageDir: string, scope: string): PackageInfo } /** - * List all installed packages under the ensemble directory. + * List all installed packages under the repertoire directory. * * Directory structure: - * ensembleDir/ + * repertoireDir/ * @{owner}/ * {repo}/ - * takt-package.yaml - * .takt-pack-lock.yaml + * takt-repertoire.yaml + * .takt-repertoire-lock.yaml * - * @param ensembleDir - absolute path to the ensemble root (~/.takt/ensemble) + * @param repertoireDir - absolute path to the repertoire root (~/.takt/repertoire) */ -export function listPackages(ensembleDir: string): PackageInfo[] { - if (!existsSync(ensembleDir)) return []; +export function listPackages(repertoireDir: string): PackageInfo[] { + if (!existsSync(repertoireDir)) return []; const packages: PackageInfo[] = []; - for (const ownerEntry of readdirSync(ensembleDir)) { + for (const ownerEntry of readdirSync(repertoireDir)) { if (!ownerEntry.startsWith('@')) continue; - const ownerDir = join(ensembleDir, ownerEntry); + const ownerDir = join(repertoireDir, ownerEntry); try { if (!statSync(ownerDir).isDirectory()) continue; } catch (e) { log.debug(`stat failed for ${ownerDir}: ${getErrorMessage(e)}`); continue; } for (const repoEntry of readdirSync(ownerDir)) { diff --git a/src/features/ensemble/lock-file.ts b/src/features/repertoire/lock-file.ts similarity index 90% rename from src/features/ensemble/lock-file.ts rename to src/features/repertoire/lock-file.ts index e9fbfb2..fe1def1 100644 --- a/src/features/ensemble/lock-file.ts +++ b/src/features/repertoire/lock-file.ts @@ -1,7 +1,7 @@ /** - * Lock file generation and parsing for ensemble packages. + * Lock file generation and parsing for repertoire packages. * - * The .takt-pack-lock.yaml records the installation provenance: + * The .takt-repertoire-lock.yaml records the installation provenance: * source: github:{owner}/{repo} * ref: tag or branch (defaults to "HEAD") * commit: full SHA from tarball directory name @@ -59,7 +59,7 @@ export function generateLockFile(params: GenerateLockFileParams): PackageLock { } /** - * Parse .takt-pack-lock.yaml content into a PackageLock object. + * Parse .takt-repertoire-lock.yaml content into a PackageLock object. * Returns empty-valued lock when yaml is empty (lock file missing). */ export function parseLockFile(yaml: string): PackageLock { diff --git a/src/features/ensemble/pack-summary.ts b/src/features/repertoire/pack-summary.ts similarity index 100% rename from src/features/ensemble/pack-summary.ts rename to src/features/repertoire/pack-summary.ts diff --git a/src/features/ensemble/remove.ts b/src/features/repertoire/remove.ts similarity index 97% rename from src/features/ensemble/remove.ts rename to src/features/repertoire/remove.ts index ddd99a8..4c5c4ab 100644 --- a/src/features/ensemble/remove.ts +++ b/src/features/repertoire/remove.ts @@ -1,5 +1,5 @@ /** - * Ensemble package removal helpers. + * Repertoire package removal helpers. * * Provides: * - findScopeReferences: scan YAML files for @scope references (for pre-removal warning) @@ -10,7 +10,7 @@ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'; import { join } from 'node:path'; import { createLogger } from '../../shared/utils/debug.js'; -const log = createLogger('ensemble-remove'); +const log = createLogger('repertoire-remove'); export interface ScopeReference { /** Absolute path to the file containing the @scope reference. */ diff --git a/src/features/ensemble/takt-pack-config.ts b/src/features/repertoire/takt-repertoire-config.ts similarity index 79% rename from src/features/ensemble/takt-pack-config.ts rename to src/features/repertoire/takt-repertoire-config.ts index 7df36f8..3aa3ba0 100644 --- a/src/features/ensemble/takt-pack-config.ts +++ b/src/features/repertoire/takt-repertoire-config.ts @@ -1,5 +1,5 @@ /** - * takt-package.yaml parsing and validation. + * takt-repertoire.yaml parsing and validation. * * Handles: * - YAML parsing with default values @@ -13,9 +13,9 @@ import { existsSync, realpathSync } from 'node:fs'; import { join } from 'node:path'; import { parse as parseYaml } from 'yaml'; -import { TAKT_PACKAGE_MANIFEST_FILENAME } from './constants.js'; +import { TAKT_REPERTOIRE_MANIFEST_FILENAME } from './constants.js'; -export interface TaktPackConfig { +export interface TaktRepertoireConfig { description?: string; path: string; takt?: { @@ -31,10 +31,10 @@ interface PackageContentCheckContext { const SEMVER_PATTERN = /^\d+\.\d+\.\d+$/; /** - * Parse takt-package.yaml content string into a TaktPackConfig. + * Parse takt-repertoire.yaml content string into a TaktRepertoireConfig. * Applies default path "." when not specified. */ -export function parseTaktPackConfig(yaml: string): TaktPackConfig { +export function parseTaktRepertoireConfig(yaml: string): TaktRepertoireConfig { const raw = (yaml.trim() ? parseYaml(yaml) : {}) as Record | null; const data = raw ?? {}; @@ -56,16 +56,16 @@ export function parseTaktPackConfig(yaml: string): TaktPackConfig { * * Throws on validation failure. */ -export function validateTaktPackPath(path: string): void { +export function validateTaktRepertoirePath(path: string): void { if (path.startsWith('/')) { - throw new Error(`${TAKT_PACKAGE_MANIFEST_FILENAME}: path must not be absolute, got "${path}"`); + throw new Error(`${TAKT_REPERTOIRE_MANIFEST_FILENAME}: path must not be absolute, got "${path}"`); } if (path.startsWith('~')) { - throw new Error(`${TAKT_PACKAGE_MANIFEST_FILENAME}: path must not start with "~", got "${path}"`); + throw new Error(`${TAKT_REPERTOIRE_MANIFEST_FILENAME}: path must not start with "~", got "${path}"`); } const segments = path.split('/'); if (segments.includes('..')) { - throw new Error(`${TAKT_PACKAGE_MANIFEST_FILENAME}: path must not contain ".." segments, got "${path}"`); + throw new Error(`${TAKT_REPERTOIRE_MANIFEST_FILENAME}: path must not contain ".." segments, got "${path}"`); } } @@ -78,7 +78,7 @@ export function validateTaktPackPath(path: string): void { export function validateMinVersion(version: string): void { if (!SEMVER_PATTERN.test(version)) { throw new Error( - `${TAKT_PACKAGE_MANIFEST_FILENAME}: takt.min_version must match X.Y.Z (no "v" prefix, no pre-release), got "${version}"`, + `${TAKT_REPERTOIRE_MANIFEST_FILENAME}: takt.min_version must match X.Y.Z (no "v" prefix, no pre-release), got "${version}"`, ); } } @@ -137,7 +137,7 @@ export function checkPackageHasContentWithContext( const configuredPath = context.configuredPath ?? '.'; const manifestPath = context.manifestPath ?? '(unknown)'; const hint = configuredPath === '.' - ? `hint: If your package content is under ".takt/", set "path: .takt" in ${TAKT_PACKAGE_MANIFEST_FILENAME}.` + ? `hint: If your package content is under ".takt/", set "path: .takt" in ${TAKT_REPERTOIRE_MANIFEST_FILENAME}.` : `hint: Verify "path: ${configuredPath}" points to a directory containing facets/ or pieces/.`; throw new Error( @@ -154,24 +154,24 @@ export function checkPackageHasContentWithContext( } /** - * Resolve the path to takt-package.yaml within an extracted tarball directory. + * Resolve the path to takt-repertoire.yaml within an extracted tarball directory. * * Search order (first found wins): - * 1. {extractDir}/.takt/takt-package.yaml - * 2. {extractDir}/takt-package.yaml + * 1. {extractDir}/.takt/takt-repertoire.yaml + * 2. {extractDir}/takt-repertoire.yaml * * @param extractDir - root of the extracted tarball * @throws if neither candidate exists */ -export function resolvePackConfigPath(extractDir: string): string { - const taktDirPath = join(extractDir, '.takt', TAKT_PACKAGE_MANIFEST_FILENAME); +export function resolveRepertoireConfigPath(extractDir: string): string { + const taktDirPath = join(extractDir, '.takt', TAKT_REPERTOIRE_MANIFEST_FILENAME); if (existsSync(taktDirPath)) return taktDirPath; - const rootPath = join(extractDir, TAKT_PACKAGE_MANIFEST_FILENAME); + const rootPath = join(extractDir, TAKT_REPERTOIRE_MANIFEST_FILENAME); if (existsSync(rootPath)) return rootPath; throw new Error( - `${TAKT_PACKAGE_MANIFEST_FILENAME} not found in "${extractDir}": checked .takt/${TAKT_PACKAGE_MANIFEST_FILENAME} and ${TAKT_PACKAGE_MANIFEST_FILENAME}`, + `${TAKT_REPERTOIRE_MANIFEST_FILENAME} not found in "${extractDir}": checked .takt/${TAKT_REPERTOIRE_MANIFEST_FILENAME} and ${TAKT_REPERTOIRE_MANIFEST_FILENAME}`, ); } diff --git a/src/features/ensemble/tar-parser.ts b/src/features/repertoire/tar-parser.ts similarity index 100% rename from src/features/ensemble/tar-parser.ts rename to src/features/repertoire/tar-parser.ts diff --git a/src/infra/config/loaders/agentLoader.ts b/src/infra/config/loaders/agentLoader.ts index 26b14fa..c8b2b2d 100644 --- a/src/infra/config/loaders/agentLoader.ts +++ b/src/infra/config/loaders/agentLoader.ts @@ -16,7 +16,7 @@ import { getBuiltinPiecesDir, getGlobalFacetDir, getProjectFacetDir, - getEnsembleDir, + getRepertoireDir, isPathSafe, } from '../paths.js'; import { resolveConfigValue } from '../resolveConfigValue.js'; @@ -31,7 +31,7 @@ function getAllowedPromptBases(cwd: string): string[] { getBuiltinPiecesDir(lang), getGlobalFacetDir('personas'), getProjectFacetDir(cwd, 'personas'), - getEnsembleDir(), + getRepertoireDir(), ]; } diff --git a/src/infra/config/loaders/pieceCategories.ts b/src/infra/config/loaders/pieceCategories.ts index 3ee5064..6b4070a 100644 --- a/src/infra/config/loaders/pieceCategories.ts +++ b/src/infra/config/loaders/pieceCategories.ts @@ -326,11 +326,11 @@ function buildCategoryTree( } /** - * Append an "ensemble" category containing all @scope pieces. + * Append a "repertoire" category containing all @scope pieces. * Creates one subcategory per @owner/repo package. - * Marks ensemble piece names as categorized (prevents them from appearing in "Others"). + * Marks repertoire piece names as categorized (prevents them from appearing in "Others"). */ -function appendEnsembleCategory( +function appendRepertoireCategory( categories: PieceCategoryNode[], allPieces: Map, categorized: Set, @@ -352,11 +352,11 @@ function appendEnsembleCategory( categorized.add(pieceName); } if (packagePieces.size === 0) return categories; - const ensembleChildren: PieceCategoryNode[] = []; + const repertoireChildren: PieceCategoryNode[] = []; for (const [packageKey, pieces] of packagePieces.entries()) { - ensembleChildren.push({ name: packageKey, pieces, children: [] }); + repertoireChildren.push({ name: packageKey, pieces, children: [] }); } - return [...categories, { name: 'ensemble', pieces: [], children: ensembleChildren }]; + return [...categories, { name: 'repertoire', pieces: [], children: repertoireChildren }]; } function appendOthersCategory( @@ -415,7 +415,7 @@ export function buildCategorizedPieces( const categorized = new Set(); const categories = buildCategoryTree(config.pieceCategories, allPieces, categorized); - const categoriesWithEnsemble = appendEnsembleCategory(categories, allPieces, categorized); + const categoriesWithEnsemble = appendRepertoireCategory(categories, allPieces, categorized); const finalCategories = config.showOthersCategory ? appendOthersCategory(categoriesWithEnsemble, allPieces, categorized, config.othersCategoryName) diff --git a/src/infra/config/loaders/pieceParser.ts b/src/infra/config/loaders/pieceParser.ts index 9cebd7c..ba5b2e8 100644 --- a/src/infra/config/loaders/pieceParser.ts +++ b/src/infra/config/loaders/pieceParser.ts @@ -12,7 +12,7 @@ import type { z } from 'zod'; import { PieceConfigRawSchema, PieceMovementRawSchema } from '../../../core/models/index.js'; import type { PieceConfig, PieceMovement, PieceRule, OutputContractEntry, OutputContractItem, LoopMonitorConfig, LoopMonitorJudge, ArpeggioMovementConfig, ArpeggioMergeMovementConfig, TeamLeaderConfig } from '../../../core/models/index.js'; import { resolvePieceConfigValue } from '../resolvePieceConfigValue.js'; -import { getEnsembleDir } from '../paths.js'; +import { getRepertoireDir } from '../paths.js'; import { type PieceSections, type FacetResolutionContext, @@ -443,7 +443,7 @@ export function loadPieceFromFile(filePath: string, projectDir: string): PieceCo lang: resolvePieceConfigValue(projectDir, 'language'), projectDir, pieceDir, - ensembleDir: getEnsembleDir(), + repertoireDir: getRepertoireDir(), }; return normalizePieceConfig(raw, pieceDir, context); diff --git a/src/infra/config/loaders/pieceResolver.ts b/src/infra/config/loaders/pieceResolver.ts index 0e26cd9..b017790 100644 --- a/src/infra/config/loaders/pieceResolver.ts +++ b/src/infra/config/loaders/pieceResolver.ts @@ -9,7 +9,7 @@ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs'; import { join, resolve, isAbsolute } from 'node:path'; import { homedir } from 'node:os'; import type { PieceConfig, PieceMovement, InteractiveMode } from '../../../core/models/index.js'; -import { getGlobalPiecesDir, getBuiltinPiecesDir, getProjectConfigDir, getEnsembleDir } from '../paths.js'; +import { getGlobalPiecesDir, getBuiltinPiecesDir, getProjectConfigDir, getRepertoireDir } from '../paths.js'; import { isScopeRef, parseScopeRef } from '../../../faceted-prompting/index.js'; import { resolvePieceConfigValues } from '../resolvePieceConfigValue.js'; import { createLogger, getErrorMessage } from '../../../shared/utils/index.js'; @@ -17,7 +17,7 @@ import { loadPieceFromFile } from './pieceParser.js'; const log = createLogger('piece-resolver'); -export type PieceSource = 'builtin' | 'user' | 'project' | 'ensemble'; +export type PieceSource = 'builtin' | 'user' | 'project' | 'repertoire'; export interface PieceWithSource { config: PieceConfig; @@ -144,7 +144,7 @@ export function loadPieceByIdentifier( projectCwd: string, ): PieceConfig | null { if (isScopeRef(identifier)) { - return loadEnsemblePieceByRef(identifier, projectCwd); + return loadRepertoirePieceByRef(identifier, projectCwd); } if (isPiecePath(identifier)) { return loadPieceFromPath(identifier, projectCwd, projectCwd); @@ -376,14 +376,14 @@ function* iteratePieceDir( } /** - * Iterate piece YAML files in all ensemble packages. + * Iterate piece YAML files in all repertoire packages. * Qualified name format: @{owner}/{repo}/{piece-name} */ -function* iterateEnsemblePieces(ensembleDir: string): Generator { - if (!existsSync(ensembleDir)) return; - for (const ownerEntry of readdirSync(ensembleDir)) { +function* iterateRepertoirePieces(repertoireDir: string): Generator { + if (!existsSync(repertoireDir)) return; + for (const ownerEntry of readdirSync(repertoireDir)) { if (!ownerEntry.startsWith('@')) continue; - const ownerPath = join(ensembleDir, ownerEntry); + const ownerPath = join(repertoireDir, ownerEntry); try { if (!statSync(ownerPath).isDirectory()) continue; } catch (e) { log.debug(`stat failed for owner dir ${ownerPath}: ${getErrorMessage(e)}`); continue; } const owner = ownerEntry.slice(1); for (const repoEntry of readdirSync(ownerPath)) { @@ -396,7 +396,7 @@ function* iterateEnsemblePieces(ensembleDir: string): Generator { const piecePath = join(piecesDir, pieceFile); try { if (!statSync(piecePath).isFile()) continue; } catch (e) { log.debug(`stat failed for piece file ${piecePath}: ${getErrorMessage(e)}`); continue; } const pieceName = pieceFile.replace(/\.ya?ml$/, ''); - yield { name: `@${owner}/${repoEntry}/${pieceName}`, path: piecePath, source: 'ensemble' }; + yield { name: `@${owner}/${repoEntry}/${pieceName}`, path: piecePath, source: 'repertoire' }; } } } @@ -404,12 +404,12 @@ function* iterateEnsemblePieces(ensembleDir: string): Generator { /** * Load a piece by @scope reference (@{owner}/{repo}/{piece-name}). - * Resolves to ~/.takt/ensemble/@{owner}/{repo}/pieces/{piece-name}.yaml + * Resolves to ~/.takt/repertoire/@{owner}/{repo}/pieces/{piece-name}.yaml */ -function loadEnsemblePieceByRef(identifier: string, projectCwd: string): PieceConfig | null { +function loadRepertoirePieceByRef(identifier: string, projectCwd: string): PieceConfig | null { const scopeRef = parseScopeRef(identifier); - const ensembleDir = getEnsembleDir(); - const piecesDir = join(ensembleDir, `@${scopeRef.owner}`, scopeRef.repo, 'pieces'); + const repertoireDir = getRepertoireDir(); + const piecesDir = join(repertoireDir, `@${scopeRef.owner}`, scopeRef.repo, 'pieces'); const filePath = resolvePieceFile(piecesDir, scopeRef.name); if (!filePath) return null; return loadPieceFromFile(filePath, projectCwd); @@ -450,12 +450,12 @@ export function loadAllPiecesWithSources(cwd: string): Map