Skip to content

feat: PLAN04-repos-core repos/ 永続クローン + 直接リンク install#27

Closed
takemi-ohama wants to merge 7 commits into
release/PLAN04from
feature/PLAN04-repos-core
Closed

feat: PLAN04-repos-core repos/ 永続クローン + 直接リンク install#27
takemi-ohama wants to merge 7 commits into
release/PLAN04from
feature/PLAN04-repos-core

Conversation

@takemi-ohama
Copy link
Copy Markdown
Contributor

Summary

  • plan: issues/PLAN04_plugin-repo-persistence.md
  • release PR: release: PLAN04 plugin repo persistence #26
  • repos/ ディレクトリに git clone を永続保持し、projects/ からシンボリックリンクで直接参照
  • plugins/ 中間層を廃止し、repos/ → projects/ の直接リンクに変更
  • plugin update を git pull ベースに変更
  • copy_plugin() / _sync_dir() 等のコピー系ロジックを削除

変更対象

  • models.py: RegisteredRepository.local_path 追加
  • registry.py: get_repos_dir() 追加、InstalledPlugin.path を repos/ ベースに変更
  • repo_manager.py: 永続クローン、git pull refresh、dirty check 付き remove
  • installer.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 対応
  • 同名プロジェクト衝突 → suffix 付きリンク
  • --link インストール → 従来動作維持

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 takemi-ohama marked this pull request as ready for review May 27, 2026 14:17
Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 1 | gemini | REQUEST_CHANGES

プラグイン管理の永続クローン化と直接リンクへの移行における、パス計算の致命的なバグと、リポジトリ削除時の dirty 検知の堅牢性に関する修正が必要です。

Comment thread lib/devbase/plugin/installer.py
Comment thread lib/devbase/plugin/updater.py Outdated
Comment thread lib/devbase/plugin/repo_manager.py
)
sync_projects(registry)
else:
print(f"Available plugins in {source.repo}:")
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[minor / 設計] _install_from_repo 内で直接 print を使用していますが、ライブラリとしての利用を考慮し、情報は PluginError のメッセージに含めるか、呼び出し側で表示を制御できるようにすべきです。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[deferred / minor] 後続 PR で対応予定。現状 print はプラグイン一覧表示の CLI 出力であり、直後に PluginError を raise しているため実害は限定的。logger 統一は今後のリファクタリングで検討します。

Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 1 | codex | REQUEST_CHANGES

repos/ 直リンク化で registry.ymlpath と衝突名の一意性を永続 metadata に反映できていないため、サブディレクトリ配置や同一 owner 複数 repo のケースを修正してください。

Comment thread lib/devbase/plugin/installer.py Outdated
Comment thread lib/devbase/plugin/updater.py Outdated
Comment thread lib/devbase/plugin/repo_manager.py Outdated
Comment thread lib/devbase/plugin/syncer.py
- 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>
@takemi-ohama
Copy link
Copy Markdown
Contributor Author

/ndf:fix サマリ (round 1)

対応件数: critical=0 / major=6 / minor=1 (合計 7 件)
deferred: 1 件 / rejected: 0 件
commit: 59fc306
CI: NONE (CI 未設定)

詳細

修正済み (7 件 — 4 ユニーク指摘 + 3 重複):

# ファイル 重要度 内容 元指摘
1 installer.py:283 major _register_repo_pluginrel_pathplugin_path.relative_to(devbase_root) に変更。サブディレクトリ配置の plugin パスが正しく保存される gemini + codex (重複)
2 updater.py:177 major 同上の修正を updater 側にも適用 gemini + codex (重複)
3 repo_manager.py:75-86 major @{u} upstream 未設定時に dirty=false となりデータ損失の恐れ。upstream 未設定時は dirty 扱いに変更 gemini (minor→major 再判定) + codex (重複)
4 syncer.py:149 major collision suffix を owner のみ → owner--repo に変更し、同一 owner 複数 repo の衝突を解消。既存 symlink 存在チェックも追加 codex

deferred (1 件):

# ファイル 重要度 内容
1 installer.py:260 minor/設計 _install_from_repo 内の print を logger に統一 — CLI 出力であり実害は限定的。後続リファクタリング PR で対応予定

テスト: 全 210 件 PASSED (0 failures)

Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 2 | codex | REQUEST_CHANGES

repos/ の永続 clone を直接参照する変更により、repo 単位の pull と plugin 単位の registry 状態がずれる経路があります。下記の修正が必要です。

Comment thread lib/devbase/plugin/updater.py
Comment thread lib/devbase/plugin/updater.py
Comment thread lib/devbase/plugin/repo_manager.py Outdated
Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 2 | gemini | APPROVE

