> ## Documentation Index
> Fetch the complete documentation index at: https://agent-skills.zhcndoc.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 在技能中使用脚本

> 如何在技能中运行命令和捆绑可执行脚本。

技能可以指示代理运行 shell 命令并在 `scripts/` 目录中捆绑可重用的脚本。本指南涵盖一次性命令、带有各自依赖项的独立脚本，以及如何设计用于代理使用的脚本接口。

## 一次性命令

当现有的包已经满足您的需求时，您可以在 `SKILL.md` 指令中直接引用它，而无需 `scripts/` 目录。许多生态系统提供在运行时自动解析依赖项的工具。

<Tabs sync={false}>
  <Tab title="uvx">
    [uvx](https://docs.astral.sh/uv/guides/tools/) 在隔离环境中运行 Python 包，具有积极的缓存功能。它随 [uv](https://docs.astral.sh/uv/) 一起提供。

    ```bash theme={null}
    uvx ruff@0.8.0 check .
    uvx black@24.10.0 .
    ```

    * 不随 Python 捆绑 — 需要单独安装。
    * 快速。积极缓存，因此重复运行几乎是瞬间的。
  </Tab>

  <Tab title="pipx">
    [pipx](https://pipx.pypa.io/) 在隔离环境中运行 Python 包。可通过操作系统包管理器获得（`apt install pipx`, `brew install pipx`）。

    ```bash theme={null}
    pipx run 'black==24.10.0' .
    pipx run 'ruff==0.8.0' check .
    ```

    * 不随 Python 捆绑 — 需要单独安装。
    * `uvx` 的成熟替代方案。虽然 `uvx` 已成为标准推荐，但 `pipx` 仍然是一个可靠的选项，具有更广泛的操作系统包管理器可用性。
  </Tab>

  <Tab title="npx">
    [npx](https://docs.npmjs.com/cli/commands/npx) 运行 npm 包，按需下载。它随 npm 一起提供（npm 随 Node.js 一起提供）。

    ```bash theme={null}
    npx eslint@9 --fix .
    npx create-vite@6 my-app
    ```

    * 随 Node.js 捆绑 — 无需额外安装。
    * 下载包，运行它，并缓存以供将来使用。
    * 使用 `npx package@version` 固定版本以实现可复现性。
  </Tab>

  <Tab title="bunx">
    [bunx](https://bun.sh/docs/cli/bunx) 是 Bun 的 `npx` 等效工具。它随 [Bun](https://bun.sh/) 一起提供。

    ```bash theme={null}
    bunx eslint@9 --fix .
    bunx create-vite@6 my-app
    ```

    * 在基于 Bun 的环境中可直接替代 `npx`。
    * 仅适用于用户环境拥有 Bun 而不是 Node.js 的情况。
  </Tab>

  <Tab title="deno run">
    [deno run](https://docs.deno.com/runtime/reference/cli/run/) 直接从 URL 或说明符运行脚本。它随 [Deno](https://deno.com/) 一起提供。

    ```bash theme={null}
    deno run npm:create-vite@6 my-app
    deno run --allow-read npm:eslint@9 -- --fix .
    ```

    * 权限标志（`--allow-read` 等）是文件系统/网络访问所必需的。
    * 使用 `--` 将 Deno 标志与工具自身的标志分开。
  </Tab>

  <Tab title="go run">
    [go run](https://pkg.go.dev/cmd/go#hdr-Compile_and_run_Go_program) 直接编译并运行 Go 包。它内置于 `go` 命令中。

    ```bash theme={null}
    go run golang.org/x/tools/cmd/goimports@v0.28.0 .
    go run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.0 run
    ```

    * 内置于 Go — 无需额外工具。
    * 固定版本或使用 `@latest` 使命令明确。
  </Tab>
</Tabs>

**技能中一次性命令的提示：**

* **固定版本**（例如，`npx eslint@9.0.0`），以便命令随时间保持一致的行为。
* **声明先决条件** 在您的 `SKILL.md` 中（例如，"Requires Node.js 18+"），而不是假设代理的环境已具备它们。对于运行时级别的要求，使用 [`compatibility` frontmatter 字段](/specification#compatibility-field)。
* **将复杂命令移入脚本。** 当您使用几个标志调用工具时，一次性命令效果很好。当命令变得复杂以至于难以第一次就做对时，`scripts/` 中经过测试的脚本更可靠。

## 从 `SKILL.md` 引用脚本

使用**相对于技能目录根目录的路径**来引用捆绑文件。代理会自动解析这些路径 — 无需绝对路径。

在 `SKILL.md` 中列出可用脚本，以便代理知道它们存在：

```markdown SKILL.md theme={null}
## 可用脚本

- **`scripts/validate.sh`** — 验证配置文件
- **`scripts/process.py`** — 处理输入数据
```

然后指示代理运行它们：

````markdown SKILL.md theme={null}
## 工作流

1. 运行验证脚本：
   ```bash
   bash scripts/validate.sh "$INPUT_FILE"
   ```

2. 处理结果：
   ```bash
   python3 scripts/process.py --input results.json
   ```
````

<Note>
  相同的相对路径约定也适用于支持文件（如 `references/*.md`）— 脚本执行路径（在代码块中）相对于**技能目录根目录**，因为代理是从那里运行命令的。
</Note>

## 独立脚本

当您需要可重用的逻辑时，在 `scripts/` 中捆绑一个脚本，该脚本在内联声明其自己的依赖项。代理可以通过单个命令运行脚本 — 无需单独的清单文件或安装步骤。

多种语言支持内联依赖项声明：

<Tabs sync={false}>
  <Tab title="Python">
    [PEP 723](https://peps.python.org/pep-0723/) 定义了内联脚本元数据的标准格式。在 `# ///` 标记内的 TOML 块中声明依赖项：

    ```python scripts/extract.py theme={null}
    # /// script
    # dependencies = [
    #   "beautifulsoup4",
    # ]
    # ///

    from bs4 import BeautifulSoup

    html = '<html><body><h1>Welcome</h1><p class="info">This is a test.</p></body></html>'
    print(BeautifulSoup(html, "html.parser").select_one("p.info").get_text())
    ```

    使用 [uv](https://docs.astral.sh/uv/) 运行（推荐）：

    ```bash theme={null}
    uv run scripts/extract.py
    ```

    `uv run` 创建隔离环境，安装声明的依赖项，并运行脚本。[pipx](https://pipx.pypa.io/) (`pipx run scripts/extract.py`) 也支持 PEP 723。

    * 使用 [PEP 508](https://peps.python.org/pep-0508/) 说明符固定版本：`"beautifulsoup4>=4.12,<5"`。
    * 使用 `requires-python` 约束 Python 版本。
    * 使用 `uv lock --script` 创建锁文件以实现完全可复现性。
  </Tab>

  <Tab title="Deno">
    Deno 的 `npm:` 和 `jsr:` 导入说明符使每个脚本默认都是独立的：

    ```typescript scripts/extract.ts theme={null}
    #!/usr/bin/env -S deno run

    import * as cheerio from "npm:cheerio@1.0.0";

    const html = `<html><body><h1>Welcome</h1><p class="info">This is a test.</p></body></html>`;
    const $ = cheerio.load(html);
    console.log($("p.info").text());
    ```

    ```bash theme={null}
    deno run scripts/extract.ts
    ```

    * 对 npm 包使用 `npm:`，对 Deno 原生包使用 `jsr:`。
    * 版本说明符遵循 semver：`@1.0.0`（精确），`@^1.0.0`（兼容）。
    * 依赖项全局缓存。使用 `--reload` 强制重新获取。
    * 带有原生附加组件（node-gyp）的包可能无法工作 — 提供预构建二进制文件的包效果最好。
  </Tab>

  <Tab title="Bun">
    当未找到 `node_modules` 目录时，Bun 会在运行时自动安装缺失的包。直接在导入路径中固定版本：

    ```typescript scripts/extract.ts theme={null}
    #!/usr/bin/env bun

    import * as cheerio from "cheerio@1.0.0";

    const html = `<html><body><h1>Welcome</h1><p class="info">This is a test.</p></body></html>`;
    const $ = cheerio.load(html);
    console.log($("p.info").text());
    ```

    ```bash theme={null}
    bun run scripts/extract.ts
    ```

    * 不需要 `package.json` 或 `node_modules`。TypeScript 原生工作。
    * 包全局缓存。首次运行下载；后续运行几乎瞬间完成。
    * 如果目录树中任何位置存在 `node_modules` 目录，自动安装将被禁用，Bun 回退到标准 Node.js 解析。
  </Tab>

  <Tab title="Ruby">
    Bundler 自 2.6 版本起随 Ruby 一起提供。使用 `bundler/inline` 直接在脚本中声明 gems：

    ```ruby scripts/extract.rb theme={null}
    require 'bundler/inline'

    gemfile do
      source 'https://rubygems.org'
      gem 'nokogiri'
    end

    html = '<html><body><h1>Welcome</h1><p class="info">This is a test.</p></body></html>'
    doc = Nokogiri::HTML(html)
    puts doc.at_css('p.info').text
    ```

    ```bash theme={null}
    ruby scripts/extract.rb
    ```

    * 显式固定版本（`gem 'nokogiri', '~> 1.16'`）— 没有锁文件。
    * 工作目录中现有的 `Gemfile` 或 `BUNDLE_GEMFILE` 环境变量可能会干扰。
  </Tab>
</Tabs>

## 为代理使用设计脚本

当代理运行您的脚本时，它读取 stdout 和 stderr 来决定下一步做什么。一些设计选择使脚本更容易被代理使用。

### 避免交互式提示

这是代理执行环境的硬性要求。代理在非交互式 shell 中运行 — 它们无法响应 TTY 提示、密码对话框或确认菜单。阻塞等待交互式输入的脚本将无限期挂起。

通过命令行标志、环境变量或 stdin 接受所有输入：

```
# 不好：挂起等待输入
$ python scripts/deploy.py
目标环境：_

# 好：带有指导的清晰错误
$ python scripts/deploy.py
错误：--env 是必需的。选项：development, staging, production.
用法：python scripts/deploy.py --env staging --tag v1.2.3
```

### 使用 `--help` 记录用法

`--help` 输出是代理了解脚本接口的主要方式。包括简短描述、可用标志和用法示例：

```
用法：scripts/process.py [OPTIONS] INPUT_FILE

处理输入数据并生成摘要报告。

选项：
  --format FORMAT    输出格式：json, csv, table（默认：json）
  --output FILE      将输出写入 FILE 而不是 stdout
  --verbose          将进度打印到 stderr

示例：
  scripts/process.py data.csv
  scripts/process.py --format csv --output report.csv data.csv
```

保持简洁 — 输出会与其正在处理的其他内容一起进入代理的上下文窗口。

### 编写有帮助的错误消息

当代理收到错误时，消息直接塑造其下一次尝试。不透明的 "Error: invalid input" 浪费了一次回合。相反，说明出了什么问题、预期是什么以及尝试什么：

```
错误：--format 必须是以下之一：json, csv, table.
       收到："xml"
```

### 使用结构化输出

优先使用结构化格式 — JSON、CSV、TSV — 而不是自由格式文本。结构化格式可以被代理和标准工具（`jq`, `cut`, `awk`）消耗，使您的脚本可在管道中组合。

```
# 空格对齐 — 难以以编程方式解析
NAME          STATUS    CREATED
my-service    running   2025-01-15

# 分隔 — 明确的字段边界
{"name": "my-service", "status": "running", "created": "2025-01-15"}
```

**将数据与诊断分开：** 将结构化数据发送到 stdout，将进度消息、警告和其他诊断发送到 stderr。这让代理能够捕获干净、可解析的输出，同时在需要时仍能访问诊断信息。

### 进一步考虑

* **幂等性。** 代理可能会重试命令。“如果不存在则创建”比“创建并在重复时失败”更安全。
* **输入约束。** 用清晰的错误拒绝模糊的输入，而不是猜测。尽可能使用枚举和封闭集。
* **试运行支持。** 对于破坏性或状态操作，`--dry-run` 标志让代理预览将要发生的事情。
* **有意义的退出代码。** 对不同的失败类型使用不同的退出代码（未找到、无效参数、认证失败），并在 `--help` 输出中记录它们，以便代理知道每个代码的含义。
* **安全的默认值。** 考虑破坏性操作是否需要显式确认标志（`--confirm`, `--force`）或其他适合风险级别的保护措施。
* **可预测的输出大小。** 许多代理框架会自动截断超过阈值（例如 10-30K 字符）的工具输出，可能会丢失关键信息。如果您的脚本可能产生大量输出，默认使用摘要或合理限制，并支持 `--offset` 等标志，以便代理在需要时请求更多信息。或者，如果输出很大且不适合分页，要求代理传递 `--output` 标志，指定输出文件或 `-` 以显式选择加入 stdout。
