feat: PLAN04-repos-core repos/ 永続クローン + 直接リンク install#27
Conversation
plugins/ 中間層を廃止し、repos/ に git clone を永続保持して projects/ からシンボリックリンクで直接参照する構造に変更。 - models.py: RegisteredRepository に local_path フィールド追加 - registry.py: get_repos_dir() 追加 - repo_manager.py: repos/ 永続クローン、git pull refresh、dirty check 付き remove - installer.py: repos/ ベースのシンボリックリンク install、repos/ 保護 uninstall、 copy_plugin / _sync_dir 等のコピー系ロジック削除 - syncer.py: InstalledPlugin.path ベース走査、同名衝突時の .<owner> suffix リンク - updater.py: git pull ベース update - cli.py: repo remove に --force オプション追加 - .gitignore: repos/ 追加 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 1 | gemini | REQUEST_CHANGES
プラグイン管理の永続クローン化と直接リンクへの移行における、パス計算の致命的なバグと、リポジトリ削除時の dirty 検知の堅牢性に関する修正が必要です。
| ) | ||
| sync_projects(registry) | ||
| else: | ||
| print(f"Available plugins in {source.repo}:") |
There was a problem hiding this comment.
[minor / 設計] _install_from_repo 内で直接 print を使用していますが、ライブラリとしての利用を考慮し、情報は PluginError のメッセージに含めるか、呼び出し側で表示を制御できるようにすべきです。
There was a problem hiding this comment.
[deferred / minor] 後続 PR で対応予定。現状 print はプラグイン一覧表示の CLI 出力であり、直後に PluginError を raise しているため実害は限定的。logger 統一は今後のリファクタリングで検討します。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 1 | codex | REQUEST_CHANGES
repos/ 直リンク化で registry.yml の path と衝突名の一意性を永続 metadata に反映できていないため、サブディレクトリ配置や同一 owner 複数 repo のケースを修正してください。
- installer.py / updater.py: rel_path を plugin名ではなく
plugin_path.relative_to(devbase_root) で算出し、
registry.yml の path が name と異なるサブディレクトリ配置に対応
- repo_manager.py: upstream未設定時に @{u}..HEAD が失敗して
dirty=false となりデータ損失の恐れがあった問題を修正。
upstream未設定時は dirty 扱いにして安全側に倒す
- syncer.py: collision suffix を owner のみ → owner--repo に変更し、
同一 owner の複数 repo で同名 project が衝突する問題を修正。
既存 symlink 存在チェックも追加
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
/ndf:fix サマリ (round 1)対応件数: critical=0 / major=6 / minor=1 (合計 7 件) 詳細修正済み (7 件 — 4 ユニーク指摘 + 3 重複):
deferred (1 件):
テスト: 全 210 件 PASSED (0 failures) |
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 2 | codex | REQUEST_CHANGES
repos/ の永続 clone を直接参照する変更により、repo 単位の pull と plugin 単位の registry 状態がずれる経路があります。下記の修正が必要です。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 2 | gemini | APPROVE
設計通り repos/ への永続クローンと symlink によるインストールへの移行が適切に実装されています。
remove 時の dirty 検知や、sync 時の衝突回避策(リポジトリ名ベースのサフィックス付与)など、エッジケースへの配慮も十分です。
- updater: git pull 前に旧 plugin の projects をスナップショットし、
pull 後の migration で旧ディレクトリが消えても移行先を検出可能に
- updater: name 指定の update でも同一 repo の全 installed plugin の
metadata (version/path) を pull 後に再読み込みして整合性を維持
- repo_manager: repo add で clone 後の registry.yml parse や名前衝突
失敗時に clone_dir を自動削除し、リトライ時の詰まりを防止
- syncer: path.split('/') を Path().parts に変更 (OS 非依存化)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
/ndf:fix サマリ (round 2)対応件数: critical=0 / major=2 / minor=2 (合計 4 件) 詳細修正済み (4 件):
deferred (round 1 から継続: 1 件):
テスト: 全 210 件 PASSED (0 failures) |
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 3 | codex | REQUEST_CHANGES
直接指定 install の既存サポートを維持するか廃止するかを実装・ドキュメント・テストで揃えてください。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 3 | gemini | APPROVE
リポジトリ全体の更新同期や、git pull 前のスナップショットによる移行ロジックの改善など、設計意図通りに実装されています。クローン失敗時のクリーンアップも追加されており、堅牢性が向上しています。いくつか軽微な改善提案がありますが、全体としてマージ可能な状態と判断します。
- installer.py: user/repo:plugin-name 形式で未登録リポジトリを指定した際に 自動で repo add を実行し、既存の直接指定形式を維持 (codex round 3 major) - updater.py: _update_repo_plugins の未使用引数 repo_local_path を削除 (gemini round 3 minor) - repo_manager.py: git_clone を try/except ブロック内に移動し、 部分 clone 失敗時もディレクトリを自動クリーンアップ (gemini round 3 minor) 全 210 テスト PASSED Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
/ndf:fix サマリ (round 3)対応件数: critical=0 / major=1 / minor=2 (合計 3 件) 詳細修正済み (3 件):
deferred (round 1 から継続: 1 件):
テスト: 全 210 件 PASSED (0 failures) |
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 4 | gemini | APPROVE
Transition to persistent clones in repos/ is a solid architectural improvement. The auto-registration UX and collision resolution in syncer (suffixing projects) are well-implemented. Safety checks for dirty repositories and robust migration logic significantly improve the system's reliability.
| ) | ||
|
|
||
| # Resolve repo URL | ||
| repo_url = resolve_repo_url(source.repo) |
There was a problem hiding this comment.
[minor / ユーザビリティ] resolve_repo_url は shorthands を HTTPS URL に変換しますが、既に同じリポジトリが SSH (git@...) で登録されている場合、add_repository でディレクトリ衝突が発生します。
実害は少ないですが、同一リポジトリの別形式での重複登録を許容するか、警告を出すなどの検討の余地があります。
There was a problem hiding this comment.
[deferred / nit] nit として据え置き。_url_to_repos_dirname が URL 正規化後の owner/repo からディレクトリ名を生成するため、SSH と HTTPS で同一リポジトリを指す場合でもディレクトリ名は一致します(例: devbasex--devbase-samples)。URL 形式が全く異なるケース(カスタム Git サーバ等)では理論上衝突の可能性がありますが、実用上は極めて稀であり、現状の Directory already exists エラーで十分対処可能と判断します。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 4 | codex | REQUEST_CHANGES
永続 clone 化により、ref 指定インストールと repo refresh 後の installed plugin メタデータ同期に修正が必要です。
- installer.py: 未登録リポジトリの自動登録時に @ref を明示的に拒否 (永続 clone はデフォルトブランチを追跡するため、pinned ref と矛盾する) - repo_manager.py: refresh_repository で git pull 後に installed plugin の metadata (version/path) を再計算し sync_projects() を実行 - repo_manager.py: _git_pull で upstream tracking branch の有無を事前検査し、 未設定時に具体的な修正手順を含むエラーメッセージを返す Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
/ndf:fix サマリ (round 4)対応件数: critical=0 / major=2 / minor=1 (合計 3 件) 詳細修正済み (3 件):
deferred (2 件):
テスト: 全 210 件 PASSED (0 failures) |
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 5 | gemini | REQUEST_CHANGES
auto-registration 時の例外処理における変数名の誤り(NameError)や、git pull 失敗時のエラーメッセージの不備など、修正が必要な箇所がいくつか見つかりました。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 5 | codex | REQUEST_CHANGES
永続 clone 化に伴う移行経路とエラー経路に、実行時失敗につながる修正点があります。
…ch refresh効率化 - installer.py:131 — @ref 拒否時の未定義変数 `url` を `repo_url` に修正 (NameError 解消) - repo_manager.py:133 — _git_pull の upstream 未設定エラーで detached HEAD/remote未設定を個別判定、remote名を動的取得 - repo_manager.py:379 — refresh_repository に sync パラメータ追加、batch refresh 時は最後に1回だけ sync_projects 実行 - installer.py:223 — legacy repo (local_path 未設定) の自動移行: 初回 install 時に永続 clone を作成して local_path を設定 - テスト追加: @ref 拒否の PluginError テスト、legacy repo migration テスト (計 212 tests PASSED) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
/ndf:fix サマリ (round 5)対応件数: critical=1 / major=3 / minor=1 (合計 5 件) 詳細修正済み (5 件 — 3 ユニーク指摘 + 2 重複):
deferred (round 4 から継続: 2 件):
テスト: 全 212 件 PASSED (0 failures) |
|
ℹ️ レビューコメント履歴整理のため本 PR を一度 close し、同じブランチ |
Summary
変更対象
models.py: RegisteredRepository.local_path 追加registry.py: get_repos_dir() 追加、InstalledPlugin.path を repos/ ベースに変更repo_manager.py: 永続クローン、git pull refresh、dirty check 付き removeinstaller.py: シンボリックリンク install、repos/ 保護 uninstall、copy_plugin 削除syncer.py: InstalledPlugin.path ベース走査、suffix 付き衝突解決updater.py: git pull ベース update.gitignore: repos/ 追加Test plan
repo add→ repos/ に full clone 作成plugin install→ projects/ から repos/ への直接リンクplugin update→ git pull 実行plugin uninstall→ リンク削除のみ、repos/ 保護repo remove→ dirty check + --force 対応