diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json index b14ec97..eefcf31 100644 --- a/.agents/plugins/marketplace.json +++ b/.agents/plugins/marketplace.json @@ -8,7 +8,7 @@ "name": "reviewable-html-workbench", "source": { "source": "local", - "path": "./plugins/reviewable-html-workbench" + "path": "./" }, "policy": { "installation": "INSTALLED_BY_DEFAULT", diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index ed794aa..f284c58 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -15,7 +15,7 @@ "author": { "name": "u1" }, - "source": "./plugins/reviewable-html-workbench" + "source": "./" } ] } diff --git a/docs/codex-plugin-packaging.md b/docs/codex-plugin-packaging.md index 1bc9615..54a7344 100644 --- a/docs/codex-plugin-packaging.md +++ b/docs/codex-plugin-packaging.md @@ -4,7 +4,9 @@ `reviewable-html-workbench` は Codex plugin repo を管理元にする。base repo の `home/skills` / `home/generated/codex-skills` には同名 skill を置かず、必要になった場合だけ薄い adapter skill を追加する。 -この repo は plugin root と marketplace root を兼ねる。Codex marketplace loader の既存パターンに合わせるため、`plugins/reviewable-html-workbench` は repo root への symlink として置く。`codex plugin marketplace add ` で `.agents/plugins/marketplace.json` が読まれ、`reviewable-html-workbench` plugin は `source.path: "./plugins/reviewable-html-workbench"` から読み込まれる。 +この repo は plugin root と marketplace root を兼ねる。`codex plugin marketplace add ` で `.agents/plugins/marketplace.json` が読まれ、`reviewable-html-workbench` plugin は `source.path: "./"`、つまり marketplace root 自体から読み込まれる。 + +以前は Codex loader の既存パターンに合わせて `plugins/reviewable-html-workbench` を repo root (`..`) への symlink として置き、`source.path` をそこへ向けていた。Windows の git は既定 (`core.symlinks=false`) で symlink をリンク先文字列を書いた通常ファイルとして checkout するため、その path を plugin root として走査した Claude Code / Codex が `ENOTDIR` で install に失敗する。symlink の解決先は元々 repo root なので、`source.path` を `"./"` に直せば POSIX 側の解決結果は変わらないまま Windows でも成立する。この理由から symlink は廃止し、tracked file に symlink を置かないことを `tests/test_project_layout.py` で検証する。 ## ローカル登録手順 diff --git a/docs/design.html b/docs/design.html index 98e1b18..3911c6d 100644 --- a/docs/design.html +++ b/docs/design.html @@ -851,7 +851,7 @@

plugin化の判断

- 採用方針は、専用repoを plugin repo の管理元にし、visual-html-renderer と reviewable-design-doc を同梱する形。Codex側は .agents/plugins/marketplace.json を持つ repo-local marketplace として登録し、plugins/reviewable-html-workbench symlink から plugin root を解決する。base repo の home/skills には同名skillを置かない。 + 採用方針は、専用repoを plugin repo の管理元にし、visual-html-renderer と reviewable-design-doc を同梱する形。Codex側は .agents/plugins/marketplace.json を持つ repo-local marketplace として登録し、source.path: "./" つまり marketplace root 自体を plugin root として解決する。base repo の home/skills には同名skillを置かない。

base repoとの衝突回避

base repoの bin/build-codex-skills.sh は home/skills から home/generated/codex-skills を生成する。visual-html-renderer と reviewable-design-doc はこのplugin repoで管理し、base repo側には同名skillを追加しないため、生成skill経路とは分離される。

diff --git a/docs/development-plan.html b/docs/development-plan.html index 2065236..7b1450a 100644 --- a/docs/development-plan.html +++ b/docs/development-plan.html @@ -480,7 +480,7 @@

