diff --git a/README.md b/README.md index b848ca4..833e451 100644 --- a/README.md +++ b/README.md @@ -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. @@ -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: @@ -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 | @@ -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) @@ -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. @@ -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` 进行规格覆盖审计。 diff --git a/feature-missing/action.yml b/feature-missing/action.yml index c1b29ac..0a3c04f 100644 --- a/feature-missing/action.yml +++ b/feature-missing/action.yml @@ -92,18 +92,18 @@ 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 @@ -111,7 +111,7 @@ inputs: ### 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 @@ -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 @@ -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 @@ -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 diff --git a/github-run-opencode/action.yml b/github-run-opencode/action.yml index f6f5e89..c6e90db 100644 --- a/github-run-opencode/action.yml +++ b/github-run-opencode/action.yml @@ -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 @@ -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 diff --git a/github-run-opencode/run-github-opencode.py b/github-run-opencode/run-github-opencode.py index d12166d..69d5421 100755 --- a/github-run-opencode/run-github-opencode.py +++ b/github-run-opencode/run-github-opencode.py @@ -12,6 +12,11 @@ script_dir = Path(__file__).resolve().parent +SUPPORTED_LANGUAGES = {"zh", "en"} +# When adding new API keys or critical env vars to main(), add them here too +# so that extra-env can warn users about overriding them. +SENSITIVE_ENV_KEYS = {"GITHUB_TOKEN", "MODEL", "ZHIPU_API_KEY", "OPENCODE_API_KEY", "DEEPSEEK_API_KEY", "PROMPT"} + def get_env(name: str, default: str = "") -> str: return os.environ.get(name, default) @@ -189,14 +194,43 @@ def main() -> int: # Model resolution (same order as original shell script) if get_env("GITHUB_RUN_OPENCODE_MODEL"): - os.environ["MODEL"] = get_env("GITHUB_RUN_OPENCODE_MODEL") + set_env("MODEL", get_env("GITHUB_RUN_OPENCODE_MODEL")) elif get_env("MODEL_NAME"): - os.environ["MODEL"] = get_env("MODEL_NAME") + set_env("MODEL", get_env("MODEL_NAME")) else: - os.environ["MODEL"] = "zhipuai-coding-plan/glm-5.1" + set_env("MODEL", "zhipuai-coding-plan/glm-5.1") set_env("PROMPT", get_env("GITHUB_RUN_OPENCODE_PROMPT")) set_env("USE_GITHUB_TOKEN", get_env("GITHUB_RUN_OPENCODE_USE_GITHUB_TOKEN")) + + # Language override: append a language instruction to the prompt. + # When PROMPT is empty (e.g. user cleared the default), skip appending + # language instructions since there is nothing to respond to. + language = get_env("GITHUB_RUN_OPENCODE_LANGUAGE", "zh").strip().lower() + existing_prompt = get_env("PROMPT", "") + zh_instruction = ( + "\n\n请使用中文回复。所有分析和说明均使用中文。" + "对于 prompt 中列出的判定关键词,使用其中文版本。" + ) + if existing_prompt: + if language == "en": + set_env("PROMPT", ( + existing_prompt + + "\n\nIMPORTANT: Respond entirely in English. " + "Use English for all analysis, explanations, and output. " + "For any verdict keywords listed in the prompt, use their English equivalents." + )) + elif language == "zh": + set_env("PROMPT", existing_prompt + zh_instruction) + elif language in SUPPORTED_LANGUAGES: + print(f"::debug::Language '{language}' has no dedicated prompt instruction, defaulting to zh") + set_env("PROMPT", existing_prompt + zh_instruction) + else: + print( + f"::warning::Unsupported language: '{language}', defaulting to Chinese. " + f"Supported values are: {', '.join(sorted(SUPPORTED_LANGUAGES))}." + ) + set_env("PROMPT", existing_prompt + zh_instruction) set_env("GITHUB_TOKEN", get_env("GITHUB_RUN_OPENCODE_GITHUB_TOKEN")) set_env("ZHIPU_API_KEY", get_env("GITHUB_RUN_OPENCODE_ZHIPU_API_KEY")) set_env("OPENCODE_API_KEY", get_env("GITHUB_RUN_OPENCODE_OPENCODE_GO_API_KEY")) @@ -216,6 +250,12 @@ def main() -> int: key = key.strip() value = value.strip() if key: + if key.startswith("GITHUB_RUN_OPENCODE_"): + print(f"::warning::extra-env key '{key}' starts with reserved prefix 'GITHUB_RUN_OPENCODE_', this may override internal configuration") + if key in SENSITIVE_ENV_KEYS: + print(f"::warning::extra-env key '{key}' overrides a sensitive runtime variable") + # Intentionally use os.environ instead of set_env() to allow + # users to explicitly set (or clear) a variable with an empty value. os.environ[key] = value reasoning_effort = get_env("GITHUB_RUN_OPENCODE_REASONING_EFFORT", "") @@ -226,7 +266,11 @@ def main() -> int: permission = None if permission_raw: try: - permission = json.loads(permission_raw) + parsed = json.loads(permission_raw) + if not isinstance(parsed, dict): + print(f"GITHUB_RUN_OPENCODE_PERMISSION must be a JSON object, got {type(parsed).__name__}: {permission_raw}", file=sys.stderr) + sys.exit(1) + permission = parsed except json.JSONDecodeError: print(f"Invalid JSON in GITHUB_RUN_OPENCODE_PERMISSION: {permission_raw}", file=sys.stderr) sys.exit(1) diff --git a/review/action.yml b/review/action.yml index 81000eb..f4fbcff 100644 --- a/review/action.yml +++ b/review/action.yml @@ -88,16 +88,16 @@ inputs: - Performance issues - Suggest improvements - Please respond in Chinese. DO NOT modify any code, only provide review comments. + DO NOT modify any code, only provide review comments. The first line of your response must be exactly one of: - - 可合并 - - 有条件合并 - - 不可合并 + - 可合并 / CAN MERGE + - 有条件合并 / CONDITIONAL MERGE + - 不可合并 / CANNOT MERGE Decision rules: - - Use "可合并" only when there are no blocking issues. - - Use "有条件合并" when merge is acceptable only after specific issues are fixed. - - Use "不可合并" when there are blocking risks, correctness issues, or major concerns that should stop the merge. + - Use "可合并" / "CAN MERGE" only when there are no blocking issues. + - Use "有条件合并" / "CONDITIONAL MERGE" when merge is acceptable only after specific issues are fixed. + - Use "不可合并" / "CANNOT MERGE" when there are blocking risks, correctness issues, or major concerns that should stop the merge. Review the latest PR HEAD only. Do not repeat issues from earlier revisions unless they are still reproducible in the current files. @@ -106,8 +106,8 @@ inputs: Output format: - First line: the decision only - Then a short summary - - Then "阻塞项" listing required fixes for merge; if none, write "阻塞项:无" - - Then "建议项" listing non-blocking improvements; if none, write "建议项:无" + - Then "阻塞项" / "Blocking Issues" listing required fixes for merge; if none, write "阻塞项:无" / "Blocking Issues: None" + - Then "建议项" / "Suggestions" listing non-blocking improvements; if none, write "建议项:无" / "Suggestions: None" use-github-token: description: Value exported as USE_GITHUB_TOKEN before running `opencode github run`. required: false @@ -140,9 +140,16 @@ inputs: 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. + 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: "" + language: + description: >- + Response language for the agent. `zh` (default) for Chinese, `en` for English. + required: false + default: "zh" runs: using: composite @@ -247,6 +254,7 @@ runs: GITHUB_RUN_OPENCODE_ENABLE_THINKING: ${{ inputs.enable-thinking }} 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 }} run: | if ! command -v python3 >/dev/null 2>&1; then printf 'python3 is required but not installed on this runner\n' >&2 diff --git a/spec-coverage/action.yml b/spec-coverage/action.yml index 620b5b3..286817e 100644 --- a/spec-coverage/action.yml +++ b/spec-coverage/action.yml @@ -103,19 +103,19 @@ inputs: Analyze the latest PR HEAD only. Verify any gap claim against the current code before listing it. - Please respond in Chinese. DO NOT modify any code. DO NOT run git commit, git push, or any other write operations. Only provide analysis. + DO NOT modify any code. DO NOT run git commit, git push, or any other write operations. Only provide analysis. Verdict rule (MUST follow): - First line must be exactly one of: - - "无需审计" — this PR does not need a spec (bug fix, docs, minor change) - - "全覆盖" — ALL spec tasks are implemented with end-to-end integration - - "发现遗漏" — spec tasks are missing, not integrated, or a spec is required but absent + - "无需审计" / "SKIP" — this PR does not need a spec (bug fix, docs, minor change) + - "全覆盖" / "FULL COVERAGE" — ALL spec tasks are implemented with end-to-end integration + - "发现遗漏" / "GAPS FOUND" — spec tasks are missing, not integrated, or a spec is required but absent Output format: - - First line: the verdict ("无需审计" / "全覆盖" / "发现遗漏") - - If "无需审计": one-line explanation of why, then stop + - First line: the verdict ("无需审计" / "全覆盖" / "发现遗漏" for Chinese; "SKIP" / "FULL COVERAGE" / "GAPS FOUND" for English) + - If "无需审计" / "SKIP": one-line explanation of why, then stop - Otherwise: a short summary listing which spec files you found and how many tasks were checked - - If verdict is "发现遗漏", classify each gap: + - If verdict is "发现遗漏" / "GAPS FOUND", classify each gap: ### CRITICAL Spec tasks with zero implementation — planned but completely absent from the PR. ### MEDIUM @@ -123,7 +123,7 @@ inputs: ### LOW Minor gaps — documentation, non-essential features, or nice-to-haves. For each gap: quote the spec task verbatim, describe what's missing in the implementation, and suggest which file(s) should be modified. - - If verdict is "全覆盖", briefly confirm all spec tasks are covered — do NOT include any severity sections. + - If verdict is "全覆盖" / "FULL COVERAGE", briefly confirm all spec tasks 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 @@ -156,7 +156,9 @@ inputs: 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. + 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: @@ -171,6 +173,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 @@ -275,6 +282,7 @@ 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 }} run: | if ! command -v python3 >/dev/null 2>&1; then printf 'python3 is required but not installed on this runner\n' >&2