fix: harden Codex skill installer staging

This commit is contained in:
Liuyaguang
2026-06-08 16:58:23 +08:00
parent 31fd544c53
commit 96a4983e77
5 changed files with 29 additions and 17 deletions
+1 -1
View File
@@ -278,7 +278,7 @@ bash CLI-Anything/codex-skill/scripts/install.sh
```
脚本会把 skill 安装到 `$CODEX_HOME/skills/cli-anything`;如果没有设置 `CODEX_HOME`,则默认安装到 `~/.codex/skills/cli-anything`
安装器还会把权威版本的 `HARNESS.md`、命令规范、按需指南、可复用辅助脚本、skill 模板和 preview 协议复制到已安装 skill 的 `references/``scripts/``assets/` 目录。这样 Codex skill 可以独立工作,同时仍以 `cli-anything-plugin/` 作为唯一权威来源。
安装器还会把权威版本的 `HARNESS.md`、命令规范、按需指南、可复用辅助脚本、skill 模板和 preview 协议复制到已安装 skill 的 `references/``scripts/` 目录。这样 Codex skill 可以独立工作,同时仍以 `cli-anything-plugin/` 作为唯一权威来源。
安装后重启 Codex,让它重新发现这个 skill。
+2 -2
View File
@@ -38,7 +38,7 @@ skill so a normal Codex installation is self-contained.
| `scripts/repl_skin.py` | Copy into generated harnesses as `utils/repl_skin.py` |
| `scripts/preview_bundle.py` | Copy into preview-capable harnesses as `utils/preview_bundle.py` |
| `scripts/skill_generator.py` | Generate canonical and packaged CLI skills |
| `assets/SKILL.md.template` | Skill generation template |
| `scripts/templates/SKILL.md.template` | Skill generation template used by `skill_generator.py` |
| `references/docs/PREVIEW_PROTOCOL.md` | Shared preview bundle protocol |
When reading vendored documents, apply these path remappings instead of resolving
@@ -50,7 +50,7 @@ plugin paths against the current working directory:
| `cli-anything-plugin/repl_skin.py` | `scripts/repl_skin.py` |
| `cli-anything-plugin/preview_bundle.py` | `scripts/preview_bundle.py` |
| `cli-anything-plugin/skill_generator.py` | `scripts/skill_generator.py` |
| `templates/SKILL.md.template` | `assets/SKILL.md.template` |
| `templates/SKILL.md.template` | `scripts/templates/SKILL.md.template` |
| `docs/PREVIEW_PROTOCOL.md` | `references/docs/PREVIEW_PROTOCOL.md` |
## Inputs
+8 -6
View File
@@ -16,7 +16,7 @@ $codexHome = if ($env:CODEX_HOME) {
$destRoot = Join-Path $codexHome "skills"
$destDir = Join-Path $destRoot "cli-anything"
$stagingDir = Join-Path $destRoot ".cli-anything.tmp.$PID"
$stagingDir = $null
if (-not (Test-Path (Join-Path $pluginDir "HARNESS.md"))) {
throw "Cannot find canonical CLI-Anything resources at: $pluginDir`nRun this installer from a full CLI-Anything repository checkout."
@@ -33,16 +33,18 @@ if (Test-Path $destDir) {
}
try {
Copy-Item -Path $skillDir -Destination $stagingDir -Recurse
$stagingDir = Join-Path $destRoot (".cli-anything.tmp." + [System.Guid]::NewGuid().ToString("N"))
New-Item -ItemType Directory -Path $stagingDir | Out-Null
Get-ChildItem -LiteralPath $skillDir -Force | Copy-Item -Destination $stagingDir -Recurse -Force
$assetDir = Join-Path $stagingDir "assets"
$referenceDir = Join-Path $stagingDir "references"
$referenceCommands = Join-Path $referenceDir "commands"
$referenceDocs = Join-Path $referenceDir "docs"
$referenceGuides = Join-Path $referenceDir "guides"
$resourceScripts = Join-Path $stagingDir "scripts"
$scriptTemplates = Join-Path $resourceScripts "templates"
New-Item -ItemType Directory -Path $assetDir, $referenceCommands, $referenceDocs, $referenceGuides, $resourceScripts -Force | Out-Null
New-Item -ItemType Directory -Path $referenceCommands, $referenceDocs, $referenceGuides, $scriptTemplates -Force | Out-Null
Copy-Item -Path (Join-Path $pluginDir "HARNESS.md") -Destination (Join-Path $referenceDir "HARNESS.md")
Copy-Item -Path (Join-Path $pluginDir "commands/*.md") -Destination $referenceCommands
@@ -50,12 +52,12 @@ try {
Copy-Item -Path (Join-Path $pluginDir "repl_skin.py") -Destination (Join-Path $resourceScripts "repl_skin.py")
Copy-Item -Path (Join-Path $pluginDir "preview_bundle.py") -Destination (Join-Path $resourceScripts "preview_bundle.py")
Copy-Item -Path (Join-Path $pluginDir "skill_generator.py") -Destination (Join-Path $resourceScripts "skill_generator.py")
Copy-Item -Path (Join-Path $pluginDir "templates/*") -Destination $assetDir
Copy-Item -Path (Join-Path $pluginDir "templates/*") -Destination $scriptTemplates
Copy-Item -Path $previewProtocol -Destination (Join-Path $referenceDocs "PREVIEW_PROTOCOL.md")
Move-Item -Path $stagingDir -Destination $destDir
} finally {
if (Test-Path $stagingDir) {
if ($stagingDir -and (Test-Path $stagingDir)) {
Remove-Item -Path $stagingDir -Recurse -Force
}
}
+8 -6
View File
@@ -9,7 +9,7 @@ PLUGIN_DIR="${REPO_ROOT}/cli-anything-plugin"
PREVIEW_PROTOCOL="${REPO_ROOT}/docs/PREVIEW_PROTOCOL.md"
DEST_ROOT="${CODEX_HOME:-$HOME/.codex}/skills"
DEST_DIR="${DEST_ROOT}/cli-anything"
STAGING_DIR="${DEST_ROOT}/.cli-anything.tmp.$$"
STAGING_DIR=""
if [[ ! -f "${PLUGIN_DIR}/HARNESS.md" ]]; then
echo "Cannot find canonical CLI-Anything resources at: ${PLUGIN_DIR}" >&2
@@ -32,17 +32,19 @@ if [[ -e "${DEST_DIR}" ]]; then
fi
cleanup() {
rm -rf "${STAGING_DIR}"
if [[ -n "${STAGING_DIR}" && -d "${STAGING_DIR}" ]]; then
rm -rf "${STAGING_DIR}"
fi
}
trap cleanup EXIT
cp -R "${SKILL_DIR}" "${STAGING_DIR}"
STAGING_DIR="$(mktemp -d "${DEST_ROOT}/.cli-anything.tmp.XXXXXX")"
cp -R "${SKILL_DIR}/." "${STAGING_DIR}/"
mkdir -p \
"${STAGING_DIR}/assets" \
"${STAGING_DIR}/references/commands" \
"${STAGING_DIR}/references/docs" \
"${STAGING_DIR}/references/guides" \
"${STAGING_DIR}/scripts"
"${STAGING_DIR}/scripts/templates"
cp "${PLUGIN_DIR}/HARNESS.md" "${STAGING_DIR}/references/HARNESS.md"
cp "${PLUGIN_DIR}/commands/"*.md "${STAGING_DIR}/references/commands/"
@@ -50,7 +52,7 @@ cp "${PLUGIN_DIR}/guides/"*.md "${STAGING_DIR}/references/guides/"
cp "${PLUGIN_DIR}/repl_skin.py" "${STAGING_DIR}/scripts/repl_skin.py"
cp "${PLUGIN_DIR}/preview_bundle.py" "${STAGING_DIR}/scripts/preview_bundle.py"
cp "${PLUGIN_DIR}/skill_generator.py" "${STAGING_DIR}/scripts/skill_generator.py"
cp "${PLUGIN_DIR}/templates/"* "${STAGING_DIR}/assets/"
cp "${PLUGIN_DIR}/templates/"* "${STAGING_DIR}/scripts/templates/"
cp "${PREVIEW_PROTOCOL}" "${STAGING_DIR}/references/docs/PREVIEW_PROTOCOL.md"
mv "${STAGING_DIR}" "${DEST_DIR}"
+10 -2
View File
@@ -9,6 +9,7 @@ PLUGIN_DIR="${REPO_ROOT}/cli-anything-plugin"
TMP_DIR="$(mktemp -d)"
CODEX_HOME="${TMP_DIR}/codex-home"
INSTALLED_DIR="${CODEX_HOME}/skills/cli-anything"
STALE_STAGING_DIR="${CODEX_HOME}/skills/.cli-anything.tmp.stale"
cleanup() {
rm -rf "${TMP_DIR}"
@@ -32,9 +33,16 @@ assert_tree_same() {
diff -qr "$1" "$2" >/dev/null || fail "directories differ: $1 $2"
}
mkdir -p "${STALE_STAGING_DIR}/codex-skill"
echo "left over from an interrupted install" > "${STALE_STAGING_DIR}/codex-skill/stale.txt"
CODEX_HOME="${CODEX_HOME}" bash "${SKILL_DIR}/scripts/install.sh"
assert_file "${INSTALLED_DIR}/SKILL.md"
[[ -d "${STALE_STAGING_DIR}" ]] ||
fail "installer reused or removed the stale staging directory"
[[ ! -d "${INSTALLED_DIR}/codex-skill" ]] ||
fail "installer created a nested codex-skill directory"
assert_file "${INSTALLED_DIR}/references/HARNESS.md"
assert_file "${INSTALLED_DIR}/references/commands/cli-anything.md"
assert_file "${INSTALLED_DIR}/references/commands/refine.md"
@@ -47,7 +55,7 @@ assert_file "${INSTALLED_DIR}/references/guides/preview-methodology.md"
assert_file "${INSTALLED_DIR}/scripts/repl_skin.py"
assert_file "${INSTALLED_DIR}/scripts/preview_bundle.py"
assert_file "${INSTALLED_DIR}/scripts/skill_generator.py"
assert_file "${INSTALLED_DIR}/assets/SKILL.md.template"
assert_file "${INSTALLED_DIR}/scripts/templates/SKILL.md.template"
assert_file "${INSTALLED_DIR}/references/docs/PREVIEW_PROTOCOL.md"
assert_same "${PLUGIN_DIR}/HARNESS.md" "${INSTALLED_DIR}/references/HARNESS.md"
@@ -57,7 +65,7 @@ assert_same "${PLUGIN_DIR}/skill_generator.py" "${INSTALLED_DIR}/scripts/skill_g
assert_same "${REPO_ROOT}/docs/PREVIEW_PROTOCOL.md" "${INSTALLED_DIR}/references/docs/PREVIEW_PROTOCOL.md"
assert_tree_same "${PLUGIN_DIR}/commands" "${INSTALLED_DIR}/references/commands"
assert_tree_same "${PLUGIN_DIR}/guides" "${INSTALLED_DIR}/references/guides"
assert_tree_same "${PLUGIN_DIR}/templates" "${INSTALLED_DIR}/assets"
assert_tree_same "${PLUGIN_DIR}/templates" "${INSTALLED_DIR}/scripts/templates"
python3 -m py_compile \
"${INSTALLED_DIR}/scripts/repl_skin.py" \