統合時の確認項目

  • 既存skillからこのpluginを呼ぶ場合は、直接script呼び出しではなくplugin skill境界経由にする。
  • 採用する登録方式

    -

    このrepoは plugin root と repo-local marketplace root を兼ねる。.agents/plugins/marketplace.json は reviewable-html-workbench-local marketplace を定義し、plugin entry は source.path: "./plugins/reviewable-html-workbench" を参照する。plugins/reviewable-html-workbench はrepo rootへのsymlinkで、Codex marketplace loaderの既存パターンに合わせるために置く。導入は codex plugin marketplace add /path/to/reviewable-html-workbench で行う。

    +

    このrepoは plugin root と repo-local marketplace root を兼ねる。.agents/plugins/marketplace.json は reviewable-html-workbench-local marketplace を定義し、plugin entry は source.path: "./" を参照し、marketplace root 自体を plugin root として解決する。以前は repo root への symlink plugins/reviewable-html-workbench を経由していたが、Windows の git が既定で symlink を通常ファイルとして checkout し install が ENOTDIR で失敗するため廃止した。導入は codex plugin marketplace add /path/to/reviewable-html-workbench で行う。

    marketplace policy は INSTALLED_BY_DEFAULT とする。AVAILABLE のままだと marketplace 登録後もplugin cacheが作られず、skill discovery に載らない。

    repo path に空白が含まれる環境では、Codex CLIのsource判定がgit source側へ倒れる場合がある。その場合は空白を含まないsymlinkを作り、codex plugin marketplace add /private/tmp/reviewable-html-workbench のようにsymlink pathを渡す。

    base repoの install.sh には含めない。Codex全プロジェクトに強制配布すると同名skillの二重登録リスクが高いため、まずは個別導入とし、必要になった場合だけbase repo側へ薄いadapterを追加する。

    diff --git a/plugins/reviewable-html-workbench b/plugins/reviewable-html-workbench deleted file mode 120000 index a96aa0e..0000000 --- a/plugins/reviewable-html-workbench +++ /dev/null @@ -1 +0,0 @@ -.. \ No newline at end of file diff --git a/tests/test_project_layout.py b/tests/test_project_layout.py index 18a4de6..6199919 100644 --- a/tests/test_project_layout.py +++ b/tests/test_project_layout.py @@ -2,6 +2,7 @@ import json import os +import subprocess import unittest from pathlib import Path @@ -46,14 +47,31 @@ def test_codex_marketplace_entry_points_to_plugin_root(self) -> None: self.assertEqual(len(plugins), 1) plugin = plugins[0] self.assertEqual(plugin["name"], "reviewable-html-workbench") - self.assertEqual(plugin["source"], {"source": "local", "path": "./plugins/reviewable-html-workbench"}) + self.assertEqual(plugin["source"], {"source": "local", "path": "./"}) self.assertEqual(plugin["policy"]["installation"], "INSTALLED_BY_DEFAULT") self.assertEqual(plugin["policy"]["authentication"], "ON_INSTALL") self.assertEqual(plugin["category"], "Productivity") - plugin_link = ROOT / "plugins" / "reviewable-html-workbench" - self.assertTrue(plugin_link.exists()) - self.assertEqual(plugin_link.resolve(), ROOT) + def test_claude_marketplace_entry_points_to_plugin_root(self) -> None: + payload = json.loads((ROOT / ".claude-plugin" / "marketplace.json").read_text(encoding="utf-8")) + plugins = payload["plugins"] + self.assertEqual(len(plugins), 1) + self.assertEqual(plugins[0]["name"], "reviewable-html-workbench") + self.assertEqual(plugins[0]["source"], "./") + + def test_repo_contains_no_symlinks(self) -> None: + """Windows の git は既定 (core.symlinks=false) で symlink を通常ファイルとして + checkout する。marketplace source がそこを指すと install が ENOTDIR で失敗するため、 + tracked file に symlink を持ち込まない。""" + listing = subprocess.run( + ["git", "ls-files", "-s"], + cwd=ROOT, + capture_output=True, + text=True, + check=True, + ).stdout + symlinks = [line.split("\t", 1)[1] for line in listing.splitlines() if line.startswith("120000 ")] + self.assertEqual(symlinks, [], f"tracked symlinks break Windows checkouts: {symlinks}") def test_codex_manifest_documents_required_interface(self) -> None: payload = json.loads((ROOT / ".codex-plugin" / "plugin.json").read_text(encoding="utf-8"))