Commit 1ca1c85
release: PLAN04 plugin repo persistence (#26)
* chore: PLAN04 release branch 作成
* feat(plugin): repos/ 永続クローンによるプラグイン管理と projects/ 直接シンボリックリンク (#29)
* 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>
* feat(plugin): 旧 plugins/ コピーインストールを repos/ 永続クローンへ移行する devbase plugin 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>
* fix(plugin): repo refresh の壊れた移行を成功扱いにせず移行時の registry.yml 重複パースを抑制
- 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>
* fix(plugin): update 時に registry.yml の指す plugin directory 存在を検証する
_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>
* fix(status): repos/ ベースプラグインの project_count を plugin.path 基準で算出する
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>
* fix(plugin): 名前指定インストールの @ref 拒否と status の空 path ガード
- 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>
* perf(plugin): migrate ループでクローン済み repo と registry.yml パースを同一リポジトリのプラグイン間で再利用
更新後の 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 回に抑制。
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 83942e4 commit 1ca1c85
16 files changed
Lines changed: 3841 additions & 458 deletions
File tree
- docs/user
- lib/devbase
- commands
- plugin
- tests/plugin
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
404 | 404 | | |
405 | 405 | | |
406 | 406 | | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
407 | 425 | | |
408 | 426 | | |
409 | 427 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
37 | 37 | | |
38 | 38 | | |
39 | 39 | | |
40 | | - | |
| 40 | + | |
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
| |||
234 | 234 | | |
235 | 235 | | |
236 | 236 | | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
237 | 240 | | |
238 | 241 | | |
239 | 242 | | |
| |||
244 | 247 | | |
245 | 248 | | |
246 | 249 | | |
| 250 | + | |
| 251 | + | |
247 | 252 | | |
248 | 253 | | |
249 | 254 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| 12 | + | |
12 | 13 | | |
13 | 14 | | |
14 | 15 | | |
| |||
34 | 35 | | |
35 | 36 | | |
36 | 37 | | |
| 38 | + | |
37 | 39 | | |
38 | 40 | | |
39 | 41 | | |
| |||
138 | 140 | | |
139 | 141 | | |
140 | 142 | | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
141 | 173 | | |
142 | 174 | | |
143 | 175 | | |
| |||
149 | 181 | | |
150 | 182 | | |
151 | 183 | | |
152 | | - | |
| 184 | + | |
| 185 | + | |
153 | 186 | | |
154 | 187 | | |
155 | 188 | | |
| |||
181 | 214 | | |
182 | 215 | | |
183 | 216 | | |
184 | | - | |
| 217 | + | |
185 | 218 | | |
186 | 219 | | |
187 | 220 | | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
188 | 225 | | |
189 | 226 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
100 | 100 | | |
101 | 101 | | |
102 | 102 | | |
103 | | - | |
104 | 103 | | |
105 | 104 | | |
106 | | - | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
107 | 114 | | |
108 | 115 | | |
109 | 116 | | |
| |||
0 commit comments