Repository navigation
🐛 Windows で plugin install が ENOTDIR になる symlink 依存を外す - #8
Open
rinjugatla wants to merge 1 commit into
Open
rinjugatla wants to merge 1 commit into
rinjugatla wants to merge 1 commit into
Conversation
Windows で marketplace を登録した後の `claude plugin install` が `ENOTDIR: not a directory, scandir '...\plugins\reviewable-html-workbench'` で失敗していた。 原因は marketplace の source が指す plugins/reviewable-html-workbench が repo root (..) への symlink だったこと。Windows の git は既定で core.symlinks=false (Git for Windows のインストーラが system gitconfig へ 書く) のため、symlink をリンク先文字列 ".." が入った 2 バイトの通常ファイル として checkout する。そこを plugin root として走査した時点で落ちる。 symlink の解決先は元々 repo root なので、source を repo root 自身へ向ければ 経路が 1 段短くなるだけで解決先は変わらない。Claude 側 (.claude-plugin/marketplace.json の source) と Codex 側 (.agents/plugins/marketplace.json の source.path) を "./" にし、symlink は 廃止した。tracked file に symlink を持ち込まないことを test で固定する。 symlink 前提だった test_codex_marketplace_entry_points_to_plugin_root は 新実装の期待値へ更新し、Claude 側 source の検査を新規に追加。 検証: Windows では symlink が壊れたままの copy から marketplace add と plugin install が通り、cache に skill 3 件が展開されることを確認。Linux コンテナでは修正前の構成 (symlink を復元し source を旧パスへ戻したもの) と 修正後の構成を両方 install し、生成された cache が plugins/ と marketplace.json の 1 行を除いて完全に一致することを diff -r で確認した。 unittest は .sh を exec できない Windows 環境固有の既存失敗 10 件を除き pass (修正前は symlink 起因の 1 件を加えた 11 件)。Codex CLI が無いため Codex 側の 実機検証は未了。 core.symlinks=true での回避も成立はするが、symlink 作成権限に依存し、かつ global 由来の設定は clone 先の .git/config に記録されないため、false へ 戻すと次の checkout で再発する。symlink 自体を廃止すれば依存が消える。 version は bump していない。`claude plugin install` のローカル導入手順の修正を 別 PR で並行して出す予定で、双方が version を上げると衝突するため、bump の 要否と値の判断は作者に委ねる (AGENTS.md の規約に対する意図的な逸脱)。
rinjugatla
force-pushed
the
fix/windows-plugin-install-symlink
branch
from
August 8, 2026 08:15
87c99b1 to
421a123
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概要
Windows ネイティブ環境で
claude plugin installが失敗し、この plugin を導入できない問題を修正します。README の手順どおり marketplace の登録までは成功しますが、続く install が
ENOTDIRで落ちます。原因は、marketplace の
sourceが指すplugins/reviewable-html-workbenchが repo root (..) への symlink であることです。Windows の git は既定でcore.symlinks=false(Git for Windows のインストーラが system gitconfig へ書き込む)のため、symlink を「リンク先文字列..が入った 2 バイトの通常ファイル」として checkout します。Claude Code はそこを plugin root としてscandirするので、走査した時点でENOTDIRになります。symlink の解決先は元々 repo root なので、
sourceを repo root 自身へ向ければ、経路が 1 段短くなるだけで解決先は変わりません。POSIX 上でこの等価性が実際に成り立つことはテスト計画で実測しています。変更内容
.claude-plugin/marketplace.json…sourceを./plugins/reviewable-html-workbench→./に変更。.agents/plugins/marketplace.json(Codex)…source.pathも同様に./に変更。Codex 側も同じ symlink を参照しており、Windows では同じ失敗をするため。plugins/reviewable-html-workbenchsymlink を削除(参照元が無くなるためplugins/ディレクトリごと消滅)。tests/test_project_layout.pytest_codex_marketplace_entry_points_to_plugin_root… symlink 前提のアサーションを新実装の期待値へ更新。test_claude_marketplace_entry_points_to_plugin_root… Claude 側sourceの検査を新規追加(従来は version しか検証しておらず、sourceの変更を検出できなかったため)。test_repo_contains_no_symlinks…git ls-files -sで mode 120000 の tracked file が無いことを検査する回帰テストを新規追加。同じ踏み方の再発を防ぐため。docs/codex-plugin-packaging.md/docs/design.html/docs/development-plan.html… symlink 構成の記述を更新し、廃止した理由を記録。なお AGENTS.md には「commit 時に 4 ファイルの version を必ず更新する」という規約がありますが、本 PR では意図的に version を bump していません。理由は「補足」に記載します。
テスト計画
Windows での install(Windows 11 / Git for Windows 2.54.0 /
core.symlinks=false)symlink が通常ファイルへ壊れたままの checkout を marketplace として登録し、install が通ることを確認しました。
~/.claude/plugins/cache/.../skills/にplan-preview/reviewable-design-doc/visual-html-rendererの 3 skill が実体として展開されることも確認しています。Linux での等価性確認(修正前 cache と修正後 cache の比較)
「Windows でだけ通って他の OS を壊していないか」を確かめるため、Linux コンテナ(
node:22-slim+claude2.1.226)で 修正前の構成(symlink を復元しsourceを旧パスへ戻したもの) と 修正後の構成 を別 marketplace として両方 install し、生成された cache を比較しました。差が出たのは、廃止した symlink 自身と
marketplace.jsonの該当 1 行だけです。Claude Code が plugin root として受け取る内容は修正前後で完全に一致するため、POSIX 側の挙動は変わりません。修正後の構成のみでの install 成功(skill 3 件の展開を含む)も同じ環境で確認済みです。自動テスト(Windows 11 / Python 3.11.14)
残る 11 件は、
.shを直接 exec できない Windows 環境固有の既存の失敗です(test_plugin_dev_switch/test_kill_review_preview_helper/test_export_pdf、いずれもWinError 193)。本 PR とは無関係で、Linux 環境では発生しません。本 PR 変更前は同じ環境で 12 件失敗しており、symlink 起因の
test_codex_marketplace_entry_points_to_plugin_rootが 1 件解消しています(Ran 314 tests / FAILED (failures=2, errors=10))。新規追加した
test_repo_contains_no_symlinksは、symlink を復元した使い捨て copy で落ちることを確認しています。plugin validation
4 つの manifest(
.claude-plugin/plugin.json/.claude-plugin/marketplace.json/.codex-plugin/plugin.json/.agents/plugins/marketplace.json)の JSON 構文も確認済みです。Checklist
補足
version を bump していないことについて
AGENTS.md の規約では commit ごとに 4 ファイルの version を更新することになっていますが、本 PR ではあえて据え置き(1.28.2 のまま)にしています。
README のローカル導入手順(
claude plugins install .)が現行 CLI では通らない問題の修正 PR を並行して出す予定で、両方が version を上げると衝突するためです。bump の要否と値(本 PR は挙動を変えない packaging 修正なので patch 相当と考えていますが、もう一方とまとめて 1 回にする判断もあり得ます)は作者にお任せします。ご指示いただければこの PR 側で bump します。test_all_version_files_are_in_syncは 4 ファイルの一致を検査するテストで、据え置きでも一致しているため pass します。core.symlinks=trueによる回避についてcore.symlinks=trueにすれば修正前の構成でも install は成立します(実測で確認しました)。ただし恒久的な解決にはなりません。git cloneを実行するため-cを渡せず、marketplace addの前に global / system の gitconfig へ書いておく必要があります。core.symlinks=trueは clone 先の.git/configに記録されません。後でfalseに戻すと次の checkout で通常ファイルへ戻り、再発します。checkout 自体はエラーを出さないため、失敗が表面化するのは install の時です。core.symlinks=falseで clone 済みの marketplace は local config が優先されるため、global を変えても直らずmarketplace remove→addのやり直しが必要です。symlink 自体を廃止すれば、これらの前提がすべて不要になります。
Codex 側の実機検証について
.agents/plugins/marketplace.jsonの変更は、手元に Codex CLI が無いため実機での install 検証ができていません。変更内容は Claude 側と同じ性質(source.pathを symlink 経由から repo root 直指定へ)で解決先も同一ですが、Codex 環境をお持ちの方に一度ご確認いただけると確実です。🤖 このPRは Claude Code(Claude Opus 5)を使用して作成しました。