关于 script-builder
script-builder 是一项将测试或验证需求转化为可重复运行脚本的技能,面向需要持久化项目检查流程的开发者。它还会为脚本生成文档入口,并按自主模式安排确认与执行步骤。
主要功能
- 01生成可重复运行的验证脚本
- 02检测现有脚本并处理重复需求
- 03按项目语言选择脚本模板
- 04执行语法检查并迭代修复
- 05在 CLAUDE.md 或 AGENTS.md 中记录脚本
适用场景
- 01将临时 API 检查保存为脚本
- 02为部署前验证建立可复用流程
- 03把重复测试探查整理成项目脚本
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ desplega-ai/ ai-toolbox --skill script-builder安装后在 Claude Code 中输入/script-builder确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
templates/bash.sh.tmplpython.py.tmplREADME.mdtypescript.ts.tmpl详细介绍
script-builder
将测试/验证意图转化为持久、可重复运行的脚本,并提交到目标项目的 scripts/ 目录。输出采用上下文最优形式:成功时仅输出一行 PASS/FAIL 和 /tmp 日志路径;完整的详细输出重定向到带时间戳的日志文件;并在 CLAUDE.md/AGENTS.md 中添加 <important if> 块,以便未来的 Agent 在再次遇到相关测试意图时发现该脚本。
工作约定
这些说明确立了你与用户之间的工作约定。核心原则如下:
-
AskUserQuestion 是主要沟通工具——每当你需要询问用户任何事项(澄清、偏好、决策、确认)时,都使用 AskUserQuestion 工具。不要以纯文本提问——始终使用结构化工具,以便用户高效作答。
-
提前了解偏好——在工作流开始时询问用户偏好,而不是等到最后才问,以免用户已经想结束。
-
自主模式决定互动频率——用户选择的自主级别决定你需要多久确认一次,但所有问题仍须通过 AskUserQuestion 提出。
适用场景
出现以下情况时,此技能会启用:
- 用户调用
/script-builder命令 - 其他技能引用
**OPTIONAL SUB-SKILL:** desplega:script-builder planning、qa或verifying流程需要一个尚不存在的、可重复运行的验证脚本- 用户表达了“将 X 转成脚本”“把这个验证封装成可复用的工具”或“我想端到端测试 X”的意图,但现有脚本无法满足需求
自主模式
根据自主模式调整行为:
| 模式 | 行为 |
|---|---|
| Autopilot | 检测模式、起草、进行语法检查、编写文档,并在升级层级时运行和迭代,无需中途确认。仅在遇到硬性阻碍或破坏性副作用时暂停。 |
| Critical(默认) | 在每个层级边界确认(起草后、编辑文档前、运行前)。在迭代循环中,使用 AskUserQuestion 询问是否应用修复。 |
| Verbose | 每一步都先确认。展示每处差异。逐步说明检测推理。 |
自主模式由调用命令传入。如果未指定,默认为 Critical。
流程步骤
Step 1:检测模式(回顾式或预先声明式)
自行决定——不要询问用户“选择哪种模式?”。使用以下启发式规则:
- 扫描近期会话中的工具使用历史(当前对话中最近约 20 次工具调用),查找测试/验证相关活动:
curl/fetch调用、bun run/python/pytest、数据库查询、qa-use浏览器操作,或针对单个端点或表反复执行的grep/日志检查。如果有 ≥2 次此类操作针对同一区域 → 回顾式模式。 - 解析用户的调用消息,查找以下线索:
- 叙述性线索 → 回顾式:“我们刚刚查明了”、“把这个转成脚本”、“把那个封装起来”、“我们刚才做的那个”。
- 意图线索 → 预先声明式:“我想测试”、“验证一下”、“冒烟检查”、“部署前检查”。
- 兜底规则:如果无法确定,默认使用预先声明式。
回顾式模式的第一步:用纯文本向用户概述观察到的活动(不超过 6 行:探查了什么、针对什么、成功信号是什么),然后进入 Step 3,并改为请求确认,而不是进行问答。
预先声明式模式的第一步:直接跳到 Step 3 的问答环节。
步骤 2:扫描现有脚本,查找重叠
按以下顺序解析 scripts 目录:
- 检查
CLAUDE.md中是否有 `` 标记。如果有,使用其中的路径。 - 如果仓库根目录下存在
scripts/,则使用它。 - 使用 AskUserQuestion,选项为:
scripts/(推荐)| 自定义路径 | 本次运行跳过目录持久化。
边缘情况 — 目录不存在:如果解析出的路径不存在,则跳过查重扫描,打印一行说明(No existing scripts directory at <path> — proceeding to intent gathering),并记住可在步骤 5 之前选择提供创建该目录的选项。
目录存在时:
- 列出 scripts 目录中的文件(v1 仅列出顶层文件)。
- 对每个文件,读取文件开头(头部注释)并提取文件名中的词元。
- 读取
CLAUDE.md/AGENTS.md,查找指向此目录中脚本的<important if="...">块,并提取触发短语。 - 将当前意图字符串与(文件名词元 ∪ 头部关键词 ∪ 触发短语)进行模糊匹配。“合理匹配”指共享关键词且属于同一领域名词(例如,
auth、health、webhook)。 - 如果存在 ≥1 个合理匹配,则使用 AskUserQuestion,选项为:
按原样复用 <name> | 扩展 <name> | 仍然生成新脚本。
对于边界匹配,绝不要默默跳过查重——应展示匹配结果并让用户决定。扩展分支会在现有脚本中追加子命令/标志(不要创建新文件);并在脚本的头部注释和现有 <important if> 块中说明新标志。
步骤 3:收集意图
两种模式都会汇总到相同的内部意图结构:{ what, success_signal, failure_signal, inputs, env, side_effects }。
前向模式 — 使用 AskUserQuestion(提一到两个问题,而不是五个):
| 问题 | 选项 |
|---|---|
| “我们要验证什么,成功信号是什么?” | [自由文本 — 在一个回答中收集 what + success signal] |
| “是否有需要标记的必需环境变量、输入或副作用(例如,写入生产环境、产生费用)?” | [自由文本 — 可选;如果前向意图已说明这些内容,则跳过] |
回顾模式 — 展示步骤 1 中的摘要,并使用 AskUserQuestion,选项为:流程没问题 | 接近了,但要修正 X | 重新开始。选择 接近了,但要修正 X 时,直接询问具体修正内容;选择 重新开始 时,转入前向模式问答。
将已确定的意图保存在工作记忆中(暂不写入磁盘)。
步骤 4:检测语言
优先顺序 — 命中第一个条件即采用,同时可通过覆盖路径调整:
- TypeScript — 存在
package.json+tsconfig.json。- 如果存在
bun.lock或bunfig.toml,则使用 Bun。 - 否则,如果
package.json的 devDependencies 中出现tsx,则使用 tsx。 - 否则,使用 已编译的 Node(在脚本头部注明:需要运行
tsc构建)。
- 如果存在
- Python — 存在
pyproject.toml或uv.lock或requirements.txt。- 如果存在
uv.lock,或pyproject.toml中配置了[tool.uv],则使用 uv(设置{{UV_METADATA}})。 - 否则,使用 原生 python3(将
{{UV_METADATA}}替换为空字符串)。
- 如果存在
- 同时检测到 TS 和 Python — 统计
src//顶层目录中的源文件数量,并使用 AskUserQuestion 询问优先选择哪种语言,文件较多的一方标记为“推荐”。 - 仅有
Cargo.toml/go.mod→ 回退到 bash(注意:v1 仅支持 TS/Python/Bash)。 - 未匹配到任何内容 → bash。
任务驱动的覆盖:如果收集到的意图明显适合 shell(“验证三个 docker 容器是否有响应”、“监视此日志文件并查找错误”),即使项目使用 TS/Python,也建议采用 bash。
使用 AskUserQuestion 确认,检测到的语言作为第一个选项(推荐)。Autopilot 中跳过。
步骤 5:起草脚本
- 选择模板:
cc-plugin/base/skills/script-builder/templates/{typescript.ts.tmpl|python.py.tmpl|bash.sh.tmpl}。 - 根据收集到的意图解析替换标记:
{{SCRIPT_NAME}}← 建议的文件名主体(参见命名表)。{{WHAT}}/{{WHEN}}/{{ENV}}/{{EXAMPLE}}← 意图字段。{{UV_METADATA}}← 按照步骤 4 处理。
- 根据意图生成
{{TEST_BODY}}。保持精简:只包含一个具体探测和断言,不要编写一组测试。重新阅读模板的 README(templates/README.md),了解约定——主体必须遵循 PASS/FAIL 的表现形式。失败时抛出异常、使用raise或执行exit 1;由模板外层的 try/trap 转换为 FAIL 行。 - 提出一个符合意图类型的文件名——参见下方的前缀表。先用 AskUserQuestion 提出建议的名称(Recommended),并将
custom name作为备选项。
命名约定(仅供参考——技能会提出建议,用户可以覆盖):
| 前缀 | 适用情况 | 示例 |
|---|---|---|
e2e-* | 跨多个组件的端到端流程 | e2e-auth-flow.ts |
check-* | 幂等的单一探测验证 | check-db-boundary.sh |
smoke-* | 部署后的最小可行检查 | smoke-prod-api.ts |
measure-* | 性能 / 大小 / token 测量 | measure-tool-tokens.ts |
seed-* / generate-* | 数据填充或生成产物(用于验证的情况较少) | seed-api-keys.sh |
如果意图与任何前缀都不完全匹配,请提出一个自由格式的名称,例如 validate-<area>.<ext>。
- 将文件写入解析后的脚本目录。使其具有可执行权限(
chmod +x)。
步骤 6:语法 / 类型检查
运行相应的检查器:
| 语言 | 检查器(按优先顺序) |
|---|---|
| TypeScript | 如果存在 Bun,使用 bunx tsc --noEmit <file>;否则使用 npx tsc --noEmit <file> |
| Python | 始终运行 python3 -m py_compile <file>;如果 ruff 位于 PATH 中,再运行 ruff check <file> |
| Bash | 如果可用,运行 shellcheck <file>;否则运行 bash -n <file> |
成功时:记录一行(syntax check OK),然后继续步骤 7。
失败时:
- 打印错误(不超过 10 行,不要打印完整输出)。
- 提出一个具体的单处修改修复方案(即将应用的确切
Edit)。 - 使用 AskUserQuestion 提供
Apply fix | Investigate | Stop选项。- Apply fix → 编辑脚本并重新运行检查器(循环执行,不设硬性次数上限)。
- Investigate → 与用户讨论;不要自动应用任何修改。
- Stop → 将脚本保留在原路径;打印路径;不要删除。
步骤 7:记录脚本
自动编辑目标项目的 CLAUDE.md 和/或 AGENTS.md,以便未来的 Agent 在再次遇到匹配意图时发现此脚本。
区块模板(技能输出的 Markdown 原文):
<important if="[TRIGGER: e.g., you are testing the auth flow]">
## [Area] validation
Run `scripts/<name>` to [one-liner]. Requires [env/deps]. Example: `<cmd>`. Full log at `/tmp/<name>-*.log`.
Generated/maintained via `/script-builder`.
</important>
行为:
- 目标文件选择:如果
CLAUDE.md和AGENTS.md都存在,则编辑两者;只编辑实际存在的文件。绝不从头创建任一文件——如果两者都不存在,则打印一行说明(No CLAUDE.md or AGENTS.md found — script generated but not documented)并跳过此步骤。 - 放置启发式规则:在文件中搜索第一个匹配
Test|Testing|Validation|Scripts的标题(不区分大小写)。如果找到,则在该章节内或其后追加新区块。否则,在文件末尾附近新增## Scripts for testing & validation章节,但要放在任何匹配License|Acknowledg|Maintain|Contributors的标题之前。 - 幂等性:如果已存在引用
scripts/<name>的区块(即之前针对同一脚本名称运行过/script-builder),则在原位置更新该区块——替换整个<important if=...>...</important>区块,不要追加重复内容。 - scripts 目录标记:如果步骤 2 是由用户选择(而非现有标记)确定 scripts 目录,则在
CLAUDE.md顶部附近(标题之后)插入 ``,以便后续运行不再显示提示。如果标记已存在,则跳过。 - 显示差异:运行相当于
git diff CLAUDE.md AGENTS.md的命令,并打印 5 行摘要,说明更改内容。绝不自动暂存——由用户提交。
步骤 8:提供升级选项
编辑文档后,决定是否继续进入运行并迭代阶段。
| 自主级别 | 行为 |
|---|---|
| 自动驾驶 | 自动升级至步骤 9,除非意图标记了副作用(写入生产环境、发送真实资金、修改共享资源)。如果标记了副作用,则按关键模式处理。 |
| 关键(默认) | 使用 AskUserQuestion:`现在运行以确认其正常工作 |
| 详细 | 与关键模式相同,此外在执行前提供拟运行命令供用户审核。 |
如果用户选择“我稍后自行运行”或“只生成,不运行”→ 直接跳至步骤 10。
步骤 9:迭代修复失败(仅限升级阶段)
由人工设定边界的循环。除自动驾驶模式外,绝不自动应用修复。
- 使用拟定的示例调用运行脚本(不带
--verbose,不带--json)。捕获退出代码,并获取/tmp日志末尾的 40 行(tail -n 40)。 - 如果退出代码为 0 → 报告 PASS(回显脚本的 PASS 行),然后继续步骤 10。
- 如果退出代码非 0:
- 用 1–3 行总结失败情况:错误类别(超时 / 4xx / 5xx / 断言 / 缺少依赖等)+ 可能原因(在日志中搜索已知特征:
ECONNREFUSED、Traceback、non-zero exit、command not found等)。 - 提出具体差异——说明你会对脚本应用的确切
Edit。展示旧内容 → 新内容。 - 使用 AskUserQuestion:
应用修复 | 换一种方式调查 | 停止。- 应用修复 → 编辑脚本,记录更改,然后返回 (1)。
- 换一种方式调查 → 转入讨论;不要自动应用更改。
- 停止 → 保留脚本,打印其路径;不要还原。
- 用 1–3 行总结失败情况:错误类别(超时 / 4xx / 5xx / 断言 / 缺少依赖等)+ 可能原因(在日志中搜索已知特征:
不设硬编码重试上限——由人工隐式设定上限。
副作用标记:如果意图声明了副作用(步骤 3),且当前为自动驾驶模式,则在首次运行前显示一行 WARNING: this script <does X> against <target>,并要求通过 AskUserQuestion 明确确认,即使处于自动驾驶模式也不例外。
步骤 10:交接
技能如何退出取决于调用方式:
作为子技能调用(来自 planning、qa、verifying):
向父技能返回控制权,并提供结构化摘要:{ script_path, status: "pass"|"fail"|"unrun", log_path?, doc_files_edited: [...] }。
直接调用(/script-builder):
使用 AskUserQuestion:Run it with /qa | Run /verify-plan | Commit the script and doc changes | Done。
- Run with /qa → 调用
desplega:qa,并将脚本路径作为来源。 - Run /verify-plan → 如果当前上下文中有计划路径,则调用
desplega:verifying。 - Commit → 提议提交消息(
feat(scripts): add scripts/<name> for <area> validation),并且仅暂存生成的脚本和对 CLAUDE.md/AGENTS.md 的编辑。不要自动提交;显示提议的git add和git commit命令,并要求用户确认。 - Done → 打印脚本路径 + 日志路径(如果运行了升级流程),然后退出。
中止路径(在之前任一关卡选择 Stop):保留生成的脚本;如果步骤 7 已运行,则保留对 CLAUDE.md/AGENTS.md 的任何编辑;并打印一行:Aborted. Script: <path>. Doc edits: <files or "none">. Re-run /script-builder or git checkout to discard. 不要代替用户运行 git restore。
学习记录
可选子技能: 如果此工作流中出现了重要见解、模式、注意事项或决策,可考虑使用 desplega:learning 通过 /learning capture 记录下来。重点记录有助于他人在未来会话中受益的经验。