refactor: 重构 SKILL.md

- 所有涉及 .env 的代码块均添加 mkdir -p(或 New-Item)确保目录存在
- .env 改用标准 KEY=VALUE 格式(GITEA_TOKEN=<值>)
- 写入:printf '%s' -> printf 'GITEA_TOKEN=...'
- 读取:cat -> grep + cut 按 key 提取
- 检查:-s 大小检查 -> grep -q 按 key 检查
- 所有无标签代码块标注了语言(bash/powershell)
- 零、路径定义首部添加 escalate 权限说明
- 每处需文件写入/网络访问的操作前标注需 escalate
- 三、添加 3.1 fallback 网络不可用时的降级处理
- 限定范围:仅返回 PineSound 内部 Skills,不混入其他来源
This commit is contained in:
Pine
2026-06-08 13:55:15 +08:00
parent 19294d825b
commit a2b5a7c1f5
+120 -32
View File
@@ -6,10 +6,14 @@ allowed-tools: Read, Grep, Edit, Write, Bash
# PineSound 内部 Skills 安装器 # PineSound 内部 Skills 安装器
> **范围说明**:本 Skill 仅关注 PineSound 内部 Skills`PineSoundSkills` 组织下的仓库)。当用户查询或管理技能时,**只返回 PineSound 内部 Skills**,不涉及其他来源的技能。如果 Gitea 不可达,fallback 也只列出本地已安装的 PineSound 内部技能。
--- ---
## 零、路径定义 ## 零、路径定义
> **⚠️ 需要请求 escalate 权限**:本 Skill 需要在 `~/.codex/skills/PineSoundSkills/` 下创建目录和 `.env` 令牌文件,以及通过 `curl` 访问内网 Gitea 服务。该路径不在沙箱默认 `writable_roots` 中,内网地址不再默认网络允许列表。**所有涉及 `mkdir`、`printf`(写入 .env)、`curl`(请求 Gitea API)的命令,都必须通过 `sandbox_permissions: "require_escalated"` 请求 escalate 权限后执行。**
整个 skill 统一使用以下路径: 整个 skill 统一使用以下路径:
| 含义 | Unix | Windows | | 含义 | Unix | Windows |
@@ -23,13 +27,17 @@ allowed-tools: Read, Grep, Edit, Write, Bash
### 1.1 获取令牌(首次/令牌无效时) ### 1.1 获取令牌(首次/令牌无效时)
**流程**: agent 通过 `AskUserQuestion` 工具向用户索要令牌 → 用户输入 → 写入 `.env` → 验证。 **流程**: agent 向用户索要令牌 → 用户输入 → 先 escalate → 写入 `.env` → 验证。
> **需 escalate**: 以下命令涉及文件系统写入。
```bash ```bash
# 1. 检查 .env 是否存在且非空 # 1. 确保目录存在,再检查 .env 是否包含 GITEA_TOKEN
TOKEN_FILE=~/.codex/skills/PineSoundSkills/.env TOKEN_FILE=~/.codex/skills/PineSoundSkills/.env
mkdir -p "$(dirname "$TOKEN_FILE")"
if [ ! -f "$TOKEN_FILE" ] || [ ! -s "$TOKEN_FILE" ]; then # KEY=VALUE 格式:检查是否存在且包含 GITEA_TOKEN 键
if [ ! -f "$TOKEN_FILE" ] || ! grep -q "^GITEA_TOKEN=" "$TOKEN_FILE" 2>/dev/null; then
echo "TOKEN_MISSING" echo "TOKEN_MISSING"
fi fi
@@ -39,18 +47,18 @@ fi
索要到令牌后,执行存储: 索要到令牌后,执行存储:
```bash ```bash
# 2. 创建目录并写入令牌 # 2. 创建目录并写入令牌KEY=VALUE 格式)
mkdir -p ~/.codex/skills/PineSoundSkills mkdir -p ~/.codex/skills/PineSoundSkills
# 用 printf 写入,避免 echo 对特殊字符的转义问题 # 用 KEY=VALUE 格式写入,避免 echo 对特殊字符的转义问题
printf '%s' "$GITEA_TOKEN" > ~/.codex/skills/PineSoundSkills/.env printf "GITEA_TOKEN=%s\n" "$GITEA_TOKEN" > ~/.codex/skills/PineSoundSkills/.env
# 3. Unix: 设置权限仅 owner 可读写 # 3. Unix: 设置权限仅 owner 可读写
chmod 600 ~/.codex/skills/PineSoundSkills/.env chmod 600 ~/.codex/skills/PineSoundSkills/.env
# 4. 验证写入成功 # 4. 验证写入成功
if [ -s ~/.codex/skills/PineSoundSkills/.env ]; then if grep -q "^GITEA_TOKEN=" ~/.codex/skills/PineSoundSkills/.env 2>/dev/null; then
echo "令牌已持久化存储" echo "令牌已持久化存储KEY=VALUE 格式)"
else else
echo "错误: 令牌写入失败" echo "错误: 令牌写入失败"
exit 1 exit 1
@@ -58,12 +66,12 @@ fi
``` ```
```powershell ```powershell
# Windows 版 # Windows 版KEY=VALUE 格式)
New-Item -ItemType Directory -Force "$env:USERPROFILE\.codex\skills\PineSoundSkills" New-Item -ItemType Directory -Force "$env:USERPROFILE\.codex\skills\PineSoundSkills"
$env:GITEA_TOKEN | Out-File -FilePath "$env:USERPROFILE\.codex\skills\PineSoundSkills\.env" -NoNewline -Encoding ASCII "GITEA_TOKEN=$env:GITEA_TOKEN" | Out-File -FilePath "$env:USERPROFILE\.codex\skills\PineSoundSkills\.env" -Encoding ASCII
# 验证 # 验证
if ((Get-Item "$env:USERPROFILE\.codex\skills\PineSoundSkills\.env").Length -gt 0) { if (Select-String -Path "$env:USERPROFILE\.codex\skills\PineSoundSkills\.env" -Pattern "^GITEA_TOKEN=" -Quiet) {
Write-Host "令牌已持久化存储" Write-Host "令牌已持久化存储KEY=VALUE 格式)"
} else { } else {
Write-Host "错误: 令牌写入失败" Write-Host "错误: 令牌写入失败"
exit 1 exit 1
@@ -73,20 +81,24 @@ if ((Get-Item "$env:USERPROFILE\.codex\skills\PineSoundSkills\.env").Length -gt
### 1.2 读取令牌(后续使用) ### 1.2 读取令牌(后续使用)
```bash ```bash
# Unix — 去除首尾空白,避免换行符污染 API 请求 # Unix — 确保目录存在后再读取令牌(按 KEY 提取)
GITEA_TOKEN=$(cat ~/.codex/skills/PineSoundSkills/.env 2>/dev/null | tr -d '\n\r' | xargs) mkdir -p ~/.codex/skills/PineSoundSkills
# 从 .env 中按 KEY 提取 GITEA_TOKENKEY=VALUE 格式)
GITEA_TOKEN=$(grep "^GITEA_TOKEN=" ~/.codex/skills/PineSoundSkills/.env 2>/dev/null | head -1 | cut -d= -f2- | tr -d '\n\r' | xargs)
if [ -z "$GITEA_TOKEN" ]; then if [ -z "$GITEA_TOKEN" ]; then
echo "错误: 令牌文件缺失或为空,请先设置令牌" echo "错误: .env 中缺少 GITEA_TOKEN,请先设置令牌"
exit 1 exit 1
fi fi
``` ```
```powershell ```powershell
# Windows # Windows — 确保目录存在后再读取令牌(按 KEY 提取)
$GITEA_TOKEN = (Get-Content "$env:USERPROFILE\.codex\skills\PineSoundSkills\.env" -Raw).Trim() $null = New-Item -ItemType Directory -Force "$env:USERPROFILE\.codex\skills\PineSoundSkills" 2>$null
$GITEA_TOKEN = (Select-String -Path "$env:USERPROFILE\.codex\skills\PineSoundSkills\.env" -Pattern "^GITEA_TOKEN=" | ForEach-Object { $_.Line.Split("=", 2)[1].Trim() })
if ([string]::IsNullOrEmpty($GITEA_TOKEN)) { if ([string]::IsNullOrEmpty($GITEA_TOKEN)) {
Write-Host "错误: 令牌文件缺失或为空,请先设置令牌" Write-Host "错误: .env 中缺少 GITEA_TOKEN,请先设置令牌"
exit 1 exit 1
} }
``` ```
@@ -95,7 +107,7 @@ if ([string]::IsNullOrEmpty($GITEA_TOKEN)) {
| 场景 | 行为 | | 场景 | 行为 |
|------|------| |------|------|
| 首次运行 | agent `AskUserQuestion` 索要 → 写入 `.env` | | 首次运行 | agent 索要 → escalatefs 写入)→ 写入 `.env` |
| 再次运行 | 直接从 `.env` 读取,跳过询问 | | 再次运行 | 直接从 `.env` 读取,跳过询问 |
| 令牌失效(API 返回 401) | 提示用户令牌可能已过期,重新执行 1.1 流程 | | 令牌失效(API 返回 401) | 提示用户令牌可能已过期,重新执行 1.1 流程 |
| 用户明确要求重新设置 | 覆盖 `.env`,执行 1.1 流程 | | 用户明确要求重新设置 | 覆盖 `.env`,执行 1.1 流程 |
@@ -121,22 +133,27 @@ echo "$PLATFORM"
## 三、查看 Gitea 仓库中的 Skills 列表 ## 三、查看 Gitea 仓库中的 Skills 列表
> **需 escalate**: 以下步骤需要同时 escalate 文件系统写入(mkdir/读取 .env)和网络访问(curl 请求内网 Gitea)。
```bash ```bash
TOKEN_FILE=~/.codex/skills/PineSoundSkills/.env TOKEN_FILE=~/.codex/skills/PineSoundSkills/.env
# 读取并清理令牌 # 确保目录存在
if [ ! -f "$TOKEN_FILE" ] || [ ! -s "$TOKEN_FILE" ]; then mkdir -p "$(dirname "$TOKEN_FILE")"
echo "错误: 令牌文件缺失或为空。请先执行令牌获取流程(见第一章)"
# 按 KEY 读取 GITEA_TOKEN
if [ ! -f "$TOKEN_FILE" ] || ! grep -q "^GITEA_TOKEN=" "$TOKEN_FILE" 2>/dev/null; then
echo "错误: .env 中缺少 GITEA_TOKEN。请先执行令牌获取流程(见第一章)"
exit 1 exit 1
fi fi
GITEA_TOKEN=$(cat "$TOKEN_FILE" 2>/dev/null | tr -d '\n\r' | xargs) GITEA_TOKEN=$(grep "^GITEA_TOKEN=" "$TOKEN_FILE" 2>/dev/null | head -1 | cut -d= -f2- | tr -d '\n\r' | xargs)
if [ -z "$GITEA_TOKEN" ]; then if [ -z "$GITEA_TOKEN" ]; then
echo "错误: 令牌为空" echo "错误: 令牌为空"
exit 1 exit 1
fi fi
# 请求 API # 请求 API(内网 Gitea,需 escalate 网络权限)
curl -s -H "Authorization: token $GITEA_TOKEN" \ curl -s -H "Authorization: token $GITEA_TOKEN" \
"http://192.168.1.3:10082/api/v1/orgs/PineSoundSkills/repos" \ "http://192.168.1.3:10082/api/v1/orgs/PineSoundSkills/repos" \
| python3 -c " | python3 -c "
@@ -153,10 +170,62 @@ for r in repos:
> 注意:`cat` 读取的令牌可能包含尾部换行符,通过 `tr -d '\n\r'` 和 `xargs` 做双重清理。如果 API 返回 401,说明令牌无效或已过期。 > 注意:`cat` 读取的令牌可能包含尾部换行符,通过 `tr -d '\n\r'` 和 `xargs` 做双重清理。如果 API 返回 401,说明令牌无效或已过期。
### 3.1 网络不可用时的 fallback(仅列出 PineSound 内部技能)
如果 `curl` 返回 `exit code 7`(连接失败)、`exit code 6`(DNS 解析失败)或 HTTP 状态码非 200,按以下方式处理:
1. 先检查 `~/.codex/skills/PineSoundSkills/` 下是否有已安装的 PineSound 技能
2. 向用户报告 Gitea 连不通,仅列出本地已安装的 PineSound 内部技能
3. 询问用户是否要重试连接或手动操作
**注意**:不要在输出中混入其他来源的技能(如系统 skills、社区 skills 等),只显示 PineSound 内部的。
```bash
# 当 Gitea API 不可达时的 fallback:列出本地已安装的 PineSound 内部技能
echo "Gitea 服务 (192.168.1.3:10082) 当前不可达。"
echo ""
echo "=== 已安装的 PineSound 内部 Skills ==="
SKILL_DIR=~/.codex/skills/PineSoundSkills
if [ -d "$SKILL_DIR" ]; then
for d in "$SKILL_DIR"/*/; do
[ -d "$d" ] || continue
name=$(basename "$d")
[ -f "${d}SKILL.md" ] && desc=$(grep '^description:' "${d}SKILL.md" | head -1 | sed 's/^description:\s*//i' | sed 's/"//g') || desc=""
echo " $name${desc:+ — $desc}"
done
else
echo "(暂未安装任何 PineSound 内部技能)"
fi
```
```powershell
# Windows fallback — 仅列出 PineSound 内部技能
Write-Host "Gitea 服务 (192.168.1.3:10082) 当前不可达。"
Write-Host ""
Write-Host "=== 已安装的 PineSound 内部 Skills ==="
$skillDir = "$env:USERPROFILE\.codex\skills\PineSoundSkills"
if (Test-Path $skillDir) {
foreach ($d in Get-ChildItem -Directory $skillDir) {
$name = $d.Name
$sf = "$($d.FullName)\SKILL.md"
$desc = ""
if (Test-Path $sf) {
$match = Select-String -Path $sf -Pattern '(?im)^description:\s*(.+)'
if ($match) { $desc = $match.Matches.Value -replace '(?im)^description:\s*', '' }
}
Write-Host " $name$(if ($desc) { " -- $desc" })"
}
} else {
Write-Host "(暂未安装任何 PineSound 内部技能)"
}
```
--- ---
## 四、安装 Skills ## 四、安装 Skills
> **需 escalate**: 以下涉及文件系统写入和 git 克隆(网络访问)。
### 4.1 确保目录存在 ### 4.1 确保目录存在
```bash ```bash
@@ -527,28 +596,32 @@ GITEA_API="http://192.168.1.3:10082/api/v1"
# ========== 令牌管理 ========== # ========== 令牌管理 ==========
# 检查令牌文件是否存在且非空 # 确保目录存在
if [ ! -f "$TOKEN_FILE" ] || [ ! -s "$TOKEN_FILE" ]; then mkdir -p "$(dirname "$TOKEN_FILE")"
echo "令牌文件不存在或为空。"
# 检查 .env 是否存在且包含 GITEA_TOKENKEY=VALUE 格式)
if [ ! -f "$TOKEN_FILE" ] || ! grep -q "^GITEA_TOKEN=" "$TOKEN_FILE" 2>/dev/null; then
echo "令牌文件不存在或未设置 GITEA_TOKEN。"
echo "请通过 AskUserQuestion 向用户索要 Gitea 令牌。" echo "请通过 AskUserQuestion 向用户索要 Gitea 令牌。"
# [agent 操作] 用 AskUserQuestion 获取用户输入的令牌 # [agent 操作] 用 AskUserQuestion 获取用户输入的令牌
# 假设用户提供了令牌,存入变量 USER_TOKEN # 假设用户提供了令牌,存入变量 USER_TOKEN
mkdir -p "$SKILL_DIR" mkdir -p "$SKILL_DIR"
printf '%s' "$USER_TOKEN" > "$TOKEN_FILE" printf "GITEA_TOKEN=%s\n" "$USER_TOKEN" > "$TOKEN_FILE"
chmod 600 "$TOKEN_FILE" chmod 600 "$TOKEN_FILE"
# 写入后验证 # 写入后验证
if [ ! -s "$TOKEN_FILE" ]; then if grep -q "^GITEA_TOKEN=" "$TOKEN_FILE" 2>/dev/null; then
echo "令牌已持久化存储到 $TOKEN_FILEKEY=VALUE 格式)"
else
echo "错误: 令牌写入失败!" echo "错误: 令牌写入失败!"
exit 1 exit 1
fi fi
echo "令牌已持久化存储到 $TOKEN_FILE"
fi fi
# 读取令牌(清理空白字符) # 按 KEY 读取令牌(清理空白字符)
GITEA_TOKEN=$(cat "$TOKEN_FILE" 2>/dev/null | tr -d '\n\r' | xargs) GITEA_TOKEN=$(grep "^GITEA_TOKEN=" "$TOKEN_FILE" 2>/dev/null | head -1 | cut -d= -f2- | tr -d '\n\r' | xargs)
if [ -z "$GITEA_TOKEN" ]; then if [ -z "$GITEA_TOKEN" ]; then
echo "错误: 令牌为空" echo "错误: 令牌为空"
exit 1 exit 1
@@ -563,6 +636,21 @@ HTTP_CODE=$(curl -s -o /tmp/pinesound_repos.json -w "%{http_code}" \
if [ "$HTTP_CODE" != "200" ]; then if [ "$HTTP_CODE" != "200" ]; then
echo "API 请求失败 (HTTP $HTTP_CODE),令牌可能无效或已过期" echo "API 请求失败 (HTTP $HTTP_CODE),令牌可能无效或已过期"
echo "请重新执行令牌获取流程" echo "请重新执行令牌获取流程"
# fallback:列出本地已安装的 PineSound 内部技能
echo ""
echo "=== 已安装的 PineSound 内部 Skills ==="
SKILL_DIR=~/.codex/skills/PineSoundSkills
if [ -d "$SKILL_DIR" ]; then
for d in "$SKILL_DIR"/*/; do
[ -d "$d" ] || continue
name=$(basename "$d")
[ -f "${d}SKILL.md" ] && desc=$(grep '^description:' "${d}SKILL.md" | head -1 | sed 's/^description:\s*//i' | sed 's/"//g') || desc=""
echo " $name${desc:+ — $desc}"
done
else
echo "(暂未安装任何 PineSound 内部技能)"
fi
exit 1 exit 1
fi fi