Skip to content

release: PLAN04 plugin repo persistence#26

Merged
takemi-ohama merged 8 commits into
mainfrom
release/PLAN04
May 28, 2026
Merged

release: PLAN04 plugin repo persistence#26
takemi-ohama merged 8 commits into
mainfrom
release/PLAN04

Conversation

@takemi-ohama
Copy link
Copy Markdown
Contributor

@takemi-ohama takemi-ohama commented May 27, 2026

Summary

  • plan: issues/PLAN04_plugin-repo-persistence.md
  • repos/ ディレクトリに git clone を永続保持し、projects/ からシンボリックリンクで直接参照する構造に変更
  • 複数 PR を統合する release ブランチ

個別 PR

Test plan (結合観点のみ)

  • PR1 + PR2 統合後に repo addplugin installprojects/ リンク → devbase up の E2E 動作
  • 既存 plugins/ ベースインストール → マイグレーション → repos/ ベース動作の通し確認

* chore: PLAN04-repos-core Draft PR 作成

* feat(plugin): repos/ 永続クローン + 直接リンク install (PLAN04-repos-core)

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>

* fix(plugin): サブディレクトリ配置・dirty検知・suffix衝突の3件修正

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

* fix(plugin): pull前スナップショット・repo全体更新・clone失敗クリーンアップ

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

* fix(plugin): round 3 レビュー指摘対応 — 直接 install の自動 repo 登録 + cleanup

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

* fix(plugin): round 4 レビュー指摘対応 — @ref 拒否・refresh メタデータ同期・pull エラー改善

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

* fix(plugin): round 5 レビュー指摘対応 — NameError修正・エラーメッセージ改善・レガシーrepo移行・batch 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>

* fix(plugin): レガシー移行時の整合性修正 + UX改善 (round 6 review)

- 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(plugin): print→logger 統一 + SSH/HTTPS URL 重複登録検知 (deferred nit)

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

