refactor: 設定の不要要素削除とconfigテンプレート刷新

This commit is contained in:
nrslib 2026-02-19 11:53:02 +09:00
parent 2a6b9f4ad0
commit 6518faf72e
19 changed files with 308 additions and 406 deletions

View File

@ -1,105 +1,91 @@
# TAKT global configuration sample # TAKT global configuration sample
# Location: ~/.takt/config.yaml # Location: ~/.takt/config.yaml
# ---- Core ---- # =====================================
language: en # General settings (piece-independent)
default_piece: default # =====================================
log_level: info language: en # UI language: en | ja
log_level: info # Log level: debug | info | warn | error
provider: claude # Default provider: claude | codex | opencode | mock
# model: sonnet # Optional model name passed to provider
# ---- Provider ---- # Execution control
# provider: claude | codex | opencode | mock # worktree_dir: ~/takt-worktrees # Base directory for shared clone execution
provider: claude # auto_pr: false # Auto-create PR after worktree execution
branch_name_strategy: ai # Branch strategy: romaji | ai
concurrency: 2 # Concurrent task execution for takt run (1-10)
# task_poll_interval_ms: 500 # Polling interval in ms during takt run (100-5000)
# prevent_sleep: false # Prevent macOS idle sleep while running
# Model (optional) # Output / notifications
# Claude examples: opus, sonnet, haiku # minimal_output: false # Minimized output for CI logs
# Codex examples: gpt-5.2-codex, gpt-5.1-codex # verbose: false # Verbose output mode
# OpenCode format: provider/model # notification_sound: true # Master switch for sounds
# model: sonnet # notification_sound_events: # Per-event sound toggle (unset means true)
# Per-persona provider override
# persona_providers:
# coder: codex
# reviewer: claude
# Provider-specific movement permission policy
# Priority:
# 1) project provider_profiles override
# 2) global provider_profiles override
# 3) project provider_profiles default
# 4) global provider_profiles default
# 5) movement.required_permission_mode (minimum floor)
# provider_profiles:
# codex:
# default_permission_mode: full
# movement_permission_overrides:
# ai_review: readonly
# claude:
# default_permission_mode: edit
# Provider-specific runtime options
# provider_options:
# codex:
# network_access: true
# claude:
# sandbox:
# allow_unsandboxed_commands: true
# ---- API Keys ----
# Environment variables take priority:
# TAKT_ANTHROPIC_API_KEY / TAKT_OPENAI_API_KEY / TAKT_OPENCODE_API_KEY
# anthropic_api_key: ""
# openai_api_key: ""
# opencode_api_key: ""
# ---- Runtime ----
# Global runtime preparation (piece_config.runtime overrides this)
# runtime:
# prepare:
# - gradle
# - node
# ---- Execution ----
# worktree_dir: ~/takt-worktrees
# auto_pr: false
# prevent_sleep: false
# ---- Run Loop ----
# concurrency: 1
# task_poll_interval_ms: 500
# interactive_preview_movements: 3
# branch_name_strategy: romaji
# ---- Output ----
# minimal_output: false
# notification_sound: true
# notification_sound_events:
# iteration_limit: true # iteration_limit: true
# piece_complete: true # piece_complete: true
# piece_abort: true # piece_abort: true
# run_complete: true # run_complete: true
# run_abort: true # run_abort: true
# observability: # observability:
# provider_events: true # provider_events: false # Persist provider stream events
# ---- Builtins ---- # Credentials (environment variables take priority)
# enable_builtin_pieces: true # anthropic_api_key: "sk-ant-..." # Claude API key
# disabled_builtins: # openai_api_key: "sk-..." # Codex/OpenAI API key
# - magi # opencode_api_key: "..." # OpenCode API key
# codex_cli_path: "/absolute/path/to/codex" # Absolute path to Codex CLI
# ---- Pipeline ---- # Pipeline
# pipeline: # pipeline:
# default_branch_prefix: "takt/" # default_branch_prefix: "takt/" # Prefix for pipeline-created branches
# commit_message_template: "feat: {title} (#{issue})" # commit_message_template: "feat: {title} (#{issue})" # Commit template
# pr_body_template: | # pr_body_template: | # PR body template
# ## Summary # ## Summary
# {issue_body} # {issue_body}
# Closes #{issue} # Closes #{issue}
# ---- Preferences ---- # Misc
# bookmarks_file: ~/.takt/preferences/bookmarks.yaml # bookmarks_file: ~/.takt/preferences/bookmarks.yaml # Bookmark file location
# piece_categories_file: ~/.takt/preferences/piece-categories.yaml
# ---- Debug ---- # =====================================
# debug: # Piece-related settings (global defaults)
# enabled: false # =====================================
# log_file: ~/.takt/logs/debug.log # 1) Route provider per persona
# persona_providers:
# coder: codex # Run coder persona on codex
# reviewer: claude # Run reviewer persona on claude
# 2) Provider options (global < project < piece)
# provider_options:
# codex:
# network_access: true # Allow network access for Codex
# opencode:
# network_access: true # Allow network access for OpenCode
# claude:
# sandbox:
# allow_unsandboxed_commands: false # true allows unsandboxed execution for listed commands
# excluded_commands:
# - "npm publish" # Commands excluded from sandbox
# 3) Movement permission policy
# provider_profiles:
# codex:
# default_permission_mode: full # Base permission: readonly | edit | full
# movement_permission_overrides:
# ai_review: readonly # Per-movement override
# claude:
# default_permission_mode: edit
# 4) Runtime preparation before execution (recommended: enabled)
runtime:
prepare:
- gradle # Prepare Gradle cache/env under .runtime
- node # Prepare npm cache/env under .runtime
# 5) Piece list / categories
# enable_builtin_pieces: true # Enable built-in pieces from builtins/{lang}/pieces
# disabled_builtins:
# - magi # Built-in piece names to disable
# piece_categories_file: ~/.takt/preferences/piece-categories.yaml # Category definition file
# interactive_preview_movements: 3 # Preview movement count in interactive mode (0-10)