設計通り repos/ への永続クローンと symlink によるインストールへの移行が適切に実装されています。
remove 時の dirty 検知や、sync 時の衝突回避策(リポジトリ名ベースのサフィックス付与)など、エッジケースへの配慮も十分です。

Comment thread lib/devbase/plugin/syncer.py Outdated
- 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>
@takemi-ohama
Copy link
Copy Markdown
Contributor Author

/ndf:fix サマリ (round 2)

対応件数: critical=0 / major=2 / minor=2 (合計 4 件)
deferred: 0 件 / rejected: 0 件
commit: 3cc7716
CI: NONE (CI 未設定)

詳細

修正済み (4 件):

# ファイル 重要度 内容 元指摘
1 updater.py:145 major git pull 前に _snapshot_plugin_projects() で旧 projects をスナップショット。pull 後の migration で旧ディレクトリが消えても移行先を検出可能に codex (round 2)
2 updater.py:149 major _update_repo_plugins() を追加し、pull 後に同一 repo の全 installed plugin の metadata を一括再読み込み。name 指定 update でも他 plugin の version/path が正しく同期される codex (round 2)
3 repo_manager.py:162 minor clone 後の registry.yml parse / 名前衝突失敗時に clone_dir を自動削除。リトライ時の "Directory already exists" を解消 codex (round 2)
4 syncer.py:53 nit (minor→nit 再判定) plugin.path.split('/')Path(plugin.path).parts に変更 (OS 非依存化) codex (round 2)

deferred (round 1 から継続: 1 件):

# ファイル 重要度 内容
1 installer.py:260 minor/設計 _install_from_repo 内の print を logger に統一 — CLI 出力であり実害は限定的。後続リファクタリング PR で対応予定

テスト: 全 210 件 PASSED (0 failures)

Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 3 | codex | REQUEST_CHANGES

直接指定 install の既存サポートを維持するか廃止するかを実装・ドキュメント・テストで揃えてください。

Comment thread lib/devbase/plugin/installer.py Outdated
Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 3 | gemini | APPROVE

リポジトリ全体の更新同期や、git pull 前のスナップショットによる移行ロジックの改善など、設計意図通りに実装されています。クローン失敗時のクリーンアップも追加されており、堅牢性が向上しています。いくつか軽微な改善提案がありますが、全体としてマージ可能な状態と判断します。

Comment thread lib/devbase/plugin/updater.py
Comment thread lib/devbase/plugin/repo_manager.py
- 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>
@takemi-ohama
Copy link
Copy Markdown
Contributor Author

/ndf:fix サマリ (round 3)

対応件数: critical=0 / major=1 / minor=2 (合計 3 件)
deferred: 1 件 (round 1 から継続) / rejected: 0 件
commit: 5f3d44d
CI: NONE (CI 未設定)

詳細

修正済み (3 件):

# ファイル 重要度 内容 元指摘
1 installer.py:115 major / 互換性 user/repo:plugin-name 形式で未登録リポジトリを指定した際に自動で repo add を実行し、既存の直接指定形式を維持。自動登録失敗時は明示的エラーメッセージで案内 codex (round 3)
2 updater.py:123 minor / cleanup _update_repo_plugins の未使用引数 repo_local_path を削除 gemini (round 3)
3 repo_manager.py:157 minor / 正確性 git_clone を try/except ブロック内に移動し、部分 clone 失敗時もディレクトリを自動クリーンアップ gemini (round 3)

deferred (round 1 から継続: 1 件):

# ファイル 重要度 内容
1 installer.py:260 minor / 設計 _install_from_repo 内の print を logger に統一 — CLI 出力であり実害は限定的。後続リファクタリング PR で対応予定

テスト: 全 210 件 PASSED (0 failures)

Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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.

Comment thread lib/devbase/plugin/repo_manager.py
)

# Resolve repo URL
repo_url = resolve_repo_url(source.repo)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[minor / ユーザビリティ] resolve_repo_url は shorthands を HTTPS URL に変換しますが、既に同じリポジトリが SSH (git@...) で登録されている場合、add_repository でディレクトリ衝突が発生します。
実害は少ないですが、同一リポジトリの別形式での重複登録を許容するか、警告を出すなどの検討の余地があります。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[deferred / nit] nit として据え置き。_url_to_repos_dirname が URL 正規化後の owner/repo からディレクトリ名を生成するため、SSH と HTTPS で同一リポジトリを指す場合でもディレクトリ名は一致します(例: devbasex--devbase-samples)。URL 形式が全く異なるケース(カスタム Git サーバ等)では理論上衝突の可能性がありますが、実用上は極めて稀であり、現状の Directory already exists エラーで十分対処可能と判断します。

Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 4 | codex | REQUEST_CHANGES

