feat(plugin): repos/ 永続クローンによるプラグイン管理と projects/ 直接シンボリックリンク#29
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>
- 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>
- 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>
- 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>
- 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>
…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>
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 6 | gemini | REQUEST_CHANGES
NameErrorの修正、detached HEAD/upstream未設定時のエラーメッセージ改善、およびバッチ処理の高速化を確認しました。レガシーリポジトリの自動移行ロジックにおいて、移行時にリポジトリ内のプラグインリスト(cache)が更新されない点などの改善を提案します。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 6 | codex | REQUEST_CHANGES
レガシーrepo移行は、clone内容の検証が完了するまで plugins.yml を更新しないようにしてください。
- installer.py: レガシーrepo移行時に parse_registry_yml で検証してから plugins.yml へ保存するように変更。plugins リストも registry.yml から 最新情報を取得して更新 (major x2 対応) - repo_manager.py: 複数リモート時に origin を優先選択 (minor) - repo_manager.py: detached HEAD エラーに具体的な復帰コマンド例を追加 (minor) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fix summary (round 6 review)commit: e5ed764 修正内容
テスト全 212 テスト PASS (既存テスト + PLAN04 テスト 42件) |
- installer.py: _install_from_repo 内の print() を logger.info() に統一 - repo_manager.py: add_repository で SSH/HTTPS 形式の URL バリアント重複を _url_to_repos_dirname 正規化により検知し、RepositoryError で拒否 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
deferred nit 対応 (commit 49e5f82)対応: 2件 (minor: 1, nit: 1) 修正内容
テスト結果
|
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 1 | codex | REQUEST_CHANGES
永続 clone を基準にした install/refresh で、ユーザー指定 ref と repo URL の識別、refresh 時の rename migration が壊れないようにしてください。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 1 | gemini | REQUEST_CHANGES
永続クローン方式への移行により、インストールや更新の効率が向上していることを確認しました。一方で、マイグレーション時のスナップショット欠如や、登録済みリポジトリにおける @ref 指定の扱いについて、いくつか改善が必要な点があります。
…・print→logger・migration テスト - 登録済みrepoへの @ref 指定を PluginError で拒否(codex + gemini 指摘) - _url_to_repos_dirname に host を含め、異なるホストの同名 repo の衝突を防止 - refresh_repository で git pull 前に _snapshot_plugin_projects を取得し _update_repo_plugins に渡すことで、pull 後のディレクトリ変更時も移行可能に - repo_manager.py の残存 print() を logger.info() に統一 - _migrate_removed_plugin / _snapshot_plugin_projects のテスト追加(3件) - refresh の pre_pull_projects 受け渡し検証テスト追加 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fix summary (round 1 review)commit: ebb33e0 修正内容
テスト結果全 221 テスト PASS (前回 212 + 新規 9件)
|
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 2 | gemini | APPROVE
リポジトリディレクトリ名の衝突回避(hostname 追加)、および git pull 時のプラグイン移行ロジックの改善を確認しました。
_url_to_repos_dirnameへの host 追加により、異なるホストの同名 repo の衝突が防止されています。既存のlocal_pathを持つレポジトリの互換性も維持されています。refresh_repositoryにおけるpre_pull_projectsのスナップショット取得により、リポジトリ構成変更を伴う更新時でも、インストール済みプロジェクトの追跡と移行が確実に行われるようになっています。- detached HEAD や upstream 未設定時のエラーメッセージ改善、および
@ref指定の適切な拒否により、UX が向上しています。
全テストのパスを確認しました。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 2 | codex | APPROVE
修正が必要な新規指摘はありません。
何のために
プラグインの install / update / uninstall フローにおいて、従来の plugins/ 中間コピー方式には以下の課題があった:
plugin updateのたびにファイルコピーが走り、変更差分が不透明これを解消するため、repos/ にリポジトリの永続クローンを保持し、projects/ から repos/ 内のプラグインディレクトリへ直接シンボリックリンクを張る方式に移行する。
何を
repos/ 永続クローンの導入
repo addで repos/ 配下に full clone を作成・永続保持 (owner--repo形式のディレクトリ名)repo refreshで既存クローンを git pull して registry.yml メタデータを同期repo removeで dirty check (uncommitted changes / unpushed commits) を行い、--forceなしでは削除をブロックprojects/ 直接シンボリックリンク install
plugin installで repos/ 内のプラグインディレクトリから projects/ へ直接シンボリックリンクを作成copy_plugin()/_sync_dir()等のコピー系ロジックを削除@ref指定は未登録リポジトリに対して拒否し、明示的なrepo addを要求git pull ベースの update
plugin updateを git pull ベースに変更 — clone し直しではなく差分取得シンボリックリンク同期の改善
--linkベースの両方式に対応した相対パスリンク生成<project>.<owner--repo>suffix 付きリンクで解決その他
RegisteredRepository.local_pathフィールド追加 (repos/ 内のクローンパス管理)PluginRegistry.get_repos_dir()追加.gitignoreにrepos/を追加tests/plugin/test_repos_core.py)Test plan
repo add→ repos/ に full clone が作成されるplugin install→ projects/ から repos/ への直接シンボリックリンクが作成されるplugin update→ git pull で差分取得されるplugin uninstall→ シンボリックリンクのみ削除、repos/ のクローンは残るrepo remove→ dirty check が動作し、--forceで強制削除できる--linkインストール → 従来の local symlink 動作を維持@ref付き install で未登録リポジトリ → エラーメッセージでrepo addを案内