mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-13 02:41:50 +08:00
feat: 为 skill-generator 添加脚本执行能力
- 默认创建 scripts/ 目录用于存放确定性脚本 - 新增 specs/scripting-integration.md 脚本集成规范 - 新增 templates/script-python.md 和 script-bash.md 脚本模板 - 模板中添加 ## Scripts 声明和 ExecuteScript 调用示例 - 支持命名即ID、扩展名即运行时的约定 - 参数自动转换: snake_case → kebab-case - Bash 模板使用 jq 构建 JSON 输出 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
277
.claude/skills/skill-generator/templates/script-bash.md
Normal file
277
.claude/skills/skill-generator/templates/script-bash.md
Normal file
@@ -0,0 +1,277 @@
|
||||
# Bash Script Template
|
||||
|
||||
Bash 脚本模板,用于生成技能中的确定性脚本。
|
||||
|
||||
## 模板代码
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# {{script_description}}
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ============================================================
|
||||
# 参数解析
|
||||
# ============================================================
|
||||
|
||||
INPUT_PATH=""
|
||||
OUTPUT_DIR="" # 由调用方指定,不设默认值
|
||||
|
||||
show_help() {
|
||||
echo "用法: $0 --input-path <path> --output-dir <dir>"
|
||||
echo ""
|
||||
echo "参数:"
|
||||
echo " --input-path 输入文件路径 (必需)"
|
||||
echo " --output-dir 输出目录 (必需,由调用方指定)"
|
||||
echo " --help 显示帮助信息"
|
||||
}
|
||||
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case $1 in
|
||||
--input-path)
|
||||
INPUT_PATH="$2"
|
||||
shift
|
||||
;;
|
||||
--output-dir)
|
||||
OUTPUT_DIR="$2"
|
||||
shift
|
||||
;;
|
||||
--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "错误: 未知参数 $1" >&2
|
||||
show_help >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# ============================================================
|
||||
# 参数验证
|
||||
# ============================================================
|
||||
|
||||
if [[ -z "$INPUT_PATH" ]]; then
|
||||
echo "错误: --input-path 是必需参数" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$OUTPUT_DIR" ]]; then
|
||||
echo "错误: --output-dir 是必需参数" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$INPUT_PATH" ]]; then
|
||||
echo "错误: 输入文件不存在: $INPUT_PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查 jq 是否可用(用于 JSON 输出)
|
||||
if ! command -v jq &> /dev/null; then
|
||||
echo "错误: 需要安装 jq" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
|
||||
# ============================================================
|
||||
# 核心逻辑
|
||||
# ============================================================
|
||||
|
||||
OUTPUT_FILE="$OUTPUT_DIR/result.txt"
|
||||
ITEMS_COUNT=0
|
||||
|
||||
# TODO: 实现处理逻辑
|
||||
# 示例:处理输入文件
|
||||
while IFS= read -r line; do
|
||||
echo "$line" >> "$OUTPUT_FILE"
|
||||
((ITEMS_COUNT++))
|
||||
done < "$INPUT_PATH"
|
||||
|
||||
# ============================================================
|
||||
# 输出 JSON 结果(使用 jq 构建,避免特殊字符问题)
|
||||
# ============================================================
|
||||
|
||||
jq -n \
|
||||
--arg output_file "$OUTPUT_FILE" \
|
||||
--argjson items_processed "$ITEMS_COUNT" \
|
||||
'{output_file: $output_file, items_processed: $items_processed, status: "success"}'
|
||||
```
|
||||
|
||||
## 变量说明
|
||||
|
||||
| 变量 | 说明 |
|
||||
|------|------|
|
||||
| `{{script_description}}` | 脚本功能描述 |
|
||||
|
||||
## 使用规范
|
||||
|
||||
### 脚本头部
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -euo pipefail # 严格模式:出错退出、未定义变量报错、管道错误传递
|
||||
```
|
||||
|
||||
### 参数解析模式
|
||||
|
||||
```bash
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case $1 in
|
||||
--param-name)
|
||||
PARAM_VAR="$2"
|
||||
shift
|
||||
;;
|
||||
--flag)
|
||||
FLAG_VAR=true
|
||||
;;
|
||||
*)
|
||||
echo "Unknown: $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
```
|
||||
|
||||
### 输出格式
|
||||
|
||||
- 最后一行打印单行 JSON
|
||||
- **强烈推荐使用 `jq`**:自动处理转义和类型
|
||||
|
||||
```bash
|
||||
# 推荐:使用 jq 构建(安全、可靠)
|
||||
jq -n \
|
||||
--arg file "$FILE" \
|
||||
--argjson count "$COUNT" \
|
||||
'{output_file: $file, items_processed: $count}'
|
||||
|
||||
# 备选:简单场景手动拼接(注意特殊字符转义)
|
||||
echo "{\"file\": \"$FILE\", \"count\": $COUNT}"
|
||||
```
|
||||
|
||||
**jq 参数类型**:
|
||||
- `--arg name value`:字符串类型
|
||||
- `--argjson name value`:数字/布尔/null 类型
|
||||
|
||||
### 错误处理
|
||||
|
||||
```bash
|
||||
# 验证错误
|
||||
if [[ -z "$PARAM" ]]; then
|
||||
echo "错误: 参数不能为空" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 命令错误
|
||||
if ! command -v jq &> /dev/null; then
|
||||
echo "错误: 需要安装 jq" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 运行时错误
|
||||
if ! some_command; then
|
||||
echo "错误: 命令执行失败" >&2
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
## 常用模式
|
||||
|
||||
### 文件遍历
|
||||
|
||||
```bash
|
||||
for file in "$INPUT_DIR"/*.json; do
|
||||
[[ -f "$file" ]] || continue
|
||||
echo "处理: $file"
|
||||
# 处理逻辑...
|
||||
done
|
||||
```
|
||||
|
||||
### 临时文件
|
||||
|
||||
```bash
|
||||
TEMP_FILE=$(mktemp)
|
||||
trap "rm -f $TEMP_FILE" EXIT
|
||||
|
||||
echo "data" > "$TEMP_FILE"
|
||||
```
|
||||
|
||||
### 调用其他工具
|
||||
|
||||
```bash
|
||||
# 检查工具存在
|
||||
require_command() {
|
||||
if ! command -v "$1" &> /dev/null; then
|
||||
echo "错误: 需要 $1" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
require_command jq
|
||||
require_command curl
|
||||
```
|
||||
|
||||
### JSON 处理(使用 jq)
|
||||
|
||||
```bash
|
||||
# 读取 JSON 字段
|
||||
VALUE=$(jq -r '.field' "$INPUT_PATH")
|
||||
|
||||
# 修改 JSON
|
||||
jq '.field = "new_value"' "$INPUT_PATH" > "$OUTPUT_FILE"
|
||||
|
||||
# 合并 JSON 文件
|
||||
jq -s 'add' file1.json file2.json > merged.json
|
||||
```
|
||||
|
||||
## 生成函数
|
||||
|
||||
```javascript
|
||||
function generateBashScript(scriptConfig) {
|
||||
return `#!/bin/bash
|
||||
# ${scriptConfig.description}
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# 参数定义
|
||||
${scriptConfig.inputs.map(i =>
|
||||
`${i.name.toUpperCase().replace(/-/g, '_')}="${i.default || ''}"`
|
||||
).join('\n')}
|
||||
|
||||
# 参数解析
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case $1 in
|
||||
${scriptConfig.inputs.map(i =>
|
||||
` --${i.name})
|
||||
${i.name.toUpperCase().replace(/-/g, '_')}="$2"
|
||||
shift
|
||||
;;`
|
||||
).join('\n')}
|
||||
*)
|
||||
echo "未知参数: $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# 参数验证
|
||||
${scriptConfig.inputs.filter(i => i.required).map(i =>
|
||||
`if [[ -z "$${i.name.toUpperCase().replace(/-/g, '_')}" ]]; then
|
||||
echo "错误: --${i.name} 是必需参数" >&2
|
||||
exit 1
|
||||
fi`
|
||||
).join('\n\n')}
|
||||
|
||||
# TODO: 实现处理逻辑
|
||||
|
||||
# 输出结果
|
||||
echo "{${scriptConfig.outputs.map(o =>
|
||||
`\\"${o.name}\\": \\"\\$${o.name.toUpperCase().replace(/-/g, '_')}\\"`
|
||||
).join(', ')}}"
|
||||
`;
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user