永続 clone 化により、ref 指定インストールと repo refresh 後の installed plugin メタデータ同期に修正が必要です。

Comment thread lib/devbase/plugin/installer.py
Comment thread lib/devbase/plugin/repo_manager.py
- 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>
@takemi-ohama
Copy link
Copy Markdown
Contributor Author

/ndf:fix サマリ (round 4)

対応件数: critical=0 / major=2 / minor=1 (合計 3 件)
deferred: 2 件 / rejected: 0 件
commit: 6fef35d
CI: NONE (CI 未設定)

詳細

修正済み (3 件):

# ファイル 重要度 内容 元指摘
1 installer.py:128 major / 正確性 未登録リポジトリの自動登録時に @ref を明示的に拒否。永続 clone はデフォルトブランチを追跡する設計のため、pinned ref と矛盾する。エラーメッセージで repo addinstall の手順を案内 codex (round 4)
2 repo_manager.py:347 major / 正確性 refresh_repository で git pull 後に _update_repo_plugins() + sync_projects() を呼び出し、installed plugin の metadata (version/path) と projects/ symlink を再同期 codex (round 4)
3 repo_manager.py:117 minor / 堅牢性 _git_pull で upstream tracking branch の有無を事前検査。未設定時に現在のブランチ名と --set-upstream-to コマンド例を含むエラーメッセージを返す gemini (round 4)

deferred (2 件):

# ファイル 重要度 内容
1 installer.py:273 nit / 設計 _install_from_repo 内の print を logger に統一 — CLI 出力であり実害は限定的。後続リファクタリング PR で対応予定 (round 1 から継続)
2 installer.py:115 nit / ユーザビリティ SSH/HTTPS 形式の重複登録検知 — _url_to_repos_dirname の正規化で同一 owner/repo は一致するため実害は極めて稀。Directory already exists で対処可能

テスト: 全 210 件 PASSED (0 failures)

Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 5 | gemini | REQUEST_CHANGES

auto-registration 時の例外処理における変数名の誤り(NameError)や、git pull 失敗時のエラーメッセージの不備など、修正が必要な箇所がいくつか見つかりました。

Comment thread lib/devbase/plugin/installer.py Outdated
Comment thread lib/devbase/plugin/repo_manager.py Outdated
Comment thread lib/devbase/plugin/repo_manager.py Outdated
Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 5 | codex | REQUEST_CHANGES

永続 clone 化に伴う移行経路とエラー経路に、実行時失敗につながる修正点があります。

Comment thread lib/devbase/plugin/installer.py Outdated
Comment thread lib/devbase/plugin/installer.py Outdated
…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
Copy link
Copy Markdown
Contributor Author

/ndf:fix サマリ (round 5)

対応件数: critical=1 / major=3 / minor=1 (合計 5 件)
deferred: 2 件 (round 4 から継続) / rejected: 0 件
commit: 99bd8f6
CI: NONE (CI 未設定)

詳細

修正済み (5 件 — 3 ユニーク指摘 + 2 重複):

# ファイル 重要度 内容 元指摘
1 installer.py:131 critical / 正確性 @ref 拒否パスで未定義変数 urlrepo_url に修正 (NameError 解消)。テスト追加 gemini (critical) + codex (major, 重複)
2 repo_manager.py:133 major / 正確性 _git_pull の upstream 未設定エラーを 3 パターンに分離: detached HEAD / remote 未設定 / upstream 未設定。remote 名を git remote で動的取得し origin 固定を解消 gemini
3 installer.py:223 major / 互換性 legacy repo (local_path 未設定) の自動移行: 初回 install 時に永続 clone を作成して local_path を設定。テスト追加 codex
4 repo_manager.py:379 minor / 効率性 refresh_repositorysync パラメータ追加。batch refresh 時は sync=False で呼び出し、ループ後に 1 回だけ sync_projects 実行 gemini

deferred (round 4 から継続: 2 件):

# ファイル 重要度 内容
1 installer.py:273 nit / 設計 _install_from_repo 内の print を logger に統一 — CLI 出力であり実害は限定的。後続リファクタリング PR で対応予定
2 installer.py:115 nit / ユーザビリティ SSH/HTTPS 形式の重複登録検知 — URL 正規化で同一リポジトリは一致するため実害は極めて稀

テスト: 全 212 件 PASSED (0 failures)

@takemi-ohama
Copy link
Copy Markdown
Contributor Author

ℹ️ レビューコメント履歴整理のため本 PR を一度 close し、同じブランチ feature/PLAN04-repos-core で新 PR を作り直します。ブランチの内容・base は変えません。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant