deploy 的腳本呼叫全改成字面絕對路徑,開頭解一次根目錄,無人看管的輪次不再停在第一支腳本 #59
@@ -17,10 +17,10 @@
|
||||
| 項目 | 內容 |
|
||||
| --- | --- |
|
||||
| 觸發時機 | 整組 jsc 技能要在這台機器的每一支已安裝 CLI 上安裝、更新或解除安裝時用。只處理單一技能不用;只想知道版本落後與否,看 doctor 就夠 |
|
||||
| 關鍵步驟 | 同時取得三項事實(detect-clis.sh 的 CLI 清單、version-guard.sh 的 report 版本表與 recommend 結論、marketplace.json 的 domain 清單)、把版本表原樣秀出並定出建議、依 jsc-ask 決策樹問出模式(呼叫端已帶模式就沿用並標明來源)、每支 CLI 各開一個 sub agent 同時跑 tools/deploy.sh {mode} {cli} {domain}...、安裝或更新後把 CLI 清單交給 jsc-hooks:hooks-install、整台機器跑一次 tools/write-guides.sh、彙整每支 CLI 的結果並要求重新啟動工作階段,最後呼叫 jsc-hooks/tools/report-status.sh skill-end jsc-cli:deploy 寫下這一輪的結果。收尾那一筆接在彙整回報之後,不取代它;走每一條出口,連停在偵測不到 CLI 那一條也要寫。status 五選一,每支 CLI 都回 0、hooks-install 判定乾淨、兩份指引都寫成是 ok,偵測不到任何 CLI、整輪沒下過任何外掛命令是 blocked,marketplace 讀不到或每支 CLI 都失敗、冒煙結果出現 No such file 是 failed,部分 CLI 成功部分失敗、有 domain 被 skip、或 write-guides.sh 回 4 讓機器沒有最新指引是 degraded,使用者沒選模式或在第一支 CLI 開跑前停手是 aborted。detail 只放模式與各項筆數,cmd 與 exit 行留在回報裡 |
|
||||
| 外部呼叫 | jsc-cli/tools/detect-clis.sh、jsc-cli/tools/deploy.sh、jsc-cli/tools/write-guides.sh、jsc-cli/tools/check-requires.sh(由 deploy.sh 在每個 domain 更新前轉呼叫)、jsc-hooks/hooks/version-guard.sh 的 report 與 recommend、jsc-hooks/hooks/restart-gate.sh require(由 deploy.sh 收尾轉呼叫)、jsc-gitea/tools/gitea.sh 讀 plugins/meta 的 marketplace.json、jsc-hooks/tools/report-status.sh skill-end、jsc-ask:ask、jsc-hooks:hooks-install |
|
||||
| 完成條件 | 每一支偵測到的 CLI 都回報結束碼與 result 行,每個 skip、warn、compat 行都照實列出;安裝或更新還要拿到 hooks-install 對每支 CLI 的總結,兩份指引都印出 wrote,收尾印出重啟指示與兩份指引路徑。這一輪還要留下一筆 skill-end 事件,或是腳本不在而略過,兩者都算收好;略過不影響這支技能的結束碼 |
|
||||
| 可驗證跡象 | 各 CLI 的外掛目錄多出或少掉 jsc-{domain}:claude 與 codex 在各自的 plugin 快取、copilot 在 installed-plugins、antigravity 與 kiro 走 $JSC_LOCAL_PLUGINS 的本地 clone 與 $JSC_KIRO_SKILLS 的複製。$JSC_HOME/restart-required.d/{cli} 出現這次的重啟狀態檔;$JSC_HOME/update-guide.md 與 $JSC_HOME/remove-guide.md 被重寫;各 CLI 的 hook 設定檔由 hooks-install 改寫;$JSC_HOME/usage/events.jsonl 會多一筆 {kind:skill,phase:end} 事件,name 是 jsc-cli:deploy,status 與 exit 就是這一輪的結果 |
|
||||
| 關鍵步驟 | 先跑一次 `readlink -f "$JSC_HOME/current"` 解出 `current` 這個目錄的絕對路徑,解到那一層就停,不再往下解成帶版本號的快取路徑——那種路徑放不進允許清單,版本號寫成萬用字元也對不上;同一步再跑 `[ -d "{剛印出來的路徑}" ]` 確認目錄存在,`JSC_HOME` 沒設時它印的是 `/current`、結束碼 0,非空又是絕對路徑,只看那兩項擋不下來。整輪只解這一次,之後每一次跨外掛腳本呼叫都填成那個字面絕對路徑,不留 `$JSC_HOME` 也不留波浪號;技能自己那四支 `tools/*.sh` 不在 `current` 底下(那裡只有 `jsc-assist`、`jsc-gitea`、`jsc-hooks`),根目錄取自 CLI 載入這支技能時講明的外掛基底目錄,原樣當字面絕對路徑用,一個指令都不跑,四支一律寫成 `{外掛根目錄}/tools/{腳本}`;那個基底目錄帶版本號,四次呼叫都會跳權限詢問,這一支有人在現場(第三步要問模式)所以按得掉,無人值守的技能不得照抄,叫用文字沒講明基底目錄就回報外掛根目錄不明並停手,不猜前綴——權限層靜態比對路徑,帶未展開變數的呼叫一律要人核准,無人看管的輪次會停在第一支腳本,補權限規則也擋不住,因為規則字面同樣是靜態比對;解不出來就停手回報。接著同時取得三項事實(detect-clis.sh 的 CLI 清單、version-guard.sh 的 report 版本表與 recommend 結論、marketplace.json 的 domain 清單)、把版本表原樣秀出並定出建議、依 jsc-ask 決策樹問出模式(呼叫端已帶模式就沿用並標明來源)、每支 CLI 各開一個 sub agent 同時跑 tools/deploy.sh {mode} {cli} {domain}...、安裝或更新後把 CLI 清單交給 jsc-hooks:hooks-install、整台機器跑一次 tools/write-guides.sh、彙整每支 CLI 的結果並要求重新啟動工作階段,最後呼叫 jsc-hooks/tools/report-status.sh skill-end jsc-cli:deploy 寫下這一輪的結果。收尾那一筆接在彙整回報之後,不取代它;走每一條出口,連停在偵測不到 CLI 那一條也要寫。status 五選一,每支 CLI 都回 0、hooks-install 判定乾淨、兩份指引都寫成是 ok,偵測不到任何 CLI、整輪沒下過任何外掛命令是 blocked,marketplace 讀不到或每支 CLI 都失敗、冒煙結果出現 No such file 是 failed,部分 CLI 成功部分失敗、有 domain 被 skip、或 write-guides.sh 回 4 讓機器沒有最新指引是 degraded,使用者沒選模式或在第一支 CLI 開跑前停手是 aborted。detail 只放模式與各項筆數,cmd 與 exit 行留在回報裡 |
|
||||
| 外部呼叫 | `readlink -f "$JSC_HOME/current"` 解出 `current` 這個目錄的絕對路徑,加上同一步的 `[ -d ]` 確認,是整輪唯一容許帶變數的兩個指令;跨外掛腳本一律用它組成的字面絕對路徑呼叫:{current 目錄}/jsc-hooks/hooks/version-guard.sh 的 report 與 recommend、{current 目錄}/jsc-gitea/tools/gitea.sh 讀 plugins/meta 的 marketplace.json、{current 目錄}/jsc-hooks/tools/report-status.sh skill-end。技能自己那四支腳本走外掛根目錄組成的字面絕對路徑:{外掛根目錄}/tools/detect-clis.sh、{外掛根目錄}/tools/deploy.sh、{外掛根目錄}/tools/write-guides.sh、{外掛根目錄}/tools/check-requires.sh(由 deploy.sh 在每個 domain 更新前轉呼叫)。第四步那段內文提到的 `jsc-hooks/hooks/version-guard.sh` 是在講擋人發生在哪一層,不是這支技能要下的呼叫,整輪只有第一步那一次真的跑它。另有 jsc-hooks/hooks/restart-gate.sh require(由 deploy.sh 收尾轉呼叫)、jsc-ask:ask、jsc-hooks:hooks-install |
|
||||
| 完成條件 | `current` 那個目錄在第一步就解出一條存在的絕對路徑(用 `[ -d ]` 查過,而且沒有再往下解成帶版本號的快取路徑),技能自己那四支腳本也有一條字面絕對的外掛根目錄可用,後續每一支腳本都用這兩條之一組成的字面絕對路徑呼叫;每一支偵測到的 CLI 都回報結束碼與 result 行,每個 skip、warn、compat 行都照實列出;安裝或更新還要拿到 hooks-install 對每支 CLI 的總結,兩份指引都印出 wrote,收尾印出重啟指示與兩份指引路徑。這一輪還要留下一筆 skill-end 事件,或是腳本不在而略過,兩者都算收好;略過不影響這支技能的結束碼 |
|
||||
| 可驗證跡象 | 各 CLI 的外掛目錄多出或少掉 jsc-{domain}:claude 與 codex 在各自的 plugin 快取、copilot 在 installed-plugins、antigravity 與 kiro 走 $JSC_LOCAL_PLUGINS 的本地 clone 與 $JSC_KIRO_SKILLS 的複製。$JSC_HOME/restart-required.d/{cli} 出現這次的重啟狀態檔;$JSC_HOME/update-guide.md 與 $JSC_HOME/remove-guide.md 被重寫;各 CLI 的 hook 設定檔由 hooks-install 改寫;$JSC_HOME/usage/events.jsonl 會多一筆 {kind:skill,phase:end} 事件,name 是 jsc-cli:deploy,status 與 exit 就是這一輪的結果。回報與逐行紀錄裡出現的腳本路徑全是字面絕對路徑,找不到 `$JSC_HOME`、`$` 開頭或波浪號開頭的呼叫,唯一的例外是開頭那一次 `readlink -f "$JSC_HOME/current"` 與同一步的 `[ -d ]` 確認;跨外掛那幾支的路徑中段是 `current`,不是 `cache/jsc/{外掛}/{版本}`,技能自己那四支則一律是外掛根目錄接 `tools/`,沒有一支寫成裸的相對路徑 |
|
||||
|
||||
## doctor
|
||||
|
||||
|
||||
+41
-9
@@ -5,6 +5,38 @@ description: Batch install, update, or uninstall the whole jsc skill set on ever
|
||||
|
||||
# deploy — batch install, update, or uninstall the skill set
|
||||
|
||||
## Path rule — every script call is a literal absolute path
|
||||
|
||||
Write every script call in this skill as a literal absolute path. Never hand the shell a path that still holds a variable or a tilde — `$JSC_HOME/...`, `~/.jsc/...`, or anything like them. The permission layer matches paths statically. It never expands a variable or a tilde, so such a path matches no allow rule, and the call falls through to an approval prompt. An unattended round has nobody to approve it. The run then dies at its first script, before it deploys anything.
|
||||
|
||||
Measured on a real machine, not assumed. `$JSC_HOME/current/jsc-assist/tools/patrol.sh` was blocked and never ran. `~/.jsc/current/...` was blocked and never ran. `/root/.jsc/current/...` ran. Adding an allow rule that itself starts with `$JSC_HOME` to `~/.claude/settings.json` changed nothing: the call stayed blocked. A wider allow list is not the fix, because the rule text is matched statically too.
|
||||
|
||||
Portability is no reason to put the variable back. Step 0 resolves the root once, at run time, on whatever machine this runs on — that is where portability comes from. Rewriting `{JSC_ROOT}/jsc-hooks/...` back to `$JSC_HOME/current/jsc-hooks/...` for tidiness re-breaks every unattended round.
|
||||
|
||||
## Step 0 — resolve the two roots, once
|
||||
|
||||
Before step 1, run this one command:
|
||||
|
||||
`readlink -f "$JSC_HOME/current"`
|
||||
|
||||
It prints one absolute directory: the absolute path of the `current` directory itself. Call it `{JSC_ROOT}` for the rest of this document. **Stop at that directory — never resolve one level further.** `current` is an ordinary directory, and the symbolic links are its entries, one per plugin; resolving one of those entries lands on the versioned plugin cache (`/root/.claude/plugins/cache/jsc/jsc-hooks/0.4.2`, say), and a versioned path is exactly the kind no allow rule can hold — a rule with `*` where the version segment goes matches nothing, measured. `{JSC_ROOT}` is the version-free root, and staying at it is the whole point. This is the only place a variable may appear. The shell expands it inside the command itself, so no unexpanded path ever reaches the permission layer.
|
||||
|
||||
Substitute `{JSC_ROOT}` with that directory in every later call, so what runs is a literal absolute path. `{JSC_ROOT}/jsc-hooks/hooks/version-guard.sh` becomes, for example, `/root/.jsc/current/jsc-hooks/hooks/version-guard.sh`.
|
||||
|
||||
Resolve it once, at the start of the run. Do not re-resolve it per call. Do not add a tool that prints it.
|
||||
|
||||
Empty output, a non-zero exit, or a path that is not an existing directory → stop and report that `$JSC_HOME/current` does not resolve. **The third item is the one the first two wave through**, so check it: with `JSC_HOME` unset the command prints `/current` and exits 0 — non-empty, absolute, and nowhere — and every literal path built from it then names a place that is not there. Run `[ -d "{the path just printed}" ]` in the same approved step as the resolve, and treat only an existing directory as a root. Every cross-plugin script this skill calls lives under it.
|
||||
|
||||
### The second root — this skill's own `tools/`
|
||||
|
||||
`jsc-cli` is **not** one of the links under `{JSC_ROOT}`; that directory carries `jsc-assist`, `jsc-gitea` and `jsc-hooks` and nothing else. So `tools/detect-clis.sh`, `tools/deploy.sh`, `tools/check-requires.sh` and `tools/write-guides.sh` cannot be reached through `{JSC_ROOT}`, and none of them may be written as a bare relative path either — the rule above wants a literal absolute path at every call site, and a call site with no way to build one is where a prefix gets guessed.
|
||||
|
||||
They sit at `{plugin root}/tools/`, and the plugin root is the base directory the CLI states when it loads this skill. Take that literal path verbatim, call it `{CLI_ROOT}`, and write all four calls as `{CLI_ROOT}/tools/{script}` — `/root/.claude/plugins/cache/jsc/jsc-cli/0.3.2/tools/deploy.sh`, for example. No command runs for this one, and it is taken once, like `{JSC_ROOT}`.
|
||||
|
||||
That base directory carries a version segment, so no allow rule covers it and each of those four calls raises an approval prompt. **That is acceptable in this skill and in no unattended one**: `deploy` runs with a person in front of it — step 3 asks them for the mode, step 4 rewrites every CLI's plugin set — so there is somebody to approve. Never carry this branch into a skill that runs from a scheduler, and never guess a prefix when the invocation states no base directory: report that this skill's own plugin root is unknown and stop, because a guessed prefix runs some other version's copy of these scripts, or nothing at all.
|
||||
|
||||
Done when `{JSC_ROOT}` holds one existing absolute directory and `{CLI_ROOT}` holds one literal absolute path.
|
||||
|
||||
## Inputs a caller may pass
|
||||
|
||||
`jsc-cli:setup` already confirmed the mode with the user and already holds a fresh version report. Re-asking and re-querying would put a second decision tree in front of someone who just answered it.
|
||||
@@ -20,13 +52,13 @@ Nothing passed in → run every step as written below.
|
||||
|
||||
1. Collect the three facts the rest of the run needs. They are independent, so start all three at once and wait for all three.
|
||||
|
||||
1. **Installed CLIs** — `tools/detect-clis.sh`, printing `{name}<TAB>{path}<TAB>{version}`. Exit 0 with at least one row → take the CLI list from it. Exit 0 with no row → stop, and report that none of claude, codex, copilot, antigravity, kiro is installed. Any non-zero exit → stop and report the exit code and stderr; never guess a CLI list.
|
||||
2. **Version evidence and recommendation** — two subcommands of `jsc-hooks/hooks/version-guard.sh`, both needed, run together: `report` prints the per-plugin rows `{domain}<TAB>{本機}<TAB>{遠端}<TAB>{落後|最新|超前|查詢失敗}` closing with `behind<TAB>{count}`, and `recommend` prints one single line and nothing else — `recommend<TAB>{update|none|unverifiable}`. `recommend` deliberately never reprints the table, so its second column stays readable by `cut`; the version table that steps 2, 3 and 7 show comes from `report`, and the conclusion comes from `recommend`. Skip this collector when the caller passed a version report.
|
||||
1. **Installed CLIs** — `{CLI_ROOT}/tools/detect-clis.sh`, printing `{name}<TAB>{path}<TAB>{version}`. Exit 0 with at least one row → take the CLI list from it. Exit 0 with no row → stop, and report that none of claude, codex, copilot, antigravity, kiro is installed. Any non-zero exit → stop and report the exit code and stderr; never guess a CLI list.
|
||||
2. **Version evidence and recommendation** — two subcommands of `{JSC_ROOT}/jsc-hooks/hooks/version-guard.sh`, both needed, run together: `report` prints the per-plugin rows `{domain}<TAB>{本機}<TAB>{遠端}<TAB>{落後|最新|超前|查詢失敗}` closing with `behind<TAB>{count}`, and `recommend` prints one single line and nothing else — `recommend<TAB>{update|none|unverifiable}`. `recommend` deliberately never reprints the table, so its second column stays readable by `cut`; the version table that steps 2, 3 and 7 show comes from `report`, and the conclusion comes from `recommend`. Skip this collector when the caller passed a version report.
|
||||
3. **Domain list** — read `plugins[].name` from the unified marketplace (**never hardcode it**; this skill then follows automatically when domains are added or removed):
|
||||
`jsc-gitea/tools/gitea.sh api GET /repos/plugins/meta/raw/.claude-plugin/marketplace.json`.
|
||||
`{JSC_ROOT}/jsc-gitea/tools/gitea.sh api GET /repos/plugins/meta/raw/.claude-plugin/marketplace.json`.
|
||||
Exit 0 with at least one `plugins[].name` → use that list. Exit 0 with an empty or unparseable list → stop and report that the marketplace holds no plugin entry. Any non-zero exit → stop and report the exit code and stderr; a partial domain list would install a partial skill set and look successful.
|
||||
|
||||
The marketplace is unified as `jsc`; the install token is `jsc-{domain}@jsc`. Each `plugins[].name` already carries the `jsc-` prefix (e.g. `jsc-ask`) — pass it to `tools/deploy.sh` as-is, prefixed or not; the script normalizes it.
|
||||
The marketplace is unified as `jsc`; the install token is `jsc-{domain}@jsc`. Each `plugins[].name` already carries the `jsc-` prefix (e.g. `jsc-ask`) — pass it to `{CLI_ROOT}/tools/deploy.sh` as-is, prefixed or not; the script normalizes it.
|
||||
|
||||
Done when the CLI list holds at least one CLI, the domain list holds at least one name, and the recommendation is either in hand or explicitly inherited from the caller.
|
||||
|
||||
@@ -50,7 +82,7 @@ Nothing passed in → run every step as written below.
|
||||
|
||||
Done when the user has named exactly one of `install`, `update` or `uninstall`, or the inherited mode is named with its source.
|
||||
|
||||
4. Run `tools/deploy.sh {mode} {cli} {domain}...` once per detected CLI, passing the whole domain list in one call so the marketplace command runs only once. This step **MUST run as a sub agent**, one sub agent per CLI, and **all of them start together** — the CLIs write to separate plugin directories, so serialising them only adds up their install times.
|
||||
4. Run `{CLI_ROOT}/tools/deploy.sh {mode} {cli} {domain}...` once per detected CLI, passing the whole domain list in one call so the marketplace command runs only once. This step **MUST run as a sub agent**, one sub agent per CLI, and **all of them start together** — the CLIs write to separate plugin directories, so serialising them only adds up their install times.
|
||||
|
||||
The script prints `cmd` and `exit` lines for every command, one `requires` line before each domain update, optional `compat` lines for Codex cache links, and one `result` line at the end; `-n` prints the commands without running them.
|
||||
|
||||
@@ -61,17 +93,17 @@ Nothing passed in → run every step as written below.
|
||||
| 2 | Usage error — the mode, the CLI name or the domain list is wrong. Report it as a defect in this skill, and do not retry with a guessed argument |
|
||||
| other | Record that CLI as failed with the exit code and stderr |
|
||||
|
||||
On update, `tools/check-requires.sh {cli} {manifest}` checks each domain's `jsc.requires` before that domain is updated. Exit 0 updates the domain as usual. Exit 1 — a missing or too-old required jsc plugin — prints a `warn` line and the domain **is still updated**: skipping it would leave a behind domain permanently unable to reach the version its dependency needs. The block lives one layer up, at skill invocation time, where `jsc-hooks/hooks/version-guard.sh` stops that domain's skills. Exit 4 — the manifest is unreadable, is not valid JSON, or python3 is missing — prints a `note` line and also still updates the domain: no verdict is not the same fact as behind, so it gets its own line rather than a `warn` that would send the operator hunting for a version problem that is not there. Exit 2 or any other code — a `check-requires.sh` usage error or a broken script — prints a `skip` line and leaves that domain untouched, because a checker that failed outright is not a pass. Codex update preserves old `jsc-cli` and `jsc-hooks` cache version paths as symlinks to the newest installed version, so a still-running Codex deploy can keep using its helper scripts and a still-running Codex session whose hook_run_id points at the old cache can finish without `No such file`. Antigravity cannot install from a Gitea URL, so the script clones each domain into the local plugin directory (`JSC_LOCAL_PLUGINS`, default `$JSC_HOME/plugins`) and installs from that path — keep that clone, because update pulls the same one. That default deliberately avoids a development checkout: when the directory holds uncommitted changes or unpushed commits, the script prints a `skip` line, leaves the tree untouched, and installs the on-disk content.
|
||||
On update, `{CLI_ROOT}/tools/check-requires.sh {cli} {manifest}` checks each domain's `jsc.requires` before that domain is updated. Exit 0 updates the domain as usual. Exit 1 — a missing or too-old required jsc plugin — prints a `warn` line and the domain **is still updated**: skipping it would leave a behind domain permanently unable to reach the version its dependency needs. The block lives one layer up, at skill invocation time, where `jsc-hooks/hooks/version-guard.sh` stops that domain's skills. **That last mention is a description of where the block happens, not a call this skill makes** — nothing here runs `version-guard.sh` except step 1.2, which is written as `{JSC_ROOT}/jsc-hooks/hooks/version-guard.sh`, so do not read it as a call site that was left un-prefixed. Exit 4 — the manifest is unreadable, is not valid JSON, or python3 is missing — prints a `note` line and also still updates the domain: no verdict is not the same fact as behind, so it gets its own line rather than a `warn` that would send the operator hunting for a version problem that is not there. Exit 2 or any other code — a `check-requires.sh` usage error or a broken script — prints a `skip` line and leaves that domain untouched, because a checker that failed outright is not a pass. Codex update preserves old `jsc-cli` and `jsc-hooks` cache version paths as symlinks to the newest installed version, so a still-running Codex deploy can keep using its helper scripts and a still-running Codex session whose hook_run_id points at the old cache can finish without `No such file`. Antigravity cannot install from a Gitea URL, so the script clones each domain into the local plugin directory (`JSC_LOCAL_PLUGINS`, default `$JSC_HOME/plugins`) and installs from that path — keep that clone, because update pulls the same one. That default deliberately avoids a development checkout: when the directory holds uncommitted changes or unpushed commits, the script prints a `skip` line, leaves the tree untouched, and installs the on-disk content.
|
||||
|
||||
Done when every detected CLI has reported an exit code and a `result` line, every skipped domain has a checker-failure reason or a local-tree reason, and every `warn` domain is named with the version it still has to catch up to.
|
||||
|
||||
5. After install or update, call `jsc-hooks:hooks-install` and **hand it the CLI list from step 1.1**, so it does not probe the same five executables a second time. `hooks-install` still detects for itself when it receives no list — that fallback is what keeps it usable on its own.
|
||||
|
||||
Take its aggregate result rather than re-reading each CLI's smoke detail; the installer already judged purge, wiring, smoke and scan per CLI, and refreshes `$JSC_HOME/current/jsc-hooks` on the way — the path `deploy.sh` follows to reach `restart-gate.sh`. Keep exactly one extra judgement here, because it is a deploy-side fact the installer does not rule on: **a smoke result containing `No such file` is a failed update**, since it means a rewritten hook path cannot execute. Report it and do not let the deploy finish as successful.
|
||||
Take its aggregate result rather than re-reading each CLI's smoke detail; the installer already judged purge, wiring, smoke and scan per CLI, and refreshes `{JSC_ROOT}/jsc-hooks` on the way — the path `deploy.sh` follows to reach `restart-gate.sh`. Keep exactly one extra judgement here, because it is a deploy-side fact the installer does not rule on: **a smoke result containing `No such file` is a failed update**, since it means a rewritten hook path cannot execute. Report it and do not let the deploy finish as successful.
|
||||
|
||||
Done when hooks-install has returned an aggregate verdict for every CLI in the list, and every `No such file` in it is reported as an update failure.
|
||||
|
||||
6. After install or update, run `tools/write-guides.sh {mode} {domain}...` **once for the whole machine**, after every CLI in step 4 has finished. It rewrites `$JSC_HOME/update-guide.md` and `$JSC_HOME/remove-guide.md` from the live detection result, so the later update and removal runs have the real commands for this machine. Skip it for `uninstall`: the guides describe an installed skill set.
|
||||
6. After install or update, run `{CLI_ROOT}/tools/write-guides.sh {mode} {domain}...` **once for the whole machine**, after every CLI in step 4 has finished. It rewrites `$JSC_HOME/update-guide.md` and `$JSC_HOME/remove-guide.md` from the live detection result, so the later update and removal runs have the real commands for this machine. Skip it for `uninstall`: the guides describe an installed skill set.
|
||||
|
||||
| Exit | Action |
|
||||
| --- | --- |
|
||||
@@ -90,7 +122,7 @@ Nothing passed in → run every step as written below.
|
||||
|
||||
8. **Record how the run ended.** This is the last thing this skill does, and it runs on every path out of the skill, the ones that stop at step 1 included. Call
|
||||
|
||||
`jsc-hooks/tools/report-status.sh skill-end jsc-cli:deploy {status} {exit code} [detail]`
|
||||
`{JSC_ROOT}/jsc-hooks/tools/report-status.sh skill-end jsc-cli:deploy {status} {exit code} [detail]`
|
||||
|
||||
`{exit code}` is the exit code of whatever decided the outcome — the worst `deploy.sh` exit of the run, or the collector that stopped step 1 — and `0` when nothing failed. `{detail}` is one short line, no more than 200 characters: the mode and the per-CLI counts fit there, the `cmd` and `exit` lines do not. **If the script is not on this machine, skip this step in silence and finish the run as it stood** — missing infrastructure is not a failure, and a reporting call may never change what this skill returns or reports.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user