fix/physical-path-resolution-across-plugins
develop
..
hooks/lib.sh
jsc_abs_path()
jsc_gitea_sh()
tools/wire-cli.sh
HERE
ROOT
cd -P
pwd -P
ln -sfn
references/behaviors.md
wire-cli.sh
plugin.json
.claude-plugin/plugin.json
.codex-plugin/plugin.json
[ -f ]
cd
jsc_gitea_sh
gitea.sh
report
recommend
unverifiable
update
current/jsc-hooks
ln -sfn "$ROOT" "$_link"
readlink -f
lib.sh
jsc-gitea
cd: can't cd to ...
behind 0
session-timer.sh
JSC_GITEA_TOOLS
version-guard.sh
lint-scripts.sh
check-behaviors.sh
ste100-lint.sh
current
wire-cli.sh status claude
status=wired
版本閘門對 11 個 domain 全部回「查詢失敗」,等於完全失效——它擋不下任何版本落後的技能呼叫,而且是無聲的:report 照印表格,只是每一列都寫查詢失敗。 根因是 jsc_gitea_sh 回傳的路徑帶著 ..,而那些 .. 要穿過 current/jsc-hooks 這條符號連結。兩種解析方式對它的答案不同:核心與 [ -f ] 用實體解析、跟著連結走,判定檔案存在;shell 的 cd 用邏輯解析、純文字消去 ..,落到一個不存在的目錄。所以 [ -f ] 檢查通過、路徑交了出去,gitea.sh 的 cd 卻失敗,回結束碼 2 與空輸出,呼叫端就判成查不到。 新增 jsc_abs_path,用 cd -P 加 pwd -P 把路徑正規化成不含 .. 的實體路徑。挑這個做法是因為兩者都是 shell 內建,不必在 PATH 上找執行檔——這些函式會在 cron 那種只剩幾段 PATH 的環境下跑,少一個外部相依就少一個解不出來的理由。jsc_gitea_sh 的四條候選改成尾端統一正規化,正規化失敗就退回原樣路徑,「找得到」的判準不變。 wire-cli.sh 的 HERE 與 ROOT 一併改成實體解析。那是同一個根因的另一種發作方式:ROOT 會被 ln -sfn 當成目標,而這支腳本常常就是經由那條連結被叫起來的,邏輯解析會讓 ROOT 等於連結自己,連結被改成指向自己,全機器 hook 一起失效。這件事實際發生過。原本靠兩道防線擋著:事後的 [ -f ] 檢查,以及文件要求呼叫端先解出實體根目錄。前者要等連結已經被寫壞才攔得到,後者靠人記得。改成實體解析之後這個失敗模式不可能成立。 行為契約第 10 列跟著改:從實體根目錄跑 wire-cli.sh 的規定保留,但性質從必要條件降成多一層保險,並寫明保險為什麼還值得買——舊版腳本還在別的機器上跑。 驗證用同形佈局做:暫存區搭一套一樣形狀的連結農場,先塞原版重現失敗、再塞改版確認修好。真實環境的連結與快取全程沒有動過。
路徑解析的修正要靠版號才傳得到機器端,版本前置檢查才會要求更新。 三份 manifest 由 sync-skill-manifest.sh 同步,只動版本欄位。
No dependencies set.
The note is not visible to the blocked user.
摘要
..穿過符號連結,邏輯解析與實體解析的答案不同。同一個根因還有另一種發作方式:接線腳本會把共用連結改成指向自己。兩處都改成實體解析。變更內容
hooks/lib.shjsc_abs_path()把路徑正規化成不含..的實體路徑;jsc_gitea_sh()的四條候選改成尾端統一正規化,正規化失敗退回原樣路徑,「找得到」的判準不變tools/wire-cli.shHERE與ROOT改成cd -P加pwd -P。ROOT會被ln -sfn當成目標,邏輯解析會讓它等於連結自己references/behaviors.mdwire-cli.sh的規定保留,但性質從必要條件降成多一層保險plugin.json、.claude-plugin/plugin.json、.codex-plugin/plugin.json設計重點
..穿過符號連結時,核心與[ -f ]用實體解析、跟著連結走;shell 的cd用邏輯解析、純文字消去..。兩邊答案不同,所以[ -f ]檢查通過的路徑,cd進不去。jsc_gitea_sh交出帶..的路徑,gitea.sh的cd失敗、回結束碼 2 與空輸出,呼叫端判成查不到。表現是report照印表格、每一列都寫「查詢失敗」,而recommend回unverifiable不回update——沒有人會被擋,也沒有人知道閘門已經不作用。wire-cli.sh常常經由current/jsc-hooks被叫起來,邏輯解析讓ROOT等於那條連結,ln -sfn "$ROOT" "$_link"於是把連結指向自己,之後每一支 hook 的接線路徑都解不開,全機器 hook 一起失效。這件事實際發生過。cd -P加pwd -P,不選readlink -f。 兩者都是 shell 內建,不必在 PATH 上找執行檔。這些函式會在 cron 那種只剩幾段 PATH 的環境下跑,少一個外部相依就少一個解不出來的理由。[ -f ]檢查連結通不通,以及文件要求呼叫端先解出實體根目錄再跑。前者要等連結已經被寫壞才攔得到,後者靠人記得。改成實體解析之後,這個失敗模式不可能成立。文件那條規定保留為保險,因為舊版腳本還在別的機器上跑。測試結果
lib.sh寫進外掛快取,那一步被權限機制擋下,沒有繞過。改用暫存區搭一套形狀相同的連結農場:實體版本目錄、旁鄰的jsc-gitea、一條指過去的current/jsc-hooks連結,退三層穿過連結的形狀與真實安裝版面一致。lib.sh跑一次,十一列「查詢失敗」一字不差地重現,jsc_gitea_sh回的正是帶..的路徑,gitea.sh回cd: can't cd to ...與結束碼 2。lib.sh再跑一次:十一個 domain 全部查得到遠端版本,behind 0,結束碼 0。ROOT跑ln -sfn,連結被寫成指向自己、session-timer.sh讀不到;用實體路徑的ROOT跑,連結指向實際目錄、可用。失敗模式重現得出來,也確認消掉了。JSC_GITEA_TOOLS帶..的值會被正規化、開發並排版面照舊解得到、四條全落空時jsc_gitea_sh回 1 而version-guard.sh仍安靜放行結束碼 0。lint-scripts.sh、check-behaviors.sh、ste100-lint.sh對這個存放庫都回結束碼 0。current連結與外掛快取全程沒有動過,wire-cli.sh status claude仍回status=wired。前置 Push Request