View File

@ -1,105 +1,91 @@
# TAKT グローバル設定サンプル # TAKT グローバル設定サンプル
# 配置場所: ~/.takt/config.yaml # 配置場所: ~/.takt/config.yaml
# ---- 基本 ---- # =====================================
language: ja # 通常設定(ピース非依存)
default_piece: default # =====================================
log_level: info language: ja # 表示言語: ja | en
log_level: info # ログレベル: debug | info | warn | error
provider: claude # デフォルト実行プロバイダー: claude | codex | opencode | mock
# model: sonnet # 省略可。providerに渡すモデル名
# ---- プロバイダー ---- # 実行制御
# provider: claude | codex | opencode | mock # worktree_dir: ~/takt-worktrees # 共有clone作成先ディレクトリ
provider: claude # auto_pr: false # worktree実行後に自動PR作成するか
branch_name_strategy: ai # ブランチ名生成: romaji | ai
concurrency: 2 # takt run の同時実行数1-10
# task_poll_interval_ms: 500 # takt run のタスク監視間隔ms100-5000
# prevent_sleep: false # macOS実行中のスリープ防止caffeinate
# モデル(任意) # 出力・通知
# Claude 例: opus, sonnet, haiku # minimal_output: false # 出力を最小化CI向け
# Codex 例: gpt-5.2-codex, gpt-5.1-codex # verbose: false # 詳細ログを有効化
# OpenCode 形式: provider/model # notification_sound: true # 通知音全体のON/OFF
# model: sonnet # notification_sound_events: # イベント別通知音未指定はtrue扱い
# ペルソナ別プロバイダー上書き
# persona_providers:
# coder: codex
# reviewer: claude
# プロバイダー別 movement 権限ポリシー
# 優先順:
# 1) project provider_profiles override
# 2) global provider_profiles override
# 3) project provider_profiles default
# 4) global provider_profiles default
# 5) movement.required_permission_mode下限補正
# provider_profiles:
# codex:
# default_permission_mode: full
# movement_permission_overrides:
# ai_review: readonly
# claude:
# default_permission_mode: edit
# プロバイダー別ランタイムオプション
# provider_options:
# codex:
# network_access: true
# claude:
# sandbox:
# allow_unsandboxed_commands: true
# ---- API キー ----
# 環境変数が優先:
# TAKT_ANTHROPIC_API_KEY / TAKT_OPENAI_API_KEY / TAKT_OPENCODE_API_KEY
# anthropic_api_key: ""
# openai_api_key: ""
# opencode_api_key: ""
# ---- ランタイム ----
# グローバルなランタイム準備piece_config.runtime があればそちらを優先)
# runtime:
# prepare:
# - gradle
# - node
# ---- 実行 ----
# worktree_dir: ~/takt-worktrees
# auto_pr: false
# prevent_sleep: false
# ---- Run Loop ----
# concurrency: 1
# task_poll_interval_ms: 500
# interactive_preview_movements: 3
# branch_name_strategy: romaji
# ---- 出力 ----
# minimal_output: false
# notification_sound: true
# notification_sound_events:
# iteration_limit: true # iteration_limit: true
# piece_complete: true # piece_complete: true
# piece_abort: true # piece_abort: true
# run_complete: true # run_complete: true
# run_abort: true # run_abort: true
# observability: # observability:
# provider_events: true # provider_events: false # providerイベントログを記録
# ---- Builtins ---- # 認証情報(環境変数優先)
# enable_builtin_pieces: true # anthropic_api_key: "sk-ant-..." # Claude APIキー
# disabled_builtins: # openai_api_key: "sk-..." # Codex APIキー
# - magi # opencode_api_key: "..." # OpenCode APIキー
# codex_cli_path: "/absolute/path/to/codex" # Codex CLI絶対パス
# ---- Pipeline ---- # パイプライン
# pipeline: # pipeline:
# default_branch_prefix: "takt/" # default_branch_prefix: "takt/" # pipeline作成ブランチの接頭辞
# commit_message_template: "feat: {title} (#{issue})" # commit_message_template: "feat: {title} (#{issue})" # コミット文テンプレート
# pr_body_template: | # pr_body_template: | # PR本文テンプレート
# ## Summary # ## Summary
# {issue_body} # {issue_body}
# Closes #{issue} # Closes #{issue}
# ---- Preferences ---- # その他
# bookmarks_file: ~/.takt/preferences/bookmarks.yaml # bookmarks_file: ~/.takt/preferences/bookmarks.yaml # ブックマーク保存先
# piece_categories_file: ~/.takt/preferences/piece-categories.yaml
# ---- Debug ---- # =====================================
# debug: # ピースにも関わる設定global defaults
# enabled: false # =====================================
# log_file: ~/.takt/logs/debug.log # 1) ペルソナ単位でプロバイダーを切り替える
# persona_providers:
# coder: codex # coderペルソナはcodexで実行
# reviewer: claude # reviewerペルソナはclaudeで実行
# 2) provider 固有オプションglobal < project < piece
# provider_options:
# codex:
# network_access: true # Codex実行時のネットワークアクセス許可
# opencode:
# network_access: true # OpenCode実行時のネットワークアクセス許可
# claude:
# sandbox:
# allow_unsandboxed_commands: false # trueで対象コマンドを非サンドボックス実行
# excluded_commands:
# - "npm publish" # 非サンドボックス対象コマンド
# 3) movement の権限ポリシー
# provider_profiles:
# codex:
# default_permission_mode: full # 既定権限: readonly | edit | full
# movement_permission_overrides:
# ai_review: readonly # movement単位の上書き
# claude:
# default_permission_mode: edit
# 4) 実行前のランタイム準備(推奨: 有効化)
runtime:
prepare:
- gradle # Gradleキャッシュ/環境を .runtime 配下に準備
- node # npmキャッシュ/環境を .runtime 配下に準備
# 5) ピース一覧/カテゴリ
# enable_builtin_pieces: true # builtins/{lang}/pieces を有効化
# disabled_builtins:
# - magi # 無効化するビルトインピース名
# piece_categories_file: ~/.takt/preferences/piece-categories.yaml # カテゴリ定義ファイル
# interactive_preview_movements: 3 # 対話モードのプレビュー件数0-10