* fix(plugin): round 1 レビュー指摘対応 — @ref拒否・host付きdirname・refresh snapshot・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>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… migrate を追加 (#31)

* chore: PLAN04-migration Draft PR 作成

* feat(plugin): 既存 plugins/ コピーインストールを repos/ 永続クローンへ移行

PLAN04 PR2。PR1 (#29) で repos/ 永続クローン方式に切り替えたが、PR1 以前に
plugins/<name>/ へファイルコピーされた既存インストールは移行されないため、その
移行ロジックを追加する。

- migrator.py (新規):
  - needs_migration / _is_legacy_plugin: legacy plugins/ インストールの検出
    (linked は --link 専用として除外)
  - _dirs_differ: コピーとクローンの差分検出 (内容変更・追加ファイルを保守的に差分扱い)
  - migrate: 未クローン repo の永続クローン作成、InstalledPlugin.path の repos/ 書き換え、
    差分なしは plugins/<name> 削除・差分ありは <name>.bak 保全、sync_projects 再実行、
    --link/.bak/skip が無ければ plugins/ を .gitkeep のみに正規化
- plugin migrate サブコマンド (cli.py / commands/plugin.py)
- install/update 初回実行時に _auto_migrate で自動移行

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(plugin): migration の symlink 差分検知漏れ / .bak 上書き / registry 先行更新を修正

cross-review round 1 の major 指摘 4 件 (codex 2 / gemini 2) に対応。

- _dirs_differ: regular file のみ比較していたため legacy copy のみに存在する
  symlink / 空ディレクトリ / 型不一致を差分として検知できず、後続の
  shutil.rmtree で silently 削除される恐れがあった。全エントリを対象に
  型 + 内容 (file は byte, symlink は target) を比較するよう厳密化
- _unique_bak_path: 既存の <name>.bak を無条件に rmtree していたため、
  前回 migration で保全した未整理バックアップが消失する恐れがあった。
  存在時は .bak-2, .bak-3 ... と一意名に退避するよう変更
- migrate: filesystem の退避/削除が成功してから registry.add で
  plugins.yml を repos/ path に書き換えるよう順序を入れ替え。失敗時に
  registry だけ先行更新され retry も効かなくなる partial state を防止
- _cleanup_plugins_dir: .bak-N 形式も保全 .bak として検知するよう調整
- 上記挙動を網羅するテスト 6 件追加

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(plugin): migration の差分判定厳密化 / partial clone 復旧 / cleanup 報告修正

cross-review round 2 の指摘対応。

- _dirs_differ: upstream 専用追加 (clone にのみ存在) を差分扱いしないよう
  変更。コピー側にのみ存在するエントリ・共通エントリの型/target/内容差分の
  みを preserved 判定に使い、通常の upstream 更新で不要な .bak 退避が発生
  しないようにした (codex#91 / gemini#91 重複指摘)。
- _files_equal: read_bytes() の全読み込みを 64KB チャンクのストリーム比較に
  置き換え、巨大ファイルでのメモリ枯渇リスクを排除 (gemini#105)。
- _ensure_repo_cloned: 前回 clone 失敗で残った partial dir (.git 無し /
  registry.yml 不正) を検知して削除・再 clone するよう修正。無限に
  parse 失敗を繰り返す経路を解消 (codex#132)。
- _cleanup_plugins_dir: .gitkeep でも .bak でもない想定外エントリが残る場合
  は cleaned=True と報告せず False を返すよう修正 (gemini#176)。
- docs: devbase plugin migrate の CLI リファレンスを追加 (codex review body)。

テスト 4 件追加 (upstream 専用追加は差分なし / 同サイズ内容差 / partial
clone 再 clone / cleanup の想定外エントリ保持)。全 252 件 pass。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(plugin): migration の保全判定・clone 健全性・registry 保存効率を改善 (PR2 round3)

cross-review round 3 の指摘に対応:

- _cleanup_plugins_dir の `.bak` 判定を `'.bak' in name` から
  `<name>.bak[-N]` 末尾一致 (_is_bak_name) に修正。my.bakery 等の誤マッチを排除
- migrate ループ内の per-plugin `registry.add` を loop 末尾の単一
  `registry.add_many` に集約し plugins.yml の保存頻発を解消
  (各 plugin の fs 移動と entry 構築は同一 try 内のため失敗時の retry 性は維持)
- _ensure_repo_cloned で local_path 設定済みでも .git/registry.yml を
  検証 (_clone_is_healthy)。壊れた既存 dir は除去して再 clone
- _files_equal で S_IMODE を比較。旧コピーの実行ビット変更を差分扱いし保全
- _auto_migrate の preserved/skipped 再通知を loud な per-plugin WARNING から
  簡潔な INFO ヒント 1 行に抑制 (詳細は devbase plugin migrate 側で出力)

migrator テスト 12 件追加 (.bak 末尾判定 / clone 健全性 / 実行ビット差分 /
batched save / broken local_path 再 clone / 警告抑制)。全 264 件 pass。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(plugin): migration の registry 重複排除 / exec ビット限定比較 / 健全 clone 保全 (PR2 round4)

- registry.add_many: 引数内で名前が重複する場合 last-wins で一意化してから
  反映し、plugins.yml に矛盾エントリが残らないようにした
- _files_equal: 全権限ビット比較を exec ビット (+x) 限定に変更し、umask /
  group 設定差による誤った .bak 退避を防止
- _ensure_repo_cloned: local_path 記録済みだが unhealthy な既存 dir でも
  .git があれば未コミット/未 push のローカル変更を失わないよう rmtree せず
  PluginError を送出し、.git 欠落 (真に壊れている) 場合のみ再 clone する

test: add_many 重複排除 / exec ビット限定 / .git 付き clone 保全の 6 件を追加

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(plugin): migration の derived clone 保全 / registry 先行永続化 / 特殊ファイル差分検知 (PR2 round5)

cross-review round 5 で指摘された 4 件に対応:

- derived clone 経路 (.git 保護): repo.local_path 未設定でも repos/<derived>
  に .git 付き既存 clone があり registry.yml だけ欠ける場合、無条件 rmtree で
  未コミット/未 push のローカル変更を失っていた。_reclaim_or_protect_existing
  を新設し local_path 経路と同じく .git 有りは削除せず PluginError で復旧案内
  する (freshly clone した分のみ破棄)。
- registry 先行永続化: 旧 plugins/ コピーの削除/.bak 退避 → add_many の順序を
  逆転し、検証済み path rewrite を破壊的 fs 操作の前に 1 回保存する二相構成へ。
  保存失敗時はコピー無傷で abort (次回 retry 可能)、phase2 の retire 失敗は
  registry が既に有効な repos/ clone を指すため lingering copy として
  _cleanup_plugins_dir が surface する (silent data loss を排除)。
- clone_dir がファイル/symlink で squat: clone_dir.is_dir() のみでは git_clone
  が失敗するため、ファイル/symlink は unlink して再 clone (git tree を持たない
  ため損失なし)。
- _entry_kind == 'other' (socket/pipe/device): 内容比較できず identical を
  証明できないため diverged 扱いとし .bak 保全に倒す。

migrator テスト 5 件追加 (derived .git 保護 / clone_dir ファイル squat /
registry 保存失敗でコピー無傷 / retire は保存後 / fifo は差分扱い)。
全 275 件 pass。ruff (E9,F63,F7,F82) / compileall pass。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(plugin): derived clone 経路で健全 clone を reuse する (round 6)

round 5 で derived 経路 (local_path 未設定) の `.git` 付き既存 dir を
無条件に保護 (PluginError) していたが過剰だった。`repos/<derived>` に
.git + registry.yml が両方そろった健全 clone が残っている場合は
PluginError で migration を skip せず、そのまま reuse して local_path を
永続化するよう修正。

- 健全 clone (.git + registry.yml) → reuse + local_path 永続化
- .git ありだが unhealthy (registry.yml 欠落) → 従来どおり保護 (PluginError)
- .git 無し / file・symlink squat → reclaim して再 clone

local_path 経路と derived 経路で挙動を揃え、fresh clone 後と healthy reuse
後の local_path 永続化を `_persist_repo_local_path` に共通化した。

健全 derived clone が reuse され migration が skip されないことを検証する
テスト `test_derived_path_with_healthy_clone_is_reused` を追加。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* perf(plugin): migration の clone 永続化を単一保存に集約 (round 7)

_ensure_repo_cloned が clone のたびに add_repository で plugins.yml を
保存していたため、多数リポジトリ移行時に保存回数が repo 数に比例していた。
clone 済み repo 行を pending_repos に貯め、path rewrite と合わせて Phase2
(破壊的 cleanup) の直前に save_migration で 1 回だけ保存するよう変更。

二相アトミシティは維持: 旧 copy 削除より前に registry が必ず flush 済みで
あること (clone を指す local_path / plugin path の両方) を不変条件として
保持。save_migration は repos + plugins を単一 load+save で upsert する。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* perf(plugin): migration の registry.yml パースをリポジトリあたり 1 回に集約 (PR2 round8)

gemini review (migrator.py:428 [minor/performance]) 対応。

_ensure_repo_cloned が clone/reuse 時に parse_registry_yml した RegistryInfo
を戻り値で返すようにし、migrate ループ側で再パースしていた重複を解消した。
さらに _build_persisted_repo もパース済み reg_info を受け取る形に変更し、
fresh-clone 経路での二重パース (helper 内 + ループ) も排除。結果として
registry.yml の読み込みはリポジトリあたり最大 1 回 (local_path fast path は
lazy fallback) に削減。未使用になった _build_persisted_repo の registry 引数も
除去。挙動・テスト (plugin 203 / migrator 60) は不変。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* perf(plugin): migration の repo 解決をループ前に 1 回へ集約 + migrate を prefix 解決対象に追加 (PR2 round9)

- migrate ループ内の registry.get_repository_by_url (毎回 plugins.yml を再読込) を
  ループ前の URL→repo 辞書索引 1 回に置換し、O(N) ディスク I/O を O(1) に集約
- SUBCMD_MAP[('plugin','pl')] に 'migrate' を追加し、devbase plugin mi / pl mi の
  prefix 解決が効くよう修正 (従来は argparse エラー)
- 再読込が plugin 数に比例しないことを検証する回帰テストを追加

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(plugin): migration の repo 解決が plugin 数に比例して plugins.yml を再読込しない回帰テストを追加 (PR2 round9)

round9 で migrate ループ内の get_repository_by_url (毎回 plugins.yml 再読込) を
ループ前の URL→repo 辞書索引 1 回に置換した変更の回帰防止。_load 呼び出し回数を
計数し plugin 数より少ないことを検証する。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
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 | APPROVE

PR #26 (PLAN04 PR2) の実装をレビューしました。旧形式の plugins/ コピーから repos/ 永続クローンへの移行ロジックは、二相コミットによる整合性確保や厳密な差分検知(実行ビットや特殊ファイル対応)を含め、非常に堅牢に設計されています。テストコードも網羅的であり、安全な移行が期待できます。

一部、同一リポジトリ内の複数プラグイン移行時におけるパースの重複という軽微なパフォーマンス上の懸念がありますが、実用上の影響は限定的と考えられます。

Comment thread lib/devbase/plugin/migrator.py
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

インラインの指摘を修正してください。

Comment thread lib/devbase/plugin/repo_manager.py
- refresh_repository: _update_repo_plugins が repo_errors を返した場合は
  warning で握りつぶさず RepositoryError として伝播。pull 後に削除された
  プラグインの移行失敗を成功扱いにしない (major)
- migrate: 同一リポジトリの複数プラグイン移行時、local_path fast path で
  返る registry.yml の遅延パースを URL 単位でキャッシュしリポジトリあたり
  1 回に抑制 (minor / performance)
- 両挙動の回帰テストを追加

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@takemi-ohama
Copy link
Copy Markdown
Contributor Author

🔧 cross-review fix | round 1 対応サマリ

commit: 65be8ac

対応件数: 2 件(重要度別)

重要度 件数 内容
critical 0
major 1 refresh_repository_update_repo_plugins の repo_errors を warning で握りつぶし、壊れた移行状態を成功扱いにしていた → RepositoryError として伝播
minor 1 migrate ループの registry.yml 重複パースを URL 単位キャッシュでリポジトリあたり 1 回に抑制 (performance)
nit 0

追加テスト

  • test_refresh_raises_when_update_repo_plugins_errors — repo_errors 発生時に RepositoryError を送出
  • test_registry_yml_parsed_once_for_multiple_plugins_same_repo — 同一リポジトリ複数プラグインで parse 1 回

deferred / rejected

  • なし

CI

  • 変更ファイルに対し CI 同等の ruff check --select=E9,F63,F7,F82 lib を実行し pass
  • 全テスト 283 passed
  • push 直後のため GitHub Actions は再実行待ち(待機せず)

備考

  • repo_manager.py:318repos_dir 未使用変数 (F841) は別関数かつ本 PR diff 外、プロジェクトの CI ruff 選択ルール (E9/F63/F7/F82 のみ) でも検出されないため今回は対象外。

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

レガシーな plugins/ へのコピーから repos/ での永続クローン管理への移行、および自動移行の仕組みが非常に丁寧に実装されています。移行時の安全策(.bak での保全やアトミックな plugins.yml 更新)や、プロジェクトの移動検知なども網羅されており、設計の堅牢性が高いです。

いくつか重箱の隅をつつくような指摘がありますが、承認に足る品質と判断します。

Comment thread lib/devbase/plugin/repo_manager.py
Comment thread lib/devbase/plugin/migrator.py
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

更新後の registry metadata を installed plugin に反映する前に、registry.yml が指す plugin directory の存在検証を追加してください。

Comment thread lib/devbase/plugin/updater.py
_update_repo_plugins が registry.yml の path をそのまま plugins.yml に書き
込むため、path が実在しないディレクトリを指していても repos/.../missing で
成功扱いになっていた。_register_repo_plugin と同様に plugin_path.is_dir() を
検証し、存在しない場合は registry を更新せず errors に積むよう修正。

回帰テスト test_update_errors_when_registry_path_missing を追加。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@takemi-ohama
Copy link
Copy Markdown
Contributor Author

🔧 cross-review fix | round 2 対応サマリ

commit: 7b77659

対応件数: 1 件(重要度別)

重要度 件数 内容
critical 0
major 1 _update_repo_plugins が registry.yml の path をそのまま plugins.yml に書き込むため、実在しないディレクトリ (repos/.../missing) を指していても成功扱いになっていた → plugin_path.is_dir() を検証し、無ければ registry を更新せず errors に積むよう修正(_register_repo_plugin の検証に整合)
minor 0 (修正) / 2 (deferred) 下記
nit 0

追加テスト

  • test_update_errors_when_registry_path_missing — registry.yml が実在しない path を指す場合に errors が返り、既存 registry entry が書き換わらないことを検証

deferred(resolve せず次ラウンドで再評価)

  • repo_manager.py:121 [minor] upstream 未設定ブランチのメッセージに (local branch?) 追加提案 → 現メッセージ no upstream tracking branch (local-only commits may exist) で同趣旨を既に明示。挙動緩和は未 push commit 喪失の安全性トレードオフを伴う設計判断のため deferred。
  • migrator.py:178 [minor] .git あり / registry.yml 無しの自動セルフヒーリング提案 → ローカル作業を黙って破棄するリスクを避ける意図的な安全側設計。エラー文で git checkout -- registry.yml を明示案内済み。自動修復は安全契約を緩める設計判断のため deferred。

rejected

  • なし

CI

  • 変更ファイルに対し ruff check --select=E9,F63,F7,F82 lib pass
  • 全テスト 284 passed
  • GitHub Actions(既存チェック)push 前時点で全 SUCCESS。push 後の再実行は待機せず。

@takemi-ohama 再レビューをお願いします。

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

PR #26 adds a necessary validation step during plugin updates to ensure that the plugin directory path specified in registry.yml actually exists. This prevents updating the registry with broken paths and incorrect version metadata (defaulting to 0.1.0) when a repository state is inconsistent.

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

永続クローン移行後に plugin.path を唯一の実体パスとして扱うよう、残っている plugins/<name> 前提の表示系も合わせて修正してください。

Comment thread lib/devbase/plugin/installer.py
devbase status の _get_plugin_info が project_count を旧レイアウト
plugins/<name>/projects から数えていたため、PLAN04 で repos/<repo>/<subdir>
へ移行したプラグインの project_count が常に 0 表示されていた。
registry.devbase_root / plugin.path / projects を基準に数えるよう変更し、
plugin.py の表示ロジックと整合させた(repos/ と --link 両方を解決)。

回帰テスト test_status_project_count.py を追加(repos ベース / --link /
projects 無しの 3 ケース)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@takemi-ohama
Copy link
Copy Markdown
Contributor Author

🔧 cross-review fix | round 3 対応サマリ

commit: d746317

対応件数: 1 件(重要度別)

重要度 件数 内容
critical 0
major 1 devbase status_get_plugin_info が project_count を旧レイアウト plugins/<name>/projects から数えていたため、PLAN04 で repos/<repo>/<subdir> へ移行したプラグインの project_count が常に 0 表示されていた → registry.devbase_root / plugin.path / projects 基準に変更し commands/plugin.py の PROJECTS 表示と整合(repos/ と --link 両方を解決)
minor 0
nit 0

追加テスト

  • tests/plugin/test_status_project_count.py — repos ベース(2件) / --link(plugins/<name>) / projects 無し(0件) の 3 ケースで project_count 算出を検証

deferred / rejected

  • なし(前ラウンドで deferred とした repo_manager.py:121 / migrator.py:178 の 2 件は方針変更なく据え置き、本ラウンドでの新規対応なし)

CI

  • ruff check --select=E9,F63,F7,F82 lib pass
  • 全テスト 287 passed
  • push 時点で GitHub Actions の既存チェック(syntax 3.10/3.11/3.12・Ruff lint・ShellCheck)全 SUCCESS。push 後の再実行は待機せず。

@takemi-ohama 再レビューをお願いします。

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

PR #26 は、devbase status におけるプラグインのプロジェクト数(project_count)の算出ロジックを修正し、PLAN04 以降の repos/ レイアウトでも正しくカウントされるようにするものです。
実装はシンプルで、回帰テストも十分に提供されており、既存の --link (plugins/ ベース) との互換性も維持されています。

Comment thread lib/devbase/commands/status.py
- installer.py: `devbase plugin install myplugin@v1` の名前指定インストール分岐で
  source.ref を _install_from_repo() に渡し既定ブランチを黙ってインストールしていた
  問題を修正。未登録/登録済みリポジトリと同様に @ref を PluginError で拒否する (major)
- status.py: plugin.path が空文字列の場合に環境ルートの projects/ を誤参照する
  可能性を防ぐため事前ガードを追加し 0 件扱いとする (minor / 堅牢性)
- 回帰テスト追加: test_install_ref_rejected_for_name_only /
  test_project_count_zero_when_path_empty

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@takemi-ohama
Copy link
Copy Markdown
Contributor Author

🔧 cross-review fix | round 4 対応サマリ

commit: b9ad5d9

対応件数: 2 件(重要度別)

重要度 件数 内容
critical 0
major 1 installer.py 名前指定インストール (devbase plugin install myplugin@v1) の分岐で source.ref_install_from_repo() にそのまま渡しており、永続クローンが ref を無視して既定ブランチを黙ってインストールしていた → 未登録/登録済みリポジトリと同様に @refPluginError で拒否(codex round4 指摘。インラインコメントは line 129 が diff 外で 422 となり thread 化されず、本サマリで対応報告)
minor 1 status.py _get_plugin_infoplugin.path が空文字列のとき devbase_root / "" / projects が環境ルートの projects を誤参照し project_count を誤計上しうる問題 → if not plugin.path: ガードで 0 件扱い(gemini round4 指摘、堅牢性)
nit 0

追加テスト

  • test_install_ref_rejected_for_name_onlymyplugin@v1PluginError を送出し、既定ブランチからのインストールが行われない(registry に未登録)ことを検証
  • test_project_count_zero_when_path_empty — 環境ルートに projects 2件があっても空 path プラグインは project_count=0 と数えることを検証
  • 全 289 passed(287 → +2)

deferred / rejected

  • なし(前ラウンドで deferred の repo_manager.py:121 / migrator.py:178 は方針変更なく据え置き、本ラウンドでの新規 deferred なし)

CI

  • ruff check --select=E9,F63,F7,F82 lib pass
  • push 時点で GitHub Actions の既存チェック(Python syntax 3.10/3.11/3.12・Ruff lint・ShellCheck)全 SUCCESS。push 後の再実行は待機せず。

@takemi-ohama 再レビューをお願いします。

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 | APPROVE

プラグインの永続クローン(repos/)への移行およびステータス表示の改善は適切に実装されています。特に migrator における 2-phase 移行による堅牢性の確保が評価できます。いくつかの軽微な効率性の改善提案をインラインで行いました。

Comment thread lib/devbase/plugin/migrator.py
Comment thread lib/devbase/plugin/migrator.py
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 | APPROVE

修正要求はありません。

…ン間で再利用

更新後の repo を repos_by_url に書き戻し、後続プラグインが local_path
fast path を通るようにして clone-reuse 分岐の再入 (registry.yml 再パース +
pending_repos 重複登録) を回避。clone/reuse パスの reg_info も
reg_info_by_url にキャッシュし、同一リポジトリの複数プラグイン移行時の
registry.yml パースを 1 回に抑制。
@takemi-ohama
Copy link
Copy Markdown
Contributor Author

🔧 /ndf:fix サマリ

対応件数: minor=2 (合計 2 件) / deferred=0 / rejected=0
commit: 9d5b712
CI: 既存 5 チェック (Python syntax 3.10/3.11/3.12・Ruff lint・ShellCheck) は push 時点で SUCCESS。push 後の再実行は待機せず。ローカルで ruff check --select=E9,F63,F7,F82 lib pass / pytest tests/plugin 120 passed。

詳細

  • [minor/効率性] lib/devbase/plugin/migrator.py — migrate ループで _ensure_repo_cloned が返した更新後 reporepos_by_url に書き戻し、同一リポジトリの後続プラグインが local_path fast path を通るよう変更。clone-reuse 分岐の再入による registry.yml 再パース + pending_repos 重複登録を回避。あわせて clone/reuse パスの reg_inforeg_info_by_url にキャッシュし、同一リポジトリ複数プラグイン移行時のパースを 1 回に抑制。
  • 回帰テスト追加: test_clone_and_registry_parse_reused_across_plugins_same_repo(local_path 無しの複数プラグインで clone 1 回・parse 1 回を検証)

@takemi-ohama takemi-ohama merged commit 1ca1c85 into main May 28, 2026
5 checks passed
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