yoi/tickets/manifest-path-resolution.md

87 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Manifest のパス解決: cwd ベース + manifest ファイル相対
レビュー中: [manifest-path-resolution.review.md](manifest-path-resolution.review.md)
## 背景
現状 manifest 内のパス(`pod.pwd` / `provider.api_key_file` / `scope.allow.target` / `scope.deny.target` / `compaction.provider.api_key_file`)は全て絶対必須で、相対パスは `ResolveError::RelativePath` で弾かれる。
これは 4 層builtin / user / project / overlayのカスケードで「相対の基準点が層ごとに違う」曖昧さを避けるための制約だったが、次の点で歪みを生んでいる
- `pod.pwd` フィールドが Unix 慣習cwd はプロセス状態、config には書かない)と乖離
- project manifest で `scope.allow = [{ target = "<repo>" }]` のような絶対パスを強いられ、プロジェクトをどこに置いても動くはずの設定が壊れる
- user manifest で `api_key_file = "~/.config/insomnia/keys/anthropic"` が書けない(`~` 展開もしていない)
cargo / pyproject / npm などに倣い「相対パスは manifest ファイルの位置基準」に切り替える。合わせて `pod.pwd` を廃止し、プロセスの cwd を使う。
## 新しい解決規則
- `pod.pwd` フィールドは削除。Pod の作業ディレクトリ = プロセスの cwd
- 相対パスの基準は層ごとに決める
- user manifest (`~/.config/insomnia/manifest.toml`) の相対 = そのファイルの親ディレクトリ
- project manifest (`<project>/.insomnia/manifest.toml`) の相対 = **プロジェクトルート**`.insomnia/` の親)。`target = "."` がワークスペース全体を指すように
- overlayインライン TOML、ファイル位置なしの相対パスは **プロセスの cwd** 基準
- builtin 層には manifest を埋め込んでいないので対象外
## 解決のタイミング
各層を**マージする前に絶対化**する。層をまたいだ相対パス合成は行わない。
```
user.toml (partial) → resolve_paths(base=user_dir) → absolute partial
project.toml (partial) → resolve_paths(base=prj_dir) ─┤
│── merge → PodManifestConfig
overlay (partial) → resolve_paths(base=cwd) ──────────┤
builtin defaults → ────────────────────────────────── ┘
```
`TryFrom<PodManifestConfig>` の時点では全パスが絶対になっているので、`ensure_absolute` は不変条件のチェックとしてのみ残す。
## 影響範囲
### `crates/manifest`
- `PodManifestConfig` から `pod.pwd` を削除
- 各 partial config を「ベースパス付き」で解決するヘルパーを追加(関数シグネチャ案: `fn resolve_partial(cfg: PodManifestConfigPartial, base: &Path) -> PodManifestConfigPartial`
- 対象フィールド: `provider.api_key_file` / `scope.allow.target` / `scope.deny.target` / `compaction.provider.api_key_file`
### `crates/pod/src/factory.rs`
- `with_user_manifest` / `with_project_manifest_from` は渡された manifest ファイルの親ディレクトリを base として保存、解決時に使う
- `with_overlay_toml` / `with_overlay_config` はプロセス cwd を base として使う
- マージ順は現状のままoverlay が最優先)
### `crates/pod/src/pod.rs` 他
- `pod.pwd` を参照している箇所を `std::env::current_dir()` に置き換え
- `Pod::from_manifest` / `from_manifest_spawned` のシグネチャから pwd 関連を削除
### `crates/pod/src/spawn_pod.rs`
- overlay TOML 構築から `pod.pwd` を消す
- 子プロセス起動時に `Command::current_dir(spawner_pwd)` で cwd を明示
現状の「spawner の pwd を子に引き継ぐ」挙動を維持するため)
- 将来、LLM が子の cwd を明示的に指定したくなったら `SpawnPod` の入力に `cwd` を足す(本チケット範囲外)
### `crates/pod/src/main.rs`
- `--pwd` フラグは削除cwd が代替)
- 起動スクリプトや TUI 側で `cd` してから `pod` を起動する運用に変更
## 完了条件
- `pod.pwd` フィールドの削除
- 各層のパスが manifest ファイル基準overlay は cwd 基準)で解決される
- マージは絶対化後の値で行う
- 既存テストが通る / 相対パスを使った manifest で起動可能
- `api_key_file = "keys/anthropic"` が user manifest 内で動作
- project manifest で `scope.allow = [{ target = "." }]` が動作
## 範囲外
- `~` 展開(`dirs::home_dir()` ベースの展開は別途。まずは `./keys/anthropic` のような単純相対のみ)
- `SpawnPod` の入力に子 cwd の指定を追加cwd 明示は別チケット)
- `pod` CLI の `--pwd` 廃止後の移行期間対応(一発破壊的変更で行く)