View File

@ -292,9 +292,6 @@ takt eject instruction plan --global
# 各ムーブメント・フェーズの組み立て済みプロンプトをプレビュー # 各ムーブメント・フェーズの組み立て済みプロンプトをプレビュー
takt prompt [piece] takt prompt [piece]
# パーミッションモードを設定
takt config
# ピースカテゴリをビルトインのデフォルトにリセット # ピースカテゴリをビルトインのデフォルトにリセット
takt reset categories takt reset categories
``` ```
@ -562,76 +559,182 @@ Claude Code はエイリアス(`opus`、`sonnet`、`haiku`、`opusplan`、`def
### グローバル設定 ### グローバル設定
デフォルトのプロバイダーとモデルを `~/.takt/config.yaml` で設定: `~/.takt/config.yaml` のサンプルです。
コメントで「通常設定」と「ピースにも関わる設定」を分けています。
```yaml ```yaml
# ~/.takt/config.yaml # ~/.takt/config.yaml
language: ja
default_piece: default
log_level: info
provider: claude # デフォルトプロバイダー: claude、codex、または opencode
model: sonnet # デフォルトモデル(オプション)
branch_name_strategy: romaji # ブランチ名生成: 'romaji'(高速)または 'ai'(低速)
prevent_sleep: false # macOS の実行中スリープ防止caffeinate
notification_sound: true # 通知音の有効/無効
notification_sound_events: # タイミング別の通知音制御
iteration_limit: false
piece_complete: true
piece_abort: true
run_complete: true # 未設定時は有効。false を指定すると無効
run_abort: true # 未設定時は有効。false を指定すると無効
concurrency: 1 # takt run の並列タスク数1-10、デフォルト: 1 = 逐次実行)
task_poll_interval_ms: 500 # takt run 中の新タスク検出ポーリング間隔100-5000、デフォルト: 500
interactive_preview_movements: 3 # 対話モードでのムーブメントプレビュー数0-10、デフォルト: 3
# ランタイム環境デフォルトpiece_config.runtime で上書き可能) # =====================================
# runtime: # 通常設定(ピース非依存)
# prepare: # =====================================
# - gradle # Gradle のキャッシュ/設定を .runtime/ に準備 language: ja # 表示言語: ja | en
# - node # npm キャッシュを .runtime/ に準備 log_level: info # ログレベル: debug | info | warn | error
provider: claude # デフォルト実行プロバイダー: claude | codex | opencode | mock
# model: sonnet # 省略可。providerに渡すモデル名
# ペルソナ別プロバイダー設定(オプション) # 実行制御
# ピースを複製せずに特定のペルソナを異なるプロバイダーにルーティング # worktree_dir: ~/takt-worktrees # 共有clone作成先ディレクトリ
# auto_pr: false # worktree実行後に自動PR作成するか
branch_name_strategy: ai # ブランチ名生成: romaji | ai
concurrency: 2 # takt run の同時実行数1-10
# task_poll_interval_ms: 500 # takt run のタスク監視間隔ms100-5000
# prevent_sleep: false # macOS実行中のスリープ防止caffeinate
# 出力・通知
# minimal_output: false # 出力を最小化CI向け
# verbose: false # 詳細ログを有効化
# notification_sound: true # 通知音全体のON/OFF
# notification_sound_events: # イベント別通知音未指定はtrue扱い
# iteration_limit: true
# piece_complete: true
# piece_abort: true
# run_complete: true
# run_abort: true
# observability:
# provider_events: false # providerイベントログを記録
# 認証情報(環境変数優先)
# anthropic_api_key: "sk-ant-..." # Claude APIキー
# openai_api_key: "sk-..." # Codex APIキー
# opencode_api_key: "..." # OpenCode APIキー
# codex_cli_path: "/absolute/path/to/codex" # Codex CLI絶対パス
# パイプライン
# pipeline:
# default_branch_prefix: "takt/" # pipeline作成ブランチの接頭辞
# commit_message_template: "feat: {title} (#{issue})" # コミット文テンプレート
# pr_body_template: | # PR本文テンプレート
# ## Summary
# {issue_body}
# Closes #{issue}
# その他
# bookmarks_file: ~/.takt/preferences/bookmarks.yaml # ブックマーク保存先
# =====================================
# ピースにも関わる設定global defaults
# =====================================
# 1) ペルソナ単位でプロバイダーを切り替える
# persona_providers: # persona_providers:
# coder: codex # coder を Codex で実行 # coder: codex # coderペルソナはcodexで実行
# ai-antipattern-reviewer: claude # レビュアーは Claude のまま # reviewer: claude # reviewerペルソナはclaudeで実行
# 2) provider 固有オプションglobal < project < piece
# provider_options:
# codex:
# network_access: true # Codex実行時のネットワークアクセス許可
# opencode:
# network_access: true # OpenCode実行時のネットワークアクセス許可
# claude:
# sandbox:
# allow_unsandboxed_commands: false # trueで対象コマンドを非サンドボックス実行
# excluded_commands:
# - "npm publish" # 非サンドボックス対象コマンド
# 3) movement の権限ポリシー
# provider_profiles:
# codex:
# default_permission_mode: full # 既定権限: readonly | edit | full
# movement_permission_overrides:
# ai_review: readonly # movement単位の上書き
# claude:
# default_permission_mode: edit
# 4) 実行前のランタイム準備(推奨: 有効化)
runtime:
prepare:
- gradle # Gradleキャッシュ/環境を .runtime 配下に準備
- node # npmキャッシュ/環境を .runtime 配下に準備
# 5) ピース一覧/カテゴリ
# enable_builtin_pieces: true # builtins/{lang}/pieces を有効化
# disabled_builtins:
# - magi # 無効化するビルトインピース名
# piece_categories_file: ~/.takt/preferences/piece-categories.yaml # カテゴリ定義ファイル
# interactive_preview_movements: 3 # 対話モードのプレビュー件数0-10
```
主要な設定項目の説明:
**通常設定**
| 項目 | 説明 |
|------|------|
| `language` | 表示言語(`ja` / `en` |
| `log_level` | ログレベル(`debug` / `info` / `warn` / `error` |
| `provider` | デフォルト実行プロバイダー(`claude` / `codex` / `opencode` / `mock` |
| `model` | モデル名provider にそのまま渡される) |
| `auto_pr` | worktree 実行後のPR作成挙動 |
| `concurrency` | `takt run` の同時実行数1-10 |
| `task_poll_interval_ms` | `takt run` のタスク監視間隔100-5000ms |
| `minimal_output` | CI向けの簡易出力モード |
| `verbose` | 詳細ログ出力 |
| `notification_sound` / `notification_sound_events` | 通知音のON/OFFとイベント別制御 |
| `pipeline.*` | pipeline 実行時のブランチ/コミット/PRテンプレート |
**ピースにも関わる設定**
| 項目 | 説明 |
|------|------|
| `persona_providers` | ペルソナ単位の provider 上書き |
| `provider_options` | provider固有オプション例: `codex.network_access``claude.sandbox.*` |
| `provider_profiles` | movement ごとの permission mode 解決ルール |
| `runtime.prepare` | 実行前の環境準備(`gradle` / `node` / 任意スクリプト) |
| `enable_builtin_pieces` / `disabled_builtins` | ビルトインピースの有効化/除外 |
| `piece_categories_file` | ピースカテゴリ定義ファイルの場所 |
| `interactive_preview_movements` | 対話モードで表示する movement プレビュー数 |
### プロジェクトローカル設定
`.takt/config.yaml` のサンプルです。
チーム/リポジトリごとの既定値を置く用途です。
```yaml
# .takt/config.yaml
# =====================================
# 通常設定(ピース非依存)
# =====================================
piece: default # このプロジェクトで使う既定ピース名
provider: claude # プロジェクト既定プロバイダー: claude | codex | opencode | mock
# verbose: false # このプロジェクトだけ詳細ログを有効化する場合
# auto_pr: false # worktree実行後に自動PR作成するか
# =====================================
# ピースにも関わる設定project overrides
# =====================================
# provider_options:
# codex:
# network_access: true # グローバル設定をこのプロジェクトで上書き
# claude:
# sandbox:
# allow_unsandboxed_commands: false
# excluded_commands:
# - "npm publish"
# プロバイダー別パーミッションプロファイル(オプション)
# 優先順: project override → global override → project default → global default → required_permission_mode下限
# provider_profiles: # provider_profiles:
# codex: # codex:
# default_permission_mode: full # default_permission_mode: full
# movement_permission_overrides: # movement_permission_overrides:
# ai_review: readonly # ai_review: readonly
# claude:
# default_permission_mode: edit
# API Key 設定(オプション)
# 環境変数 TAKT_ANTHROPIC_API_KEY / TAKT_OPENAI_API_KEY / TAKT_OPENCODE_API_KEY で上書き可能
anthropic_api_key: sk-ant-... # Claude (Anthropic) を使う場合
# openai_api_key: sk-... # Codex (OpenAI) を使う場合
# opencode_api_key: ... # OpenCode を使う場合
# Codex CLI パスの上書き(オプション)
# Codex SDK が使用する CLI バイナリを上書き(実行可能ファイルの絶対パスを指定)
# 環境変数 TAKT_CODEX_CLI_PATH で上書き可能
# codex_cli_path: /usr/local/bin/codex
# ビルトインピースのフィルタリング(オプション)
# builtin_pieces_enabled: true # false でビルトイン全体を無効化
# disabled_builtins: [magi, passthrough] # 特定のビルトインピースを無効化
# パイプライン実行設定(オプション)
# ブランチ名、コミットメッセージ、PRの本文をカスタマイズできます。
# pipeline:
# default_branch_prefix: "takt/"
# commit_message_template: "feat: {title} (#{issue})"
# pr_body_template: |
# ## Summary
# {issue_body}
# Closes #{issue}
``` ```
プロジェクトローカルで使える主な項目:
| 項目 | 説明 |
|------|------|
| `piece` | プロジェクト既定のピース |
| `provider` | プロジェクト既定のプロバイダー |
| `verbose` | ローカル詳細ログ |
| `auto_pr` | ローカル既定のPR作成挙動 |
| `provider_options` | provider固有オプションのローカル上書き |
| `provider_profiles` | movement権限ポリシーのローカル上書き |
設定解決の優先順位(高 → 低):
1. 環境変数(`TAKT_*`
2. `.takt/config.yaml`(プロジェクトローカル)
3. `~/.takt/config.yaml`(グローバル)
4. デフォルト値
**注意:** Codex SDK は Git 管理下のディレクトリでのみ動作します。`--skip-git-repo-check` は Codex CLI 専用です。 **注意:** Codex SDK は Git 管理下のディレクトリでのみ動作します。`--skip-git-repo-check` は Codex CLI 専用です。
**API Key の設定方法:** **API Key の設定方法:**

View File

@ -144,14 +144,6 @@ E2Eテストを追加・変更した場合は、このドキュメントも更
- `takt list --non-interactive --action diff --branch <branch>` で差分統計が出力されることを確認する。 - `takt list --non-interactive --action diff --branch <branch>` で差分統計が出力されることを確認する。
- `takt list --non-interactive --action try --branch <branch>` で変更がステージされることを確認する。 - `takt list --non-interactive --action try --branch <branch>` で変更がステージされることを確認する。
- `takt list --non-interactive --action merge --branch <branch>` でブランチがマージされ削除されることを確認する。 - `takt list --non-interactive --action merge --branch <branch>` でブランチがマージされ削除されることを確認する。
- Config permission mode`e2e/specs/cli-config.e2e.ts`
- 目的: `takt config` でパーミッションモードの切り替えと永続化を確認。
- LLM: 呼び出さないLLM不使用の操作のみ
- 手順(ユーザー行動/コマンド):
- `takt config default` を実行し、`Switched to: default` が出力されることを確認する。
- `takt config sacrifice-my-pc` を実行し、`Switched to: sacrifice-my-pc` が出力されることを確認する。
- `takt config sacrifice-my-pc` 実行後、`.takt/config.yaml``permissionMode: sacrifice-my-pc` が保存されていることを確認する。
- `takt config invalid-mode` を実行し、`Invalid mode` が出力されることを確認する。
- Reset categories`e2e/specs/cli-reset-categories.e2e.ts` - Reset categories`e2e/specs/cli-reset-categories.e2e.ts`
- 目的: `takt reset categories` でカテゴリオーバーレイのリセットを確認。 - 目的: `takt reset categories` でカテゴリオーバーレイのリセットを確認。
- LLM: 呼び出さないLLM不使用の操作のみ - LLM: 呼び出さないLLM不使用の操作のみ

View File

@ -1,7 +1,6 @@
provider: claude provider: claude
language: en language: en
log_level: info log_level: info
default_piece: default
notification_sound: false notification_sound: false
notification_sound_events: notification_sound_events:
iteration_limit: false iteration_limit: false

View File

@ -1,85 +0,0 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import { createIsolatedEnv, type IsolatedEnv } from '../helpers/isolated-env';
import { runTakt } from '../helpers/takt-runner';
import { createLocalRepo, type LocalRepo } from '../helpers/test-repo';
// E2E更新時は docs/testing/e2e.md も更新すること
describe('E2E: Config command (takt config)', () => {
let isolatedEnv: IsolatedEnv;
let repo: LocalRepo;
beforeEach(() => {
isolatedEnv = createIsolatedEnv();
repo = createLocalRepo();
});
afterEach(() => {
try { repo.cleanup(); } catch { /* best-effort */ }
try { isolatedEnv.cleanup(); } catch { /* best-effort */ }
});
it('should switch to default mode with explicit argument', () => {
// Given: a local repo with isolated env
// When: running takt config default
const result = runTakt({
args: ['config', 'default'],
cwd: repo.path,
env: isolatedEnv.env,
});
// Then: exits successfully and outputs switched message
expect(result.exitCode).toBe(0);
const output = result.stdout;
expect(output).toMatch(/Switched to: default/);
});
it('should switch to sacrifice-my-pc mode with explicit argument', () => {
// Given: a local repo with isolated env
// When: running takt config sacrifice-my-pc
const result = runTakt({
args: ['config', 'sacrifice-my-pc'],
cwd: repo.path,
env: isolatedEnv.env,
});
// Then: exits successfully and outputs switched message
expect(result.exitCode).toBe(0);
const output = result.stdout;
expect(output).toMatch(/Switched to: sacrifice-my-pc/);
});
it('should persist permission mode to project config', () => {
// Given: a local repo with isolated env
// When: running takt config sacrifice-my-pc
runTakt({
args: ['config', 'sacrifice-my-pc'],
cwd: repo.path,
env: isolatedEnv.env,
});
// Then: .takt/config.yaml contains permissionMode: sacrifice-my-pc
const configPath = join(repo.path, '.takt', 'config.yaml');
const content = readFileSync(configPath, 'utf-8');
expect(content).toMatch(/permissionMode:\s*sacrifice-my-pc/);
});
it('should report error for invalid mode name', () => {
// Given: a local repo with isolated env
// When: running takt config with an invalid mode
const result = runTakt({
args: ['config', 'invalid-mode'],
cwd: repo.path,
env: isolatedEnv.env,
});
// Then: output contains invalid mode message
const combined = result.stdout + result.stderr;
expect(combined).toMatch(/Invalid mode/);
});
});

View File

@ -66,7 +66,6 @@ vi.mock('../infra/config/index.js', () => ({
vi.mock('../infra/config/paths.js', () => ({ vi.mock('../infra/config/paths.js', () => ({
clearPersonaSessions: vi.fn(), clearPersonaSessions: vi.fn(),
getCurrentPiece: vi.fn(() => 'default'),
isVerboseMode: vi.fn(() => false), isVerboseMode: vi.fn(() => false),
})); }));

View File

@ -1,5 +1,5 @@
/** /**
* Tests for takt config functions * Tests for config functions
*/ */
import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { describe, it, expect, beforeEach, afterEach } from 'vitest';
@ -13,7 +13,6 @@ import {
loadPiece, loadPiece,
listPieces, listPieces,
loadPersonaPromptFromPath, loadPersonaPromptFromPath,
getCurrentPiece,
setCurrentPiece, setCurrentPiece,
getProjectConfigDir, getProjectConfigDir,
getBuiltinPersonasDir, getBuiltinPersonasDir,
@ -297,47 +296,6 @@ describe('loadPersonaPromptFromPath (builtin paths)', () => {
}); });
}); });
describe('getCurrentPiece', () => {
let testDir: string;
beforeEach(() => {
testDir = join(tmpdir(), `takt-test-${randomUUID()}`);
mkdirSync(testDir, { recursive: true });
});
afterEach(() => {
if (existsSync(testDir)) {
rmSync(testDir, { recursive: true, force: true });
}
});
it('should return default when no config exists', () => {
const piece = getCurrentPiece(testDir);
expect(piece).toBe('default');
});
it('should return saved piece name from config.yaml', () => {
const configDir = getProjectConfigDir(testDir);
mkdirSync(configDir, { recursive: true });
writeFileSync(join(configDir, 'config.yaml'), 'piece: default\n');
const piece = getCurrentPiece(testDir);
expect(piece).toBe('default');
});
it('should return default for empty config', () => {
const configDir = getProjectConfigDir(testDir);
mkdirSync(configDir, { recursive: true });
writeFileSync(join(configDir, 'config.yaml'), '');
const piece = getCurrentPiece(testDir);
expect(piece).toBe('default');
});
});
describe('setCurrentPiece', () => { describe('setCurrentPiece', () => {
let testDir: string; let testDir: string;
@ -373,7 +331,7 @@ describe('setCurrentPiece', () => {
setCurrentPiece(testDir, 'first'); setCurrentPiece(testDir, 'first');
setCurrentPiece(testDir, 'second'); setCurrentPiece(testDir, 'second');
const piece = getCurrentPiece(testDir); const piece = loadProjectConfig(testDir).piece;
expect(piece).toBe('second'); expect(piece).toBe('second');
}); });

View File

@ -85,7 +85,6 @@ describe('createIsolatedEnv', () => {
expect(config.language).toBe('en'); expect(config.language).toBe('en');
expect(config.log_level).toBe('info'); expect(config.log_level).toBe('info');
expect(config.default_piece).toBe('default');
expect(config.notification_sound).toBe(false); expect(config.notification_sound).toBe(false);
expect(config.notification_sound_events).toEqual({ expect(config.notification_sound_events).toEqual({
iteration_limit: false, iteration_limit: false,
@ -173,7 +172,6 @@ describe('createIsolatedEnv', () => {
[ [
'language: en', 'language: en',
'log_level: info', 'log_level: info',
'default_piece: default',
'notification_sound: true', 'notification_sound: true',
'notification_sound_events: true', 'notification_sound_events: true',
].join('\n'), ].join('\n'),

View File

@ -97,7 +97,6 @@ describe('GlobalConfig load/save with API keys', () => {
it('should load config with API keys from YAML', () => { it('should load config with API keys from YAML', () => {
const yaml = [ const yaml = [
'language: en', 'language: en',
'default_piece: default',
'log_level: info', 'log_level: info',
'provider: claude', 'provider: claude',
'anthropic_api_key: sk-ant-from-yaml', 'anthropic_api_key: sk-ant-from-yaml',
@ -113,7 +112,6 @@ describe('GlobalConfig load/save with API keys', () => {
it('should load config without API keys', () => { it('should load config without API keys', () => {
const yaml = [ const yaml = [
'language: en', 'language: en',
'default_piece: default',
'log_level: info', 'log_level: info',
'provider: claude', 'provider: claude',
].join('\n'); ].join('\n');
@ -128,7 +126,6 @@ describe('GlobalConfig load/save with API keys', () => {
// Write initial config // Write initial config
const yaml = [ const yaml = [
'language: en', 'language: en',
'default_piece: default',
'log_level: info', 'log_level: info',
'provider: claude', 'provider: claude',
].join('\n'); ].join('\n');
@ -147,7 +144,6 @@ describe('GlobalConfig load/save with API keys', () => {
it('should not persist API keys when not set', () => { it('should not persist API keys when not set', () => {
const yaml = [ const yaml = [
'language: en', 'language: en',
'default_piece: default',
'log_level: info', 'log_level: info',
'provider: claude', 'provider: claude',
].join('\n'); ].join('\n');
@ -183,7 +179,6 @@ describe('resolveAnthropicApiKey', () => {
process.env['TAKT_ANTHROPIC_API_KEY'] = 'sk-ant-from-env'; process.env['TAKT_ANTHROPIC_API_KEY'] = 'sk-ant-from-env';
const yaml = [ const yaml = [
'language: en', 'language: en',
'default_piece: default',
'log_level: info', 'log_level: info',
'provider: claude', 'provider: claude',
'anthropic_api_key: sk-ant-from-yaml', 'anthropic_api_key: sk-ant-from-yaml',
@ -198,7 +193,6 @@ describe('resolveAnthropicApiKey', () => {
delete process.env['TAKT_ANTHROPIC_API_KEY']; delete process.env['TAKT_ANTHROPIC_API_KEY'];
const yaml = [ const yaml = [
'language: en', 'language: en',
'default_piece: default',
'log_level: info', 'log_level: info',
'provider: claude', 'provider: claude',
'anthropic_api_key: sk-ant-from-yaml', 'anthropic_api_key: sk-ant-from-yaml',
@ -213,7 +207,6 @@ describe('resolveAnthropicApiKey', () => {
delete process.env['TAKT_ANTHROPIC_API_KEY']; delete process.env['TAKT_ANTHROPIC_API_KEY'];
const yaml = [ const yaml = [
'language: en', 'language: en',
'default_piece: default',
'log_level: info', 'log_level: info',
'provider: claude', 'provider: claude',
].join('\n'); ].join('\n');
@ -254,7 +247,6 @@ describe('resolveOpenaiApiKey', () => {
process.env['TAKT_OPENAI_API_KEY'] = 'sk-openai-from-env'; process.env['TAKT_OPENAI_API_KEY'] = 'sk-openai-from-env';
const yaml = [ const yaml = [
'language: en', 'language: en',
'default_piece: default',
'log_level: info', 'log_level: info',
'provider: claude', 'provider: claude',
'openai_api_key: sk-openai-from-yaml', 'openai_api_key: sk-openai-from-yaml',
@ -269,7 +261,6 @@ describe('resolveOpenaiApiKey', () => {
delete process.env['TAKT_OPENAI_API_KEY']; delete process.env['TAKT_OPENAI_API_KEY'];
const yaml = [ const yaml = [
'language: en', 'language: en',
'default_piece: default',
'log_level: info', 'log_level: info',
'provider: claude', 'provider: claude',
'openai_api_key: sk-openai-from-yaml', 'openai_api_key: sk-openai-from-yaml',
@ -284,7 +275,6 @@ describe('resolveOpenaiApiKey', () => {
delete process.env['TAKT_OPENAI_API_KEY']; delete process.env['TAKT_OPENAI_API_KEY'];
const yaml = [ const yaml = [
'language: en', 'language: en',
'default_piece: default',
'log_level: info', 'log_level: info',
'provider: claude', 'provider: claude',
].join('\n'); ].join('\n');
@ -318,7 +308,6 @@ describe('resolveCodexCliPath', () => {
process.env['TAKT_CODEX_CLI_PATH'] = envCodexPath; process.env['TAKT_CODEX_CLI_PATH'] = envCodexPath;
const yaml = [ const yaml = [
'language: en', 'language: en',
'default_piece: default',
'log_level: info', 'log_level: info',
'provider: codex', 'provider: codex',
`codex_cli_path: ${configCodexPath}`, `codex_cli_path: ${configCodexPath}`,
@ -334,7 +323,6 @@ describe('resolveCodexCliPath', () => {
const configCodexPath = createExecutableFile('config-codex'); const configCodexPath = createExecutableFile('config-codex');
const yaml = [ const yaml = [
'language: en', 'language: en',
'default_piece: default',
'log_level: info', 'log_level: info',
'provider: codex', 'provider: codex',
`codex_cli_path: ${configCodexPath}`, `codex_cli_path: ${configCodexPath}`,
@ -349,7 +337,6 @@ describe('resolveCodexCliPath', () => {
delete process.env['TAKT_CODEX_CLI_PATH']; delete process.env['TAKT_CODEX_CLI_PATH'];
const yaml = [ const yaml = [
'language: en', 'language: en',
'default_piece: default',
'log_level: info', 'log_level: info',
'provider: codex', 'provider: codex',
].join('\n'); ].join('\n');
@ -395,7 +382,6 @@ describe('resolveCodexCliPath', () => {
delete process.env['TAKT_CODEX_CLI_PATH']; delete process.env['TAKT_CODEX_CLI_PATH'];
const yaml = [ const yaml = [
'language: en', 'language: en',
'default_piece: default',
'log_level: info', 'log_level: info',
'provider: codex', 'provider: codex',
`codex_cli_path: ${join(testDir, 'missing-codex-from-config')}`, `codex_cli_path: ${join(testDir, 'missing-codex-from-config')}`,
@ -427,7 +413,6 @@ describe('resolveOpencodeApiKey', () => {
process.env['TAKT_OPENCODE_API_KEY'] = 'sk-opencode-from-env'; process.env['TAKT_OPENCODE_API_KEY'] = 'sk-opencode-from-env';
const yaml = [ const yaml = [
'language: en', 'language: en',
'default_piece: default',
'log_level: info', 'log_level: info',
'provider: claude', 'provider: claude',
'opencode_api_key: sk-opencode-from-yaml', 'opencode_api_key: sk-opencode-from-yaml',
@ -442,7 +427,6 @@ describe('resolveOpencodeApiKey', () => {
delete process.env['TAKT_OPENCODE_API_KEY']; delete process.env['TAKT_OPENCODE_API_KEY'];
const yaml = [ const yaml = [
'language: en', 'language: en',
'default_piece: default',
'log_level: info', 'log_level: info',
'provider: claude', 'provider: claude',
'opencode_api_key: sk-opencode-from-yaml', 'opencode_api_key: sk-opencode-from-yaml',
@ -457,7 +441,6 @@ describe('resolveOpencodeApiKey', () => {
delete process.env['TAKT_OPENCODE_API_KEY']; delete process.env['TAKT_OPENCODE_API_KEY'];
const yaml = [ const yaml = [
'language: en', 'language: en',
'default_piece: default',
'log_level: info', 'log_level: info',
'provider: claude', 'provider: claude',
].join('\n'); ].join('\n');

View File

@ -109,7 +109,6 @@ vi.mock('../infra/config/paths.js', async (importOriginal) => {
updatePersonaSession: vi.fn(), updatePersonaSession: vi.fn(),
loadWorktreeSessions: vi.fn().mockReturnValue({}), loadWorktreeSessions: vi.fn().mockReturnValue({}),
updateWorktreeSession: vi.fn(), updateWorktreeSession: vi.fn(),
getCurrentPiece: vi.fn().mockReturnValue('default'),
getProjectConfigDir: vi.fn().mockImplementation((cwd: string) => join(cwd, '.takt')), getProjectConfigDir: vi.fn().mockImplementation((cwd: string) => join(cwd, '.takt')),
}; };
}); });

View File

@ -91,7 +91,6 @@ vi.mock('../infra/config/paths.js', async (importOriginal) => {
updatePersonaSession: vi.fn(), updatePersonaSession: vi.fn(),
loadWorktreeSessions: vi.fn().mockReturnValue({}), loadWorktreeSessions: vi.fn().mockReturnValue({}),
updateWorktreeSession: vi.fn(), updateWorktreeSession: vi.fn(),
getCurrentPiece: vi.fn().mockReturnValue('default'),
getProjectConfigDir: vi.fn().mockImplementation((cwd: string) => join(cwd, '.takt')), getProjectConfigDir: vi.fn().mockImplementation((cwd: string) => join(cwd, '.takt')),
}; };
}); });

View File

@ -110,7 +110,6 @@ export interface GlobalConfig {
/** Project-level configuration */ /** Project-level configuration */
export interface ProjectConfig { export interface ProjectConfig {
piece?: string; piece?: string;
agents?: CustomAgentConfig[];
provider?: 'claude' | 'codex' | 'opencode' | 'mock'; provider?: 'claude' | 'codex' | 'opencode' | 'mock';
providerOptions?: MovementProviderOptions; providerOptions?: MovementProviderOptions;
/** Provider-specific permission profiles */ /** Provider-specific permission profiles */

View File

@ -468,7 +468,6 @@ export const GlobalConfigSchema = z.object({
/** Project config schema */ /** Project config schema */
export const ProjectConfigSchema = z.object({ export const ProjectConfigSchema = z.object({
piece: z.string().optional(), piece: z.string().optional(),
agents: z.array(CustomAgentConfigSchema).optional(),
provider: z.enum(['claude', 'codex', 'opencode', 'mock']).optional(), provider: z.enum(['claude', 'codex', 'opencode', 'mock']).optional(),
provider_options: MovementProviderOptionsSchema, provider_options: MovementProviderOptionsSchema,
provider_profiles: ProviderPermissionProfilesSchema, provider_profiles: ProviderPermissionProfilesSchema,

View File

@ -35,7 +35,6 @@ export {
export { export {
saveProjectConfig, saveProjectConfig,
updateProjectConfig, updateProjectConfig,
getCurrentPiece,
setCurrentPiece, setCurrentPiece,
isVerboseMode, isVerboseMode,
type ProjectLocalConfig, type ProjectLocalConfig,

View File

@ -117,7 +117,6 @@ export {
loadProjectConfig, loadProjectConfig,
saveProjectConfig, saveProjectConfig,
updateProjectConfig, updateProjectConfig,
getCurrentPiece,
setCurrentPiece, setCurrentPiece,
type ProjectLocalConfig, type ProjectLocalConfig,
} from './project/projectConfig.js'; } from './project/projectConfig.js';

View File

@ -6,7 +6,6 @@ export {
loadProjectConfig, loadProjectConfig,
saveProjectConfig, saveProjectConfig,
updateProjectConfig, updateProjectConfig,
getCurrentPiece,
setCurrentPiece, setCurrentPiece,
type ProjectLocalConfig, type ProjectLocalConfig,
} from './projectConfig.js'; } from './projectConfig.js';

View File

@ -136,14 +136,6 @@ export function updateProjectConfig<K extends keyof ProjectLocalConfig>(
saveProjectConfig(projectDir, config); saveProjectConfig(projectDir, config);
} }
/**
* Get current piece from project config
*/
export function getCurrentPiece(projectDir: string): string {
const config = loadProjectConfig(projectDir);
return config.piece || 'default';
}
/** /**
* Set current piece in project config * Set current piece in project config
*/ */

View File

@ -13,8 +13,6 @@ export interface ProjectLocalConfig {
provider?: 'claude' | 'codex' | 'opencode' | 'mock'; provider?: 'claude' | 'codex' | 'opencode' | 'mock';
/** Auto-create PR after worktree execution */ /** Auto-create PR after worktree execution */
auto_pr?: boolean; auto_pr?: boolean;
/** Auto-create PR after worktree execution (camelCase alias) */
autoPr?: boolean;
/** Verbose output mode */ /** Verbose output mode */
verbose?: boolean; verbose?: boolean;
/** Provider-specific options (overrides global, overridden by piece/movement) */ /** Provider-specific options (overrides global, overridden by piece/movement) */