Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .agents/plugins/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"name": "reviewable-html-workbench",
"source": {
"source": "local",
"path": "./plugins/reviewable-html-workbench"
"path": "./"
},
"policy": {
"installation": "INSTALLED_BY_DEFAULT",
Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"author": {
"name": "u1"
},
"source": "./plugins/reviewable-html-workbench"
"source": "./"
}
]
}
4 changes: 3 additions & 1 deletion docs/codex-plugin-packaging.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <repo>` で `.agents/plugins/marketplace.json` が読まれ、`reviewable-html-workbench` plugin は `source.path: "./plugins/reviewable-html-workbench"` から読み込まれる。
この repo は plugin root と marketplace root を兼ねる。`codex plugin marketplace add <repo>` で `.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` で検証する。

## ローカル登録手順

Expand Down
2 changes: 1 addition & 1 deletion docs/design.html
Original file line number Diff line number Diff line change
Expand Up @@ -851,7 +851,7 @@ <h3>plugin化の判断</h3>
</tbody>
</table>
<div class="callout">
採用方針は、専用repoを plugin repo の管理元にし、<code>visual-html-renderer</code> と <code>reviewable-design-doc</code> を同梱する形。Codex側は <code>.agents/plugins/marketplace.json</code> を持つ repo-local marketplace として登録し、<code>plugins/reviewable-html-workbench</code> symlink から plugin root を解決する。base repo の <code>home/skills</code> には同名skillを置かない。
採用方針は、専用repoを plugin repo の管理元にし、<code>visual-html-renderer</code> と <code>reviewable-design-doc</code> を同梱する形。Codex側は <code>.agents/plugins/marketplace.json</code> を持つ repo-local marketplace として登録し、<code>source.path: "./"</code> つまり marketplace root 自体を plugin root として解決する。base repo の <code>home/skills</code> には同名skillを置かない。
</div>
<h3>base repoとの衝突回避</h3>
<p>base repoの <code>bin/build-codex-skills.sh</code> は <code>home/skills</code> から <code>home/generated/codex-skills</code> を生成する。<code>visual-html-renderer</code> と <code>reviewable-design-doc</code> はこのplugin repoで管理し、base repo側には同名skillを追加しないため、生成skill経路とは分離される。</p>
Expand Down
2 changes: 1 addition & 1 deletion docs/development-plan.html
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ <h3>統合時の確認項目</h3>
<li>既存skillからこのpluginを呼ぶ場合は、直接script呼び出しではなくplugin skill境界経由にする。</li>
</ul>
<h3>採用する登録方式</h3>
<p>このrepoは plugin root と repo-local marketplace root を兼ねる。<code>.agents/plugins/marketplace.json</code> は <code>reviewable-html-workbench-local</code> marketplace を定義し、plugin entry は <code>source.path: "./plugins/reviewable-html-workbench"</code> を参照する。<code>plugins/reviewable-html-workbench</code> はrepo rootへのsymlinkで、Codex marketplace loaderの既存パターンに合わせるために置く。導入は <code>codex plugin marketplace add /path/to/reviewable-html-workbench</code> で行う。</p>
<p>このrepoは plugin root と repo-local marketplace root を兼ねる。<code>.agents/plugins/marketplace.json</code> は <code>reviewable-html-workbench-local</code> marketplace を定義し、plugin entry は <code>source.path: "./"</code> を参照し、marketplace root 自体を plugin root として解決する。以前は repo root への symlink <code>plugins/reviewable-html-workbench</code> を経由していたが、Windows の git が既定で symlink を通常ファイルとして checkout し install が <code>ENOTDIR</code> で失敗するため廃止した。導入は <code>codex plugin marketplace add /path/to/reviewable-html-workbench</code> で行う。</p>
<p>marketplace policy は <code>INSTALLED_BY_DEFAULT</code> とする。<code>AVAILABLE</code> のままだと marketplace 登録後もplugin cacheが作られず、skill discovery に載らない。</p>
<p>repo path に空白が含まれる環境では、Codex CLIのsource判定がgit source側へ倒れる場合がある。その場合は空白を含まないsymlinkを作り、<code>codex plugin marketplace add /private/tmp/reviewable-html-workbench</code> のようにsymlink pathを渡す。</p>
<p>base repoの <code>install.sh</code> には含めない。Codex全プロジェクトに強制配布すると同名skillの二重登録リスクが高いため、まずは個別導入とし、必要になった場合だけbase repo側へ薄いadapterを追加する。</p>
Expand Down
1 change: 0 additions & 1 deletion plugins/reviewable-html-workbench

This file was deleted.

26 changes: 22 additions & 4 deletions tests/test_project_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import json
import os
import subprocess
import unittest
from pathlib import Path

Expand Down Expand Up @@ -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"))
Expand Down