Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
211 changes: 209 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# opencode-actions

[中文文档](#中文文档)

Reusable GitHub Actions for installing and running OpenCode in other repositories.

This repository is licensed under Apache 2.0.
Expand All @@ -20,7 +22,7 @@ Write this in your CI.yaml
opencode-go-api-key: ${{ secrets.OPENCODE_GO_API_KEY }}
```

You'll get a automatic reviewer in Chinese.
You'll get an automatic reviewer (Chinese by default, configurable via `language` input).

Or add the skills to your project:

Expand Down Expand Up @@ -64,6 +66,7 @@ Use this when you want the shortest consumer workflow for `opencode github run`.
| `reasoning-effort` | `max` | Reasoning effort level for the model agent (`low`, `medium`, `high`, `max`) |
| `enable-thinking` | `true` | Enable thinking mode for the model agent |
| `use-github-token` | `true` | Exported as `USE_GITHUB_TOKEN` before `opencode github run` |
| `language` | `zh` | Response language: `zh` for Chinese, `en` for English |
| `attempts` | `3` | Total attempts before failing |
| `retry-profile` | `github-network` | Built-in retry preset for common GitHub failures |
| `timeout-seconds` | `600` | Maximum execution time for `opencode github run`; `0` disables it |
Expand Down Expand Up @@ -108,7 +111,7 @@ Use this alongside `review` and `feature-missing` to audit whether a PR implemen
Unlike `feature-missing` (which checks PR self-described scope), `spec-coverage` uses the project's own spec files as the **authoritative source of intended scope**. This catches cases where a PR implements part of a larger planned feature but skips critical integration steps.

- auto-discovers spec files in `openspec/changes/*/tasks.md`, `specs/**`, and other common locations
- intelligently skips bug fixes and minor changes that don't need specs (`无需审计`)
- intelligently skips bug fixes and minor changes that don't need specs (`SKIP`)
- reports missing spec files as a CRITICAL gap when a feature PR should have one but doesn't
- cross-references unchecked task items against the PR diff
- checks end-to-end integration (models read at runtime, configs consumed, APIs called)
Expand Down Expand Up @@ -199,6 +202,26 @@ uses: Svtter/opencode-actions/run-opencode@v2
opencode-go-api-key: ${{ secrets.OPENCODE_GO_API_KEY }}
```

To use English output, set the `language` input:

```yaml
- name: Run OpenCode review (English)
uses: Svtter/opencode-actions/review@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
language: en
```

Or configure it from repository variables:

```yaml
- name: Run OpenCode review
uses: Svtter/opencode-actions/review@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
language: ${{ vars.OPENCODE_LANGUAGE }}
```

More examples live in `examples/`.

If you need more control, you can still use `setup-opencode` and `run-opencode` directly. For example, pass `opencode-path` explicitly when reusing a binary from another job or a custom location.
Expand Down Expand Up @@ -243,3 +266,187 @@ The initial release-notes template lives at `docs/releases/v1.0.0.md`.
- `args` is parsed as a space-delimited string, so keep complex text in environment variables like `PROMPT`
- the installer is external, so cache invalidation uses `cache-key` instead of a guaranteed version pin
- first version is optimized for GitHub-hosted or Linux self-hosted runners

---

# 中文文档

[English Documentation](#opencode-actions)

可复用的 GitHub Actions,用于在其他仓库中安装和运行 OpenCode。

本仓库基于 Apache 2.0 许可证。

## 快速开始

在你的 CI.yaml 中写入:

```yaml
- name: Run OpenCode review
uses: Svtter/opencode-actions/review@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

# 以下密钥只需提供一个即可
deepseek-api-key: ${{ secrets.DEEPSEEK_API_KEY }}
zhipu-api-key: ${{ secrets.ZHIPU_API_KEY }}
opencode-go-api-key: ${{ secrets.OPENCODE_GO_API_KEY }}
```

你将获得一个自动化的 PR 审查机器人(默认中文回复,可通过 `language` 输入切换语言)。

或将技能添加到你的项目:

```bash
npx skills add sun-praise/opencode-actions
```

## 包含的 Actions

- `review`:内置 prompt 和模型默认值的 PR 审查封装
- `feature-missing`:对照关联 issue 的需求,审计 PR 实现的完整性
- `spec-coverage`:对照项目规格/任务文件,交叉检查 PR 实现的覆盖度
- `github-run-opencode`:`opencode github run` 常用工作流的一步封装
- `setup-opencode`:安装 OpenCode,恢复缓存,导出二进制路径
- `run-opencode`:运行 `opencode`,支持 GitHub 网络抖动的重试逻辑

## 语言配置

所有 action 均支持 `language` 输入参数,用于控制 agent 的回复语言:

- `zh`(默认):中文回复
- `en`:英文回复

```yaml
- name: Run OpenCode review (英文)
uses: Svtter/opencode-actions/review@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
language: en
```

也可以从仓库变量中读取:

```yaml
- name: Run OpenCode review
uses: Svtter/opencode-actions/review@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
language: ${{ vars.OPENCODE_LANGUAGE }}
```

## 三个审查 Action 的区别

| Action | 审查范围 | 发现的问题 |
| --- | --- | --- |
| `review` | PR diff | 代码质量、安全问题、Bug |
| `feature-missing` | PR 标题/正文 + 关联 issue | PR 自述需求的完整性 |
| `spec-coverage` | 项目规格/任务文件 | 计划范围 vs 实际实现的差距 |

## review

最简单的 PR 审查方案。

- 内置审查 prompt 模板
- 内置 `MODEL` 解析:显式 `model` 输入 > `MODEL_NAME` 环境变量 > `zhipuai-coding-plan/glm-5.1`
- 内置 `timeout-seconds` 默认值:`600`(10 分钟)
- 可选的 `fallback-models` 支持超时驱动的模型轮换

## feature-missing

配合 `review` 使用,审计 PR 是否完整实现了关联 issue 中的需求。

- 自动通过 `gh pr view` 读取关联 issue 作为需求规格
- 如无关联 issue,从 PR 标题和正文提取需求
- 按严重程度分类:CRITICAL / MEDIUM / LOW

```yaml
- name: Run feature missing audit
uses: Svtter/opencode-actions/feature-missing@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
zhipu-api-key: ${{ secrets.ZHIPU_API_KEY }}
opencode-go-api-key: ${{ secrets.OPENCODE_GO_API_KEY }}
```

## spec-coverage

配合 `review` 和 `feature-missing` 使用,审计 PR 是否实现了项目规格/任务文件中的全部计划。

与 `feature-missing`(检查 PR 自述范围)不同,`spec-coverage` 使用项目自身的规格文件作为**预期范围的权威来源**。可以发现 PR 实现了大型计划功能的一部分但跳过了关键集成步骤的情况。

- 自动发现 `openspec/changes/*/tasks.md`、`specs/**` 等位置的规格文件
- 智能跳过不需要规格的 bug 修复和小改动
- 当功能型 PR 缺少规格文件时报告为 CRITICAL 级别的遗漏
- 按严重程度分类:CRITICAL / MEDIUM / LOW

```yaml
- name: Run spec coverage audit
uses: Svtter/opencode-actions/spec-coverage@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
zhipu-api-key: ${{ secrets.ZHIPU_API_KEY }}
opencode-go-api-key: ${{ secrets.OPENCODE_GO_API_KEY }}
```

## github-run-opencode

当你需要最简短的 `opencode github run` 工作流时使用。

### 常用输入

| 输入 | 默认值 | 描述 |
| --- | --- | --- |
| `model` | `MODEL_NAME`,否则 `zhipuai-coding-plan/glm-5.1` | 在 `opencode github run` 前导出为 `MODEL` |
| `fallback-models` | 空 | 可选的有序回退模型列表,按可用 API 密钥过滤 |
| `prompt` | 内置 PR 审查模板 | 在 `opencode github run` 前导出为 `PROMPT` |
| `language` | `zh` | 回复语言:`zh` 中文,`en` 英文 |
| `github-token` | 空 | 在 `opencode github run` 前导出为 `GITHUB_TOKEN` |
| `zhipu-api-key` | 空 | 在 `opencode github run` 前导出为 `ZHIPU_API_KEY` |
| `deepseek-api-key` | 空 | 在 `opencode github run` 前导出为 `DEEPSEEK_API_KEY` |
| `opencode-go-api-key` | 空 | 在 `opencode github run` 前导出为 `OPENCODE_GO_API_KEY` |
| `reasoning-effort` | `max` | 模型推理力度(`low`、`medium`、`high`、`max`) |
| `enable-thinking` | `true` | 启用模型的 thinking 模式 |
| `attempts` | `3` | 失败前的总尝试次数 |
| `timeout-seconds` | `600` | `opencode github run` 的最大执行时间;`0` 禁用 |

## setup-opencode

### 输入

| 输入 | 默认值 | 描述 |
| --- | --- | --- |
| `install-url` | `https://opencode.ai/install` | 引导安装 OpenCode 的安装器 URL |
| `install-dir` | 自动计算 | `opencode` 安装目录 |
| `xdg-cache-home` | 自动计算 | XDG 缓存目录 |
| `cache` | `true` | 启用 `actions/cache` 缓存 |
| `cache-key` | `v1` | 用于使安装器缓存失效的键后缀 |
| `install-attempts` | `3` | 安装器总尝试次数 |
| `allow-preinstalled` | `false` | 复用 PATH 上已有的可信 `opencode` |

## 使用方式

```yaml
uses: Svtter/opencode-actions/review@v2
uses: Svtter/opencode-actions/feature-missing@v2
uses: Svtter/opencode-actions/spec-coverage@v2
uses: Svtter/opencode-actions/github-run-opencode@v2
uses: Svtter/opencode-actions/setup-opencode@v2
uses: Svtter/opencode-actions/run-opencode@v2
```

更多示例请参见 `examples/` 目录。

## 本地验证

```bash
bash tests/test.sh
```

## 发布清单

1. 公开推送仓库。
2. 确认 `main` 分支的 CI 通过。
3. 创建带有 semver 标签(如 `v1.0.0`)的 GitHub Release。
4. 确认 `Update Major Tag` 工作流将 `v1` 标签移至该 release。
5. 使用 `owner/repo/review@v2` 进行审查,`owner/repo/feature-missing@v2` 进行 PR 范围审计,`owner/repo/spec-coverage@v2` 进行规格覆盖审计。
32 changes: 24 additions & 8 deletions feature-missing/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,26 +92,26 @@ inputs:
Do not repeat issues from earlier revisions unless they are still reproducible in the current files.
Verify any gap claim against the current code before listing it.

Please respond in Chinese. DO NOT modify any code, only provide analysis.
DO NOT modify any code, only provide analysis.

Verdict rule (MUST follow):
- After completing your analysis, set the first line to exactly one of:
- "无遗漏" if and only if ALL spec items are fully implemented (no gaps at all)
- "发现遗漏" if and only if at least one gap exists
- The first line MUST match your actual finding. NEVER write "发现遗漏" when no gaps exist.
- "无遗漏" / "NO GAPS" if and only if ALL spec items are fully implemented (no gaps at all)
- "发现遗漏" / "GAPS FOUND" if and only if at least one gap exists
- The first line MUST match your actual finding. NEVER write "发现遗漏" / "GAPS FOUND" when no gaps exist.

Output format:
- First line: the verdict ("无遗漏" or "发现遗漏") — see verdict rule above
- First line: the verdict ("无遗漏" or "发现遗漏" for Chinese; "NO GAPS" or "GAPS FOUND" for English) — see verdict rule above
- Then a short summary of your analysis
- If verdict is "发现遗漏", classify each gap by severity:
- If verdict is "发现遗漏" / "GAPS FOUND", classify each gap by severity:
### CRITICAL
Core functionality described in the spec is missing or completely non-functional.
### MEDIUM
Partial implementation, integration gaps, or important edge cases not handled.
### LOW
Minor gaps, nice-to-have features, or documentation discrepancies.
For each gap: describe what's missing, reference the relevant spec section, and suggest where the implementation should be added.
- If verdict is "无遗漏", briefly confirm all spec items are covered — do NOT include any severity sections.
- If verdict is "无遗漏" / "NO GAPS", briefly confirm all spec items are covered — do NOT include any severity sections.
use-github-token:
description: Value exported as USE_GITHUB_TOKEN before running `opencode github run`.
required: false
Expand Down Expand Up @@ -140,6 +140,15 @@ inputs:
description: Enable thinking mode for the model agent. When true, generates opencode.json with thinking.type=enabled.
required: false
default: "true"
extra-env:
description: >-
Extra environment variables to pass to opencode runtime.
Multi-line KEY=VALUE pairs, one per line. Empty lines and lines
starting with '#' are ignored. Note: these variables are set after
internal configuration and may override sensitive runtime settings
such as MODEL, GITHUB_TOKEN, or API keys.
required: false
default: ""
fallback-models:
description: Optional comma- or newline-delimited fallback models tried after timeout or timeout-like failures.
required: false
Expand All @@ -152,6 +161,11 @@ inputs:
description: Rotate to the next fallback model when output matches this regex.
required: false
default: timed out|timeout|deadline exceeded|context deadline exceeded|operation timed out|connection timed out
language:
description: >-
Response language for the agent. `zh` (default) for Chinese, `en` for English.
required: false
default: "zh"

runs:
using: composite
Expand Down Expand Up @@ -255,8 +269,10 @@ runs:
GITHUB_RUN_OPENCODE_FALLBACK_ON_REGEX: ${{ inputs.fallback-on-regex }}
GITHUB_RUN_OPENCODE_PERMISSION: >-
{"edit":"deny","bash":{"git commit *":"deny","git push *":"deny","git add *":"deny","git stash *":"deny","git reset *":"deny","git checkout *":"deny"}}
GITHUB_RUN_OPENCODE_LANGUAGE: ${{ inputs.language }}
GITHUB_RUN_OPENCODE_EXTRA_ENV: ${{ inputs.extra-env }}
run: |
if ! command -v python3 >\/dev/null 2>&1; then
if ! command -v python3 >/dev/null 2>&1; then
printf 'python3 is required but not installed on this runner\n' >&2
exit 1
fi
Expand Down
7 changes: 7 additions & 0 deletions github-run-opencode/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ inputs:
Example: '{"edit":"deny","bash":{"git commit *":"deny"}}'
required: false
default: ""
language:
description: >-
Response language for the agent. `zh` (default) for Chinese, `en` for English.
Appends a language override instruction to the prompt.
required: false
default: "zh"

runs:
using: composite
Expand Down Expand Up @@ -215,6 +221,7 @@ runs:
GITHUB_RUN_OPENCODE_REASONING_EFFORT: ${{ inputs.reasoning-effort }}
GITHUB_RUN_OPENCODE_ENABLE_THINKING: ${{ inputs.enable-thinking }}
GITHUB_RUN_OPENCODE_PERMISSION: ${{ inputs.permission }}
GITHUB_RUN_OPENCODE_LANGUAGE: ${{ inputs.language }}
run: |
if ! command -v python3 >/dev/null 2>&1; then
printf 'python3 is required but not installed on this runner\n' >&2
Expand Down
Loading