Merge pull request '跨外掛路徑改實體解析,修好失效的版本閘門,並讓接線腳本不再可能把連結指向自己' (#82) from fix/physical-path-resolution-across-plugins into develop
Reviewed-on: #82
This commit was merged in pull request #82.
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jsc-hooks",
|
"name": "jsc-hooks",
|
||||||
"version": "0.4.2",
|
"version": "0.4.3",
|
||||||
"description": "跨 CLI hooks:STE100 語言強制、工時計時、技能用量記錄、SDLC 模型鎖、版本前置檢查、註解範圍守門、繁中編碼守門、部署後強制重啟、寫入與提交閘門",
|
"description": "跨 CLI hooks:STE100 語言強制、工時計時、技能用量記錄、SDLC 模型鎖、版本前置檢查、註解範圍守門、繁中編碼守門、部署後強制重啟、寫入與提交閘門",
|
||||||
"skills": "./skills",
|
"skills": "./skills",
|
||||||
"author": {
|
"author": {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"hooks": "./hooks/codex-hooks.json",
|
"hooks": "./hooks/codex-hooks.json",
|
||||||
"name": "jsc-hooks",
|
"name": "jsc-hooks",
|
||||||
"version": "0.4.2",
|
"version": "0.4.3",
|
||||||
"description": "跨 CLI hooks:STE100 語言強制、工時計時、技能用量記錄、SDLC 模型鎖、版本前置檢查、註解範圍守門、繁中編碼守門、部署後強制重啟、寫入與提交閘門",
|
"description": "跨 CLI hooks:STE100 語言強制、工時計時、技能用量記錄、SDLC 模型鎖、版本前置檢查、註解範圍守門、繁中編碼守門、部署後強制重啟、寫入與提交閘門",
|
||||||
"skills": "./skills",
|
"skills": "./skills",
|
||||||
"jsc": {
|
"jsc": {
|
||||||
|
|||||||
+44
-10
@@ -229,27 +229,61 @@ cli_name() {
|
|||||||
else printf 'unknown'; fi
|
else printf 'unknown'; fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 把一個檔案路徑正規化成不含 `..` 的實體路徑。解不出來就回傳 1。
|
||||||
|
#
|
||||||
|
# 為什麼一定要正規化:路徑裡的 `..` 一旦要穿過符號連結,兩種解法會給出不同的答案。
|
||||||
|
# 核心與 `[ -f ]` 走實體解析:先跟著連結走到目標,再從目標往上退。
|
||||||
|
# shell 的 `cd` 走邏輯解析:把 `..` 當純文字消去,退回的是連結自己的上層目錄。
|
||||||
|
# 找別的 plugin 是靠自己的位置往上退幾層再往下找,而安裝版面的腳本目錄正是經由一條符號
|
||||||
|
# 連結被叫到的,退層數一超過連結目標底下的深度就會踩到這個差異:這裡的 `[ -f ]` 說檔案
|
||||||
|
# 在、把路徑交出去,被呼叫的腳本自己 `cd` 過去卻找不到那個目錄,回一個空輸出與非零結束
|
||||||
|
# 碼。呼叫端只看得到「查詢失敗」,看不出是路徑寫法的問題,於是整道閘門無聲失效。
|
||||||
|
#
|
||||||
|
# 為什麼用 `cd -P` 加 `pwd -P` 而不是 readlink:這兩個都是 shell 內建,不必在 PATH 上找
|
||||||
|
# 外部執行檔。這些函式會在 cron 那種只剩幾段 PATH 的環境下跑,少一個外部相依就少一個
|
||||||
|
# 解不出來的理由。`-P` 是逐段跟著連結走的那一種解法,跟核心的答案一致。
|
||||||
|
jsc_abs_path() { # $1=檔案路徑
|
||||||
|
[ -n "${1:-}" ] || return 1
|
||||||
|
_ap_dir=$(CDPATH= cd -P -- "$(dirname -- "$1")" 2>/dev/null && pwd -P) || return 1
|
||||||
|
[ -n "$_ap_dir" ] || return 1
|
||||||
|
case "$_ap_dir" in
|
||||||
|
*/) printf '%s%s\n' "$_ap_dir" "$(basename -- "$1")" ;;
|
||||||
|
*) printf '%s/%s\n' "$_ap_dir" "$(basename -- "$1")" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
# 找出 jsc-gitea 的 tools/gitea.sh 絕對路徑。所有 gitea 操作一律經由它(技能準則),
|
# 找出 jsc-gitea 的 tools/gitea.sh 絕對路徑。所有 gitea 操作一律經由它(技能準則),
|
||||||
# 不可自行拼 API 呼叫:token 取用與 tea 金鑰退回都寫在那支腳本裡。
|
# 不可自行拼 API 呼叫:token 取用與 tea 金鑰退回都寫在那支腳本裡。
|
||||||
# 找不到就回傳 1,由呼叫端安靜降級(hook 一律 exit 0,不中斷宿主 CLI)。
|
# 找不到就回傳 1,由呼叫端安靜降級(hook 一律 exit 0,不中斷宿主 CLI)。
|
||||||
|
#
|
||||||
|
# 每一條候選路徑都先湊出來、最後統一過 jsc_abs_path 才交出去,理由見該函式的說明:
|
||||||
|
# 這裡的候選帶著 `..`,而那些 `..` 要穿過安裝版面的符號連結,交出去的原樣路徑
|
||||||
|
# 只有 `[ -f ]` 認得,被呼叫的腳本自己 `cd` 過去會失敗。正規化失敗時退回原樣路徑,
|
||||||
|
# 讓「找得到」這件事的判準不因為多了一道正規化而變嚴。
|
||||||
jsc_gitea_sh() {
|
jsc_gitea_sh() {
|
||||||
if [ -n "${JSC_GITEA_TOOLS:-}" ] && [ -f "$JSC_GITEA_TOOLS/gitea.sh" ]; then
|
_c=""
|
||||||
printf '%s\n' "$JSC_GITEA_TOOLS/gitea.sh"; return 0
|
|
||||||
fi
|
|
||||||
_root="${CLAUDE_PLUGIN_ROOT:-$JSC_SCRIPT_DIR/..}"
|
_root="${CLAUDE_PLUGIN_ROOT:-$JSC_SCRIPT_DIR/..}"
|
||||||
|
if [ -n "${JSC_GITEA_TOOLS:-}" ] && [ -f "$JSC_GITEA_TOOLS/gitea.sh" ]; then
|
||||||
|
_c="$JSC_GITEA_TOOLS/gitea.sh"
|
||||||
|
fi
|
||||||
# 開發用的並排存取庫版面:{workspace}/hooks 旁邊就是 {workspace}/gitea
|
# 開發用的並排存取庫版面:{workspace}/hooks 旁邊就是 {workspace}/gitea
|
||||||
for _c in "$_root/../gitea/tools/gitea.sh" "$_root/../jsc-gitea/tools/gitea.sh"; do
|
if [ -z "$_c" ]; then
|
||||||
[ -f "$_c" ] && { printf '%s\n' "$_c"; return 0; }
|
for _p in "$_root/../gitea/tools/gitea.sh" "$_root/../jsc-gitea/tools/gitea.sh"; do
|
||||||
|
[ -f "$_p" ] && { _c="$_p"; break; }
|
||||||
done
|
done
|
||||||
|
fi
|
||||||
# 已安裝版面:每個 plugin 各有版本目錄,取排序最後的一份(通常即最新版)
|
# 已安裝版面:每個 plugin 各有版本目錄,取排序最後的一份(通常即最新版)
|
||||||
_c=$(ls -d "$_root"/../../jsc-gitea/*/tools/gitea.sh \
|
if [ -z "$_c" ]; then
|
||||||
|
_p=$(ls -d "$_root"/../../jsc-gitea/*/tools/gitea.sh \
|
||||||
"$_root"/../../gitea/*/tools/gitea.sh \
|
"$_root"/../../gitea/*/tools/gitea.sh \
|
||||||
"$HOME"/.claude/plugins/cache/*/jsc-gitea/*/tools/gitea.sh 2>/dev/null \
|
"$HOME"/.claude/plugins/cache/*/jsc-gitea/*/tools/gitea.sh 2>/dev/null \
|
||||||
| sort | tail -n1)
|
| sort | tail -n1)
|
||||||
[ -n "$_c" ] && [ -f "$_c" ] && { printf '%s\n' "$_c"; return 0; }
|
[ -n "$_p" ] && [ -f "$_p" ] && _c="$_p"
|
||||||
_c=$(command -v gitea.sh 2>/dev/null || true)
|
fi
|
||||||
[ -n "$_c" ] && { printf '%s\n' "$_c"; return 0; }
|
[ -n "$_c" ] || _c=$(command -v gitea.sh 2>/dev/null || true)
|
||||||
return 1
|
[ -n "$_c" ] || return 1
|
||||||
|
_n=$(jsc_abs_path "$_c") && [ -n "$_n" ] && _c="$_n"
|
||||||
|
printf '%s\n' "$_c"
|
||||||
}
|
}
|
||||||
|
|
||||||
# 每個 CLI 代號對應的實際執行檔(antigravity 是 agy、kiro 是 kiro-cli,其餘同名)
|
# 每個 CLI 代號對應的實際執行檔(antigravity 是 agy、kiro 是 kiro-cli,其餘同名)
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jsc-hooks",
|
"name": "jsc-hooks",
|
||||||
"version": "0.4.2",
|
"version": "0.4.3",
|
||||||
"description": "跨 CLI hooks:STE100 語言強制、工時計時、技能用量記錄、SDLC 模型鎖、版本前置檢查、註解範圍守門、繁中編碼守門、部署後強制重啟、寫入與提交閘門",
|
"description": "跨 CLI hooks:STE100 語言強制、工時計時、技能用量記錄、SDLC 模型鎖、版本前置檢查、註解範圍守門、繁中編碼守門、部署後強制重啟、寫入與提交閘門",
|
||||||
"skills": "./skills/",
|
"skills": "./skills/",
|
||||||
"jsc": {
|
"jsc": {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
| 項目 | 內容 |
|
| 項目 | 內容 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| 觸發時機 | 裝好或更新完 jsc 技能組之後,要把九支 hook 接線到每一支已安裝的 CLI 時用;`jsc-cli:deploy` 收尾會把偵測到的 CLI 清單交給它。不用於撰寫新的 hook,也不用於單獨修一支壞掉的 hook,那是 `jsc-hooks:repair` 的事 |
|
| 觸發時機 | 裝好或更新完 jsc 技能組之後,要把九支 hook 接線到每一支已安裝的 CLI 時用;`jsc-cli:deploy` 收尾會把偵測到的 CLI 清單交給它。不用於撰寫新的 hook,也不用於單獨修一支壞掉的 hook,那是 `jsc-hooks:repair` 的事 |
|
||||||
| 關鍵步驟 | 先跑前置步驟解出兩個字面絕對路徑:`readlink -f "$JSC_HOME/current"` 解出連結農場根目錄(跨 domain 呼叫用它),`readlink -f "$JSC_HOME/current/jsc-hooks"` 解出 jsc-hooks 的實體根目錄(只有 `wire-cli.sh` 從這裡跑,因為它會改寫自己正踩著的那條連結,走連結跑會讓 `ln -sfn` 把連結指向自己、全機器 hook 一起失效)、兩個路徑各解一次不重解、各自在同一步用 `[ -d ]` 查過印出來的目錄真的存在(`JSC_HOME` 沒設時第一條會印出 `/current`、結束碼 0,非空又是絕對路徑,只查前三項擋不下來),任何一條解不出來、不是絕對路徑、或目錄不存在就停手回報是哪一條沒解出來並叫人跑 `jsc-cli:deploy`,不接任何線也不猜路徑、不退回帶版本號的快取路徑、之後每一次腳本呼叫都用解出來的字面絕對路徑開頭、取得 CLI 清單(呼叫端交來的優先,沒有才自己跑 `detect-clis.sh`)、第一支 CLI 單獨跑完整條管線(它負責更新共用的 `{連結農場根}/jsc-hooks` 連結)、其餘 CLI 一支一個 sub agent 並行、每支 CLI 依序走 purge、接線、status、smoke、scan 五道關卡、讀每道關卡自己印的第一行判定、任一關卡出錯就寫 `ERROR_{HASH}` 並轉給 `jsc-hooks:repair`(異常頁與索引目錄頁分屬兩個存取庫,各自解析;只解不出目錄頁的存取庫時異常頁照寫、索引跳過,回報要講明那一頁沒被索引)、目錄頁那一列指向異常頁的連結一律寫成 `[{文字}]({連結})`,網址取 `gitea.sh wiki-url`,寫進去之前先過 `jsc-gitea/tools/link-check.sh`,結束碼 0 才寫連結、驗不過那一格只留純文字頁名而那一列與異常頁照寫(`report-error.sh` 內部做完,結束碼不變)、逐 CLI 回報五道關卡的結果 |
|
| 關鍵步驟 | 先跑前置步驟解出兩個字面絕對路徑:`readlink -f "$JSC_HOME/current"` 解出連結農場根目錄(跨 domain 呼叫用它),`readlink -f "$JSC_HOME/current/jsc-hooks"` 解出 jsc-hooks 的實體根目錄(只有 `wire-cli.sh` 從這裡跑。它會改寫自己正踩著的那條連結,但它自己已經把 `HERE` 與 `ROOT` 解成實體路徑,`ln -sfn` 不會再把連結指向自己,所以從實體根目錄跑現在是多一層保險、不是唯一防線;照做的理由是舊版腳本還在別的機器上跑,那些版本走連結跑仍會把連結寫成指向自己、全機器 hook 一起失效)、兩個路徑各解一次不重解、各自在同一步用 `[ -d ]` 查過印出來的目錄真的存在(`JSC_HOME` 沒設時第一條會印出 `/current`、結束碼 0,非空又是絕對路徑,只查前三項擋不下來),任何一條解不出來、不是絕對路徑、或目錄不存在就停手回報是哪一條沒解出來並叫人跑 `jsc-cli:deploy`,不接任何線也不猜路徑、不退回帶版本號的快取路徑、之後每一次腳本呼叫都用解出來的字面絕對路徑開頭、取得 CLI 清單(呼叫端交來的優先,沒有才自己跑 `detect-clis.sh`)、第一支 CLI 單獨跑完整條管線(它負責更新共用的 `{連結農場根}/jsc-hooks` 連結)、其餘 CLI 一支一個 sub agent 並行、每支 CLI 依序走 purge、接線、status、smoke、scan 五道關卡、讀每道關卡自己印的第一行判定、任一關卡出錯就寫 `ERROR_{HASH}` 並轉給 `jsc-hooks:repair`(異常頁與索引目錄頁分屬兩個存取庫,各自解析;只解不出目錄頁的存取庫時異常頁照寫、索引跳過,回報要講明那一頁沒被索引)、目錄頁那一列指向異常頁的連結一律寫成 `[{文字}]({連結})`,網址取 `gitea.sh wiki-url`,寫進去之前先過 `jsc-gitea/tools/link-check.sh`,結束碼 0 才寫連結、驗不過那一格只留純文字頁名而那一列與異常頁照寫(`report-error.sh` 內部做完,結束碼不變)、逐 CLI 回報五道關卡的結果 |
|
||||||
| 外部呼叫 | `readlink -f`(前置步驟解兩個根目錄,各一次)、`tools/wire-cli.sh purge`、`tools/wire-cli.sh {cli}`、`tools/wire-cli.sh status`、`tools/wire-cli.sh smoke`、`tools/scan-hook-errors.sh`、`tools/report-error.sh`、`jsc-cli/tools/detect-clis.sh`、`jsc-hooks:repair` 技能、`jsc-gitea:wiki`(寫 `ERROR_{HASH}` 時經 `report-error.sh`)、`jsc-gitea/tools/gitea.sh wiki-url` 與 `jsc-gitea/tools/link-check.sh`(同樣經 `report-error.sh`,取目錄頁那一列的網址並驗它連得到);接線腳本內部另呼叫 `hooks/skill-name.sh` 與 `hooks/deny.sh` 做冒煙斷言 |
|
| 外部呼叫 | `readlink -f`(前置步驟解兩個根目錄,各一次)、`tools/wire-cli.sh purge`、`tools/wire-cli.sh {cli}`、`tools/wire-cli.sh status`、`tools/wire-cli.sh smoke`、`tools/scan-hook-errors.sh`、`tools/report-error.sh`、`jsc-cli/tools/detect-clis.sh`、`jsc-hooks:repair` 技能、`jsc-gitea:wiki`(寫 `ERROR_{HASH}` 時經 `report-error.sh`)、`jsc-gitea/tools/gitea.sh wiki-url` 與 `jsc-gitea/tools/link-check.sh`(同樣經 `report-error.sh`,取目錄頁那一列的網址並驗它連得到);接線腳本內部另呼叫 `hooks/skill-name.sh` 與 `hooks/deny.sh` 做冒煙斷言 |
|
||||||
| 完成條件 | 前置步驟解出的兩個根目錄都是一條存在的絕對路徑(各自用 `[ -d ]` 查過),而且整個流程沒有任何一次腳本呼叫帶著未展開的變數或波浪號,每一支偵測到的 CLI 都有五道關卡各一行判定,沒有任何一道回結束碼 2,smoke 的 `lines` 條數與它自己的斷言相符,claude、codex、copilot、antigravity 回 `wired` 而 kiro 回 `degraded`(CLI 擋不下技能叫用),四支非 claude 的執行期錯誤掃描一律據實回 `unavailable`,各 CLI 的形狀與觸發驗證等級分開寫進回報(codex、antigravity、kiro 形狀實證,copilot 形狀未證;kiro 觸發部分實證,其餘未驗證),每一筆錯誤都帶一個 `ERROR_{HASH}` 結果與一條對 `develop` 的修正 PR 連結,而且目錄頁那一列的連結驗不過時,回報要講明那一列只有純文字頁名、沒有連結 |
|
| 完成條件 | 前置步驟解出的兩個根目錄都是一條存在的絕對路徑(各自用 `[ -d ]` 查過),而且整個流程沒有任何一次腳本呼叫帶著未展開的變數或波浪號,每一支偵測到的 CLI 都有五道關卡各一行判定,沒有任何一道回結束碼 2,smoke 的 `lines` 條數與它自己的斷言相符,claude、codex、copilot、antigravity 回 `wired` 而 kiro 回 `degraded`(CLI 擋不下技能叫用),四支非 claude 的執行期錯誤掃描一律據實回 `unavailable`,各 CLI 的形狀與觸發驗證等級分開寫進回報(codex、antigravity、kiro 形狀實證,copilot 形狀未證;kiro 觸發部分實證,其餘未驗證),每一筆錯誤都帶一個 `ERROR_{HASH}` 結果與一條對 `develop` 的修正 PR 連結,而且目錄頁那一列的連結驗不過時,回報要講明那一列只有純文字頁名、沒有連結 |
|
||||||
| 可驗證跡象 | 各 CLI 的設定檔多出 jsc 段落:codex 的 `config.toml` 標記段落、`hooks/codex-hooks.json`(從 `hooks/hooks.json` 推導,matcher `Skill` 換成 `Bash`)與 `.codex-plugin/plugin.json` 指過去的 `hooks` 路徑字串、copilot 的 `~/.copilot/settings.json` 頂層 `hooks` 鍵(matcher `skill`,合併不覆寫,`enabledPlugins` 與第三方條目原樣保留)與 `$COPILOT_HOME` 底下的指引檔、antigravity 的 `~/.gemini/config/hooks.json` 的 `jsc` 段落(`PreToolUse` 為 Grouped、matcher `^view_file$`,`PreInvocation` 維持 Flat)、kiro 的 `~/.kiro/agents/jsc.json`(`hooks` 為 `agentSpawn`、`userPromptSubmit`、`stop` 三個合法事件加 `timeout_ms`、兩層 `skill://` glob 的 `resources`、明列的 `tools`,並通過 `kiro-cli agent validate`)與 `~/.kiro/settings/cli.json` 的 `chat.defaultAgent=jsc`;四支非 claude 的接線命令都以 `JSC_CLI={代號}` 前綴自帶 CLI 代號,缺了它兩道閘門解不出技能名、一律安靜放行,所以 `status` 把它列成單獨一項;另有 `{連結農場根}/jsc-hooks` 符號連結建立或更新,而且它指向 jsc-hooks 的實體根目錄、不是指向自己(`readlink -f` 解得出一個存在的目錄,裡面有 `hooks/session-timer.sh` 與 `tools/jsc-wrap.sh`)、各 CLI 設定裡存下來的接線命令也都是展開後的字面絕對路徑,只有存放庫自帶的 `hooks/hooks.json` 保留 `${JSC_HOME:-$HOME/.jsc}/current/jsc-hooks` 這段變數寫法,由 hook 自己的 shell 在執行當下展開、`$JSC_HOME/backup/hooks/{cli}/{時間戳}/` 留下 purge 前的備份、出錯時 wiki 多一頁 `ERROR_{HASH}`(落在 `JSC_WIKI_REPO_ERROR` 解出的存取庫)並在索引目錄頁補一列(落在 `JSC_WIKI_REPO_CONTENTS` 解出的另一個存取庫,那一列的第 2 格寫成 `[{頁名}]({絕對網址})`,網址取自 `gitea.sh wiki-url` 且已經過 `link-check.sh` 驗到結束碼 0;驗不過那一格只有純文字頁名,`report-error.sh` 在 stderr 留一行 `[jsc]` 講明是哪一種原因)、修正路徑留下一條對 `develop` 的 PR 。接線完成後 `$JSC_HOME/usage/events.jsonl` 會逐行長出 `{kind:hook}` 事件,每支 hook 每次執行一筆,欄位含 `status` 與實際結束碼;跑過技能之後另有 `{kind:skill,phase:start}`。事件寫不進去不影響任何 hook 的結束碼 |
|
| 可驗證跡象 | 各 CLI 的設定檔多出 jsc 段落:codex 的 `config.toml` 標記段落、`hooks/codex-hooks.json`(從 `hooks/hooks.json` 推導,matcher `Skill` 換成 `Bash`)與 `.codex-plugin/plugin.json` 指過去的 `hooks` 路徑字串、copilot 的 `~/.copilot/settings.json` 頂層 `hooks` 鍵(matcher `skill`,合併不覆寫,`enabledPlugins` 與第三方條目原樣保留)與 `$COPILOT_HOME` 底下的指引檔、antigravity 的 `~/.gemini/config/hooks.json` 的 `jsc` 段落(`PreToolUse` 為 Grouped、matcher `^view_file$`,`PreInvocation` 維持 Flat)、kiro 的 `~/.kiro/agents/jsc.json`(`hooks` 為 `agentSpawn`、`userPromptSubmit`、`stop` 三個合法事件加 `timeout_ms`、兩層 `skill://` glob 的 `resources`、明列的 `tools`,並通過 `kiro-cli agent validate`)與 `~/.kiro/settings/cli.json` 的 `chat.defaultAgent=jsc`;四支非 claude 的接線命令都以 `JSC_CLI={代號}` 前綴自帶 CLI 代號,缺了它兩道閘門解不出技能名、一律安靜放行,所以 `status` 把它列成單獨一項;另有 `{連結農場根}/jsc-hooks` 符號連結建立或更新,而且它指向 jsc-hooks 的實體根目錄、不是指向自己(`readlink -f` 解得出一個存在的目錄,裡面有 `hooks/session-timer.sh` 與 `tools/jsc-wrap.sh`)、各 CLI 設定裡存下來的接線命令也都是展開後的字面絕對路徑,只有存放庫自帶的 `hooks/hooks.json` 保留 `${JSC_HOME:-$HOME/.jsc}/current/jsc-hooks` 這段變數寫法,由 hook 自己的 shell 在執行當下展開、`$JSC_HOME/backup/hooks/{cli}/{時間戳}/` 留下 purge 前的備份、出錯時 wiki 多一頁 `ERROR_{HASH}`(落在 `JSC_WIKI_REPO_ERROR` 解出的存取庫)並在索引目錄頁補一列(落在 `JSC_WIKI_REPO_CONTENTS` 解出的另一個存取庫,那一列的第 2 格寫成 `[{頁名}]({絕對網址})`,網址取自 `gitea.sh wiki-url` 且已經過 `link-check.sh` 驗到結束碼 0;驗不過那一格只有純文字頁名,`report-error.sh` 在 stderr 留一行 `[jsc]` 講明是哪一種原因)、修正路徑留下一條對 `develop` 的 PR 。接線完成後 `$JSC_HOME/usage/events.jsonl` 會逐行長出 `{kind:hook}` 事件,每支 hook 每次執行一筆,欄位含 `status` 與實際結束碼;跑過技能之後另有 `{kind:skill,phase:start}`。事件寫不進去不影響任何 hook 的結束碼 |
|
||||||
|
|||||||
+8
-2
@@ -136,8 +136,14 @@
|
|||||||
# 有這個逃生門才測得動 purge 的 JSON 刪鍵:預設路徑是使用者自己的設定檔,拿真檔案試刪
|
# 有這個逃生門才測得動 purge 的 JSON 刪鍵:預設路徑是使用者自己的設定檔,拿真檔案試刪
|
||||||
# 等於拿使用者的環境當測試場。指向一份複製品就能完整跑過 purge claude 而不動到本人設定。
|
# 等於拿使用者的環境當測試場。指向一份複製品就能完整跑過 purge claude 而不動到本人設定。
|
||||||
set -u
|
set -u
|
||||||
HERE=$(cd "$(dirname "$0")" && pwd)
|
# 這兩行一定要實體解析(`cd -P` 加 `pwd -P`),不能拿邏輯路徑。
|
||||||
ROOT=$(cd "$HERE/.." && pwd)
|
# ROOT 會被 ensure_stable_root() 當成 `ln -sfn "$ROOT" "$_link"` 的目標,而這支腳本本身
|
||||||
|
# 常常就是經由那條連結被叫起來的。邏輯解析會把連結原樣留在路徑裡,於是 ROOT 等於連結
|
||||||
|
# 自己,連結被改成指向自己,之後每一支 hook 的接線路徑都解不開,全機器 hook 一起失效。
|
||||||
|
# 這件事實際發生過。實體解析永遠退到連結指向的那個實際目錄,這個失敗模式就不可能成立。
|
||||||
|
# 事後才用 `[ -f ]` 檢查連結通不通不夠:那要等連結已經被寫壞才攔得到。
|
||||||
|
HERE=$(CDPATH= cd -P -- "$(dirname -- "$0")" && pwd -P)
|
||||||
|
ROOT=$(CDPATH= cd -P -- "$HERE/.." && pwd -P)
|
||||||
HOOKS="$ROOT/hooks"
|
HOOKS="$ROOT/hooks"
|
||||||
JSC_HOME="${JSC_HOME:-$HOME/.jsc}"
|
JSC_HOME="${JSC_HOME:-$HOME/.jsc}"
|
||||||
WIRE_ROOT="$ROOT"
|
WIRE_ROOT="$ROOT"
|
||||||
|
|||||||
Reference in New Issue
Block a user