From fdda36dc9ace7a14254cb0a66f6f578a12137f11 Mon Sep 17 00:00:00 2001 From: svtter Date: Thu, 14 May 2026 22:34:35 +0800 Subject: [PATCH 01/11] feat: add bilingual (zh/en) language support to all actions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a `language` input (default: `zh`) to all actions that controls the agent's response language. When set to `en`, the Python script appends an English language override instruction to the prompt. Changes: - `run-github-opencode.py`: read `GITHUB_RUN_OPENCODE_LANGUAGE` env var, append English instruction to prompt when language is `en` - `github-run-opencode/action.yml`: add `language` input - `review/action.yml`: add `language` input, update prompt with bilingual verdict keywords (可合并/CAN MERGE, etc.) - `feature-missing/action.yml`: add `language` input, update prompt with bilingual verdict keywords (无遗漏/NO GAPS, etc.) - `spec-coverage/action.yml`: add `language` input, update prompt with bilingual verdict keywords (无需审计/SKIP, etc.) - `README.md`: add complete Chinese documentation section Users can configure language via input or from repository variables: language: ${{ vars.OPENCODE_LANGUAGE }} Co-Authored-By: Claude Opus 4.7 --- README.md | 211 ++++++++++++++++++++- feature-missing/action.yml | 18 +- github-run-opencode/action.yml | 7 + github-run-opencode/run-github-opencode.py | 12 ++ review/action.yml | 22 ++- spec-coverage/action.yml | 20 +- 6 files changed, 267 insertions(+), 23 deletions(-) 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..ace759e 100644 --- a/feature-missing/action.yml +++ b/feature-missing/action.yml @@ -96,14 +96,14 @@ inputs: 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 @@ -152,6 +152,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,6 +260,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 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..e98ece0 100755 --- a/github-run-opencode/run-github-opencode.py +++ b/github-run-opencode/run-github-opencode.py @@ -197,6 +197,18 @@ def main() -> int: 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 + language = get_env("GITHUB_RUN_OPENCODE_LANGUAGE", "zh").strip().lower() + if language == "en": + existing_prompt = os.environ.get("PROMPT", "") + if existing_prompt: + os.environ["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." + ) 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")) diff --git a/review/action.yml b/review/action.yml index 81000eb..c0225ad 100644 --- a/review/action.yml +++ b/review/action.yml @@ -90,14 +90,14 @@ inputs: Please respond in Chinese. 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 @@ -143,6 +143,11 @@ inputs: starting with '#' are ignored. 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 +252,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..11451e8 100644 --- a/spec-coverage/action.yml +++ b/spec-coverage/action.yml @@ -107,15 +107,15 @@ inputs: 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 @@ -171,6 +171,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 +280,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 From 412f60b80e233107633f79a8887b2b503f091f91 Mon Sep 17 00:00:00 2001 From: svtter Date: Thu, 14 May 2026 22:50:45 +0800 Subject: [PATCH 02/11] fix: validate json.loads returns dict for permission input Prevents runtime crash when user passes non-object JSON (e.g. 'true', '42', '[1,2]') as GITHUB_RUN_OPENCODE_PERMISSION. Now prints a clear error message and exits instead of failing with AttributeError in _deep_merge. --- github-run-opencode/run-github-opencode.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/github-run-opencode/run-github-opencode.py b/github-run-opencode/run-github-opencode.py index e98ece0..57edb10 100755 --- a/github-run-opencode/run-github-opencode.py +++ b/github-run-opencode/run-github-opencode.py @@ -238,7 +238,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) From ba5666252c7de5cf37f572bef403d89aa7f661b7 Mon Sep 17 00:00:00 2001 From: svtter Date: Fri, 15 May 2026 00:06:41 +0800 Subject: [PATCH 03/11] fix: remove hardcoded Chinese language instruction from prompt templates Move language-specific response instructions to Python layer where they are dynamically appended based on the language input parameter. This eliminates the conflict when language: en is set but prompt templates contained hardcoded 'Please respond in Chinese.' - Remove 'Please respond in Chinese.' from review, feature-missing, and spec-coverage action.yml prompt templates - Add explicit zh language instruction in Python (append Chinese response directive when language != 'en') --- feature-missing/action.yml | 2 +- github-run-opencode/run-github-opencode.py | 12 +++++++++--- review/action.yml | 2 +- spec-coverage/action.yml | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/feature-missing/action.yml b/feature-missing/action.yml index ace759e..24b44cc 100644 --- a/feature-missing/action.yml +++ b/feature-missing/action.yml @@ -92,7 +92,7 @@ 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: diff --git a/github-run-opencode/run-github-opencode.py b/github-run-opencode/run-github-opencode.py index 57edb10..8c412d8 100755 --- a/github-run-opencode/run-github-opencode.py +++ b/github-run-opencode/run-github-opencode.py @@ -200,15 +200,21 @@ def main() -> int: # Language override: append a language instruction to the prompt language = get_env("GITHUB_RUN_OPENCODE_LANGUAGE", "zh").strip().lower() - if language == "en": - existing_prompt = os.environ.get("PROMPT", "") - if existing_prompt: + existing_prompt = os.environ.get("PROMPT", "") + if existing_prompt: + if language == "en": os.environ["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." ) + else: + os.environ["PROMPT"] = ( + existing_prompt + + "\n\n请使用中文回复。所有分析和说明均使用中文。" + "对于 prompt 中列出的判定关键词,使用其中文版本。" + ) 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")) diff --git a/review/action.yml b/review/action.yml index c0225ad..230f853 100644 --- a/review/action.yml +++ b/review/action.yml @@ -88,7 +88,7 @@ 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 diff --git a/spec-coverage/action.yml b/spec-coverage/action.yml index 11451e8..9c35f66 100644 --- a/spec-coverage/action.yml +++ b/spec-coverage/action.yml @@ -103,7 +103,7 @@ 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: From 77da466bafc125f76d13721b6793f22a54dd4fdd Mon Sep 17 00:00:00 2001 From: svtter Date: Fri, 15 May 2026 00:11:24 +0800 Subject: [PATCH 04/11] =?UTF-8?q?fix:=20address=20review=20suggestions=20?= =?UTF-8?q?=E2=80=94=20normalize=20dev/null=20redirect=20and=20use=20set?= =?UTF-8?q?=5Fenv()=20consistently?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feature-missing/action.yml | 2 +- github-run-opencode/run-github-opencode.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/feature-missing/action.yml b/feature-missing/action.yml index 24b44cc..e2c677e 100644 --- a/feature-missing/action.yml +++ b/feature-missing/action.yml @@ -262,7 +262,7 @@ runs: {"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 + 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/run-github-opencode.py b/github-run-opencode/run-github-opencode.py index 8c412d8..3bcc7b4 100755 --- a/github-run-opencode/run-github-opencode.py +++ b/github-run-opencode/run-github-opencode.py @@ -200,21 +200,21 @@ def main() -> int: # Language override: append a language instruction to the prompt language = get_env("GITHUB_RUN_OPENCODE_LANGUAGE", "zh").strip().lower() - existing_prompt = os.environ.get("PROMPT", "") + existing_prompt = get_env("PROMPT", "") if existing_prompt: if language == "en": - os.environ["PROMPT"] = ( + 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." - ) + )) else: - os.environ["PROMPT"] = ( + set_env("PROMPT", ( existing_prompt + "\n\n请使用中文回复。所有分析和说明均使用中文。" "对于 prompt 中列出的判定关键词,使用其中文版本。" - ) + )) 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")) From 43b6ecf60530ab2a6c78f9cd32c05b76a32034be Mon Sep 17 00:00:00 2001 From: svtter Date: Fri, 15 May 2026 00:17:25 +0800 Subject: [PATCH 05/11] fix: handle unsupported language values with warning, add design intent comment --- github-run-opencode/run-github-opencode.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/github-run-opencode/run-github-opencode.py b/github-run-opencode/run-github-opencode.py index 3bcc7b4..6914006 100755 --- a/github-run-opencode/run-github-opencode.py +++ b/github-run-opencode/run-github-opencode.py @@ -198,7 +198,9 @@ def main() -> int: 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 + # 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", "") if existing_prompt: @@ -209,7 +211,18 @@ def main() -> int: "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 + + "\n\n请使用中文回复。所有分析和说明均使用中文。" + "对于 prompt 中列出的判定关键词,使用其中文版本。" + )) else: + print( + f"Unsupported language: '{language}', defaulting to Chinese. " + "Supported values are 'zh' and 'en'.", + file=sys.stderr, + ) set_env("PROMPT", ( existing_prompt + "\n\n请使用中文回复。所有分析和说明均使用中文。" From 214d3c534cdf5ef38aa7044ddfedfe5e7ba0b0a1 Mon Sep 17 00:00:00 2001 From: svtter Date: Fri, 15 May 2026 00:20:41 +0800 Subject: [PATCH 06/11] fix: deduplicate zh_instruction and use ::warning:: for unsupported language --- github-run-opencode/run-github-opencode.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/github-run-opencode/run-github-opencode.py b/github-run-opencode/run-github-opencode.py index 6914006..653f0a7 100755 --- a/github-run-opencode/run-github-opencode.py +++ b/github-run-opencode/run-github-opencode.py @@ -203,6 +203,10 @@ def main() -> int: # 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", ( @@ -212,22 +216,13 @@ def main() -> int: "For any verdict keywords listed in the prompt, use their English equivalents." )) elif language == "zh": - set_env("PROMPT", ( - existing_prompt - + "\n\n请使用中文回复。所有分析和说明均使用中文。" - "对于 prompt 中列出的判定关键词,使用其中文版本。" - )) + set_env("PROMPT", existing_prompt + zh_instruction) else: print( - f"Unsupported language: '{language}', defaulting to Chinese. " - "Supported values are 'zh' and 'en'.", - file=sys.stderr, + f"::warning::Unsupported language: '{language}', defaulting to Chinese. " + "Supported values are 'zh' and 'en'." ) - set_env("PROMPT", ( - existing_prompt - + "\n\n请使用中文回复。所有分析和说明均使用中文。" - "对于 prompt 中列出的判定关键词,使用其中文版本。" - )) + 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")) From 6b7e8234e456d5cacbbfe9a40d8cc73f0c8fece2 Mon Sep 17 00:00:00 2001 From: svtter Date: Fri, 15 May 2026 00:24:41 +0800 Subject: [PATCH 07/11] fix: use set_env() for MODEL assignment and add extra-env input to feature-missing - Replace os.environ["MODEL"] = ... with set_env() for consistency - Add extra-env input to feature-missing/action.yml, matching review and spec-coverage --- feature-missing/action.yml | 8 ++++++++ github-run-opencode/run-github-opencode.py | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/feature-missing/action.yml b/feature-missing/action.yml index e2c677e..65e271e 100644 --- a/feature-missing/action.yml +++ b/feature-missing/action.yml @@ -140,6 +140,13 @@ 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. + required: false + default: "" fallback-models: description: Optional comma- or newline-delimited fallback models tried after timeout or timeout-like failures. required: false @@ -261,6 +268,7 @@ runs: 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 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 653f0a7..723eea7 100755 --- a/github-run-opencode/run-github-opencode.py +++ b/github-run-opencode/run-github-opencode.py @@ -189,11 +189,11 @@ 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")) From 25793c599993afa8abdf55719a753d5dd869d5ee Mon Sep 17 00:00:00 2001 From: svtter Date: Fri, 15 May 2026 00:28:48 +0800 Subject: [PATCH 08/11] refactor: add SUPPORTED_LANGUAGES constant and reserved prefix warning for extra-env - Define SUPPORTED_LANGUAGES set for easier language support extension - Add warning when extra-env key starts with GITHUB_RUN_OPENCODE_ prefix - Addresses review suggestions from AI code review --- github-run-opencode/run-github-opencode.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/github-run-opencode/run-github-opencode.py b/github-run-opencode/run-github-opencode.py index 723eea7..ca6d1d4 100755 --- a/github-run-opencode/run-github-opencode.py +++ b/github-run-opencode/run-github-opencode.py @@ -201,6 +201,7 @@ def main() -> int: # 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. + SUPPORTED_LANGUAGES = {"zh", "en"} language = get_env("GITHUB_RUN_OPENCODE_LANGUAGE", "zh").strip().lower() existing_prompt = get_env("PROMPT", "") zh_instruction = ( @@ -215,12 +216,12 @@ def main() -> int: "Use English for all analysis, explanations, and output. " "For any verdict keywords listed in the prompt, use their English equivalents." )) - elif language == "zh": + elif language in SUPPORTED_LANGUAGES: set_env("PROMPT", existing_prompt + zh_instruction) else: print( f"::warning::Unsupported language: '{language}', defaulting to Chinese. " - "Supported values are 'zh' and 'en'." + 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")) @@ -242,6 +243,8 @@ 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") os.environ[key] = value reasoning_effort = get_env("GITHUB_RUN_OPENCODE_REASONING_EFFORT", "") From 0fbc29e66e52d17af608566dc5840a20d2dfb98a Mon Sep 17 00:00:00 2001 From: svtter Date: Fri, 15 May 2026 00:36:48 +0800 Subject: [PATCH 09/11] =?UTF-8?q?fix:=20address=20review=20suggestions=20?= =?UTF-8?q?=E2=80=94=20module-level=20constants,=20sensitive=20env=20warni?= =?UTF-8?q?ngs,=20language=20branch=20comment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .serena/.gitignore | 2 + .serena/project.yml | 132 ++++++++++++++++++ feature-missing/action.yml | 4 +- .../run-github-opencode.cpython-311.pyc | Bin 0 -> 19730 bytes github-run-opencode/run-github-opencode.py | 9 +- review/action.yml | 4 +- spec-coverage/action.yml | 4 +- 7 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 .serena/.gitignore create mode 100644 .serena/project.yml create mode 100644 github-run-opencode/__pycache__/run-github-opencode.cpython-311.pyc diff --git a/.serena/.gitignore b/.serena/.gitignore new file mode 100644 index 0000000..2e510af --- /dev/null +++ b/.serena/.gitignore @@ -0,0 +1,2 @@ +/cache +/project.local.yml diff --git a/.serena/project.yml b/.serena/project.yml new file mode 100644 index 0000000..b828e38 --- /dev/null +++ b/.serena/project.yml @@ -0,0 +1,132 @@ +# the name by which the project can be referenced within Serena +project_name: "pr-74" + + +# list of languages for which language servers are started; choose from: +# al angular ansible bash clojure +# cpp cpp_ccls crystal csharp csharp_omnisharp +# dart elixir elm erlang fortran +# fsharp go groovy haskell haxe +# hlsl html java json julia +# kotlin lean4 lua luau markdown +# matlab msl nix ocaml pascal +# perl php php_phpactor powershell python +# python_jedi python_ty r rego ruby +# ruby_solargraph rust scala scss solidity +# swift systemverilog terraform toml typescript +# typescript_vts vue yaml zig +# (This list may be outdated. For the current list, see values of Language enum here: +# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py +# For some languages, there are alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.) +# Note: +# - For C, use cpp +# - For JavaScript, use typescript +# - For Angular projects, use angular (subsumes typescript+html; requires `npm install` in the project root) +# - For SCSS / Sass / plain CSS, use scss (some-sass-language-server handles all three) +# - For Free Pascal/Lazarus, use pascal +# Special requirements: +# Some languages require additional setup/installations. +# See here for details: https://oraios.github.io/serena/01-about/020_programming-languages.html#language-servers +# When using multiple languages, the first language server that supports a given file will be used for that file. +# The first language is the default language and the respective language server will be used as a fallback. +# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored. +languages: +- bash + +# the encoding used by text files in the project +# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings +encoding: "utf-8" + +# line ending convention to use when writing source files. +# Possible values: unset (use global setting), "lf", "crlf", or "native" (platform default) +# This does not affect Serena's own files (e.g. memories and configuration files), which always use native line endings. +line_ending: + +# The language backend to use for this project. +# If not set, the global setting from serena_config.yml is used. +# Valid values: LSP, JetBrains +# Note: the backend is fixed at startup. If a project with a different backend +# is activated post-init, an error will be returned. +language_backend: + +# whether to use project's .gitignore files to ignore files +ignore_all_files_in_gitignore: true + +# advanced configuration option allowing to configure language server-specific options. +# Maps the language key to the options. +# Have a look at the docstring of the constructors of the LS implementations within solidlsp (e.g., for C# or PHP) to see which options are available. +# No documentation on options means no options are available. +ls_specific_settings: {} + +# list of additional workspace folder paths for cross-package reference support (e.g. in monorepos). +# Paths can be absolute or relative to the project root. +# Each folder is registered as an LSP workspace folder, enabling language servers to discover +# symbols and references across package boundaries. +# Currently supported for: TypeScript. +# Example: +# additional_workspace_folders: +# - ../sibling-package +# - ../shared-lib +additional_workspace_folders: [] + +# list of additional paths to ignore in this project. +# Same syntax as gitignore, so you can use * and **. +# Note: global ignored_paths from serena_config.yml are also applied additively. +ignored_paths: [] + +# whether the project is in read-only mode +# If set to true, all editing tools will be disabled and attempts to use them will result in an error +# Added on 2025-04-18 +read_only: false + +# list of tool names to exclude. +# This extends the existing exclusions (e.g. from the global configuration) +# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html +excluded_tools: [] + +# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default). +# This extends the existing inclusions (e.g. from the global configuration). +# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html +included_optional_tools: [] + +# fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools. +# This cannot be combined with non-empty excluded_tools or included_optional_tools. +# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html +fixed_tools: [] + +# list of mode names that are to be activated by default, overriding the setting in the global configuration. +# The full set of modes to be activated is base_modes (from global config) + default_modes + added_modes. +# If the setting is undefined/empty, the default_modes from the global configuration (serena_config.yml) apply. +# Otherwise, this overrides the setting from the global configuration (serena_config.yml). +# Therefore, you can set this to [] if you do not want the default modes defined in the global config to apply +# for this project. +# This setting can, in turn, be overridden by CLI parameters (--mode). +# See https://oraios.github.io/serena/02-usage/050_configuration.html#modes +default_modes: + +# list of mode names to be activated additionally for this project, e.g. ["query-projects"] +# The full set of modes to be activated is base_modes (from global config) + default_modes + added_modes. +# See https://oraios.github.io/serena/02-usage/050_configuration.html#modes +added_modes: + +# initial prompt for the project. It will always be given to the LLM upon activating the project +# (contrary to the memories, which are loaded on demand). +initial_prompt: "" + +# time budget (seconds) per tool call for the retrieval of additional symbol information +# such as docstrings or parameter information. +# This overrides the corresponding setting in the global configuration; see the documentation there. +# If null or missing, use the setting from the global configuration. +symbol_info_budget: + +# list of regex patterns which, when matched, mark a memory entry as read‑only. +# Extends the list from the global configuration, merging the two lists. +read_only_memory_patterns: [] + +# list of regex patterns for memories to completely ignore. +# Matching memories will not appear in list_memories or activate_project output +# and cannot be accessed via read_memory or write_memory. +# To access ignored memory files, use the read_file tool on the raw file path. +# Extends the list from the global configuration, merging the two lists. +# Example: ["_archive/.*", "_episodes/.*"] +ignored_memory_patterns: [] diff --git a/feature-missing/action.yml b/feature-missing/action.yml index 65e271e..0a3c04f 100644 --- a/feature-missing/action.yml +++ b/feature-missing/action.yml @@ -144,7 +144,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: diff --git a/github-run-opencode/__pycache__/run-github-opencode.cpython-311.pyc b/github-run-opencode/__pycache__/run-github-opencode.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9fd1df35f6dd15605a06c0e319babc761611721e GIT binary patch literal 19730 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 str: return os.environ.get(name, default) @@ -201,7 +204,6 @@ def main() -> int: # 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. - SUPPORTED_LANGUAGES = {"zh", "en"} language = get_env("GITHUB_RUN_OPENCODE_LANGUAGE", "zh").strip().lower() existing_prompt = get_env("PROMPT", "") zh_instruction = ( @@ -216,6 +218,9 @@ def main() -> int: "Use English for all analysis, explanations, and output. " "For any verdict keywords listed in the prompt, use their English equivalents." )) + # When adding a new language to SUPPORTED_LANGUAGES, add a dedicated + # if/elif branch above with the correct instruction; otherwise the + # new language falls through to the zh default here. elif language in SUPPORTED_LANGUAGES: set_env("PROMPT", existing_prompt + zh_instruction) else: @@ -245,6 +250,8 @@ def main() -> int: 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") os.environ[key] = value reasoning_effort = get_env("GITHUB_RUN_OPENCODE_REASONING_EFFORT", "") diff --git a/review/action.yml b/review/action.yml index 230f853..f4fbcff 100644 --- a/review/action.yml +++ b/review/action.yml @@ -140,7 +140,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: "" language: diff --git a/spec-coverage/action.yml b/spec-coverage/action.yml index 9c35f66..286817e 100644 --- a/spec-coverage/action.yml +++ b/spec-coverage/action.yml @@ -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: From 4d595a18b71fa3200b817812b392d1f43b03bf87 Mon Sep 17 00:00:00 2001 From: svtter Date: Fri, 15 May 2026 00:37:01 +0800 Subject: [PATCH 10/11] chore: remove accidentally tracked .serena and __pycache__ --- .serena/.gitignore | 2 - .serena/project.yml | 132 ------------------ .../run-github-opencode.cpython-311.pyc | Bin 19730 -> 0 bytes 3 files changed, 134 deletions(-) delete mode 100644 .serena/.gitignore delete mode 100644 .serena/project.yml delete mode 100644 github-run-opencode/__pycache__/run-github-opencode.cpython-311.pyc diff --git a/.serena/.gitignore b/.serena/.gitignore deleted file mode 100644 index 2e510af..0000000 --- a/.serena/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/cache -/project.local.yml diff --git a/.serena/project.yml b/.serena/project.yml deleted file mode 100644 index b828e38..0000000 --- a/.serena/project.yml +++ /dev/null @@ -1,132 +0,0 @@ -# the name by which the project can be referenced within Serena -project_name: "pr-74" - - -# list of languages for which language servers are started; choose from: -# al angular ansible bash clojure -# cpp cpp_ccls crystal csharp csharp_omnisharp -# dart elixir elm erlang fortran -# fsharp go groovy haskell haxe -# hlsl html java json julia -# kotlin lean4 lua luau markdown -# matlab msl nix ocaml pascal -# perl php php_phpactor powershell python -# python_jedi python_ty r rego ruby -# ruby_solargraph rust scala scss solidity -# swift systemverilog terraform toml typescript -# typescript_vts vue yaml zig -# (This list may be outdated. For the current list, see values of Language enum here: -# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py -# For some languages, there are alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.) -# Note: -# - For C, use cpp -# - For JavaScript, use typescript -# - For Angular projects, use angular (subsumes typescript+html; requires `npm install` in the project root) -# - For SCSS / Sass / plain CSS, use scss (some-sass-language-server handles all three) -# - For Free Pascal/Lazarus, use pascal -# Special requirements: -# Some languages require additional setup/installations. -# See here for details: https://oraios.github.io/serena/01-about/020_programming-languages.html#language-servers -# When using multiple languages, the first language server that supports a given file will be used for that file. -# The first language is the default language and the respective language server will be used as a fallback. -# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored. -languages: -- bash - -# the encoding used by text files in the project -# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings -encoding: "utf-8" - -# line ending convention to use when writing source files. -# Possible values: unset (use global setting), "lf", "crlf", or "native" (platform default) -# This does not affect Serena's own files (e.g. memories and configuration files), which always use native line endings. -line_ending: - -# The language backend to use for this project. -# If not set, the global setting from serena_config.yml is used. -# Valid values: LSP, JetBrains -# Note: the backend is fixed at startup. If a project with a different backend -# is activated post-init, an error will be returned. -language_backend: - -# whether to use project's .gitignore files to ignore files -ignore_all_files_in_gitignore: true - -# advanced configuration option allowing to configure language server-specific options. -# Maps the language key to the options. -# Have a look at the docstring of the constructors of the LS implementations within solidlsp (e.g., for C# or PHP) to see which options are available. -# No documentation on options means no options are available. -ls_specific_settings: {} - -# list of additional workspace folder paths for cross-package reference support (e.g. in monorepos). -# Paths can be absolute or relative to the project root. -# Each folder is registered as an LSP workspace folder, enabling language servers to discover -# symbols and references across package boundaries. -# Currently supported for: TypeScript. -# Example: -# additional_workspace_folders: -# - ../sibling-package -# - ../shared-lib -additional_workspace_folders: [] - -# list of additional paths to ignore in this project. -# Same syntax as gitignore, so you can use * and **. -# Note: global ignored_paths from serena_config.yml are also applied additively. -ignored_paths: [] - -# whether the project is in read-only mode -# If set to true, all editing tools will be disabled and attempts to use them will result in an error -# Added on 2025-04-18 -read_only: false - -# list of tool names to exclude. -# This extends the existing exclusions (e.g. from the global configuration) -# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html -excluded_tools: [] - -# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default). -# This extends the existing inclusions (e.g. from the global configuration). -# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html -included_optional_tools: [] - -# fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools. -# This cannot be combined with non-empty excluded_tools or included_optional_tools. -# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html -fixed_tools: [] - -# list of mode names that are to be activated by default, overriding the setting in the global configuration. -# The full set of modes to be activated is base_modes (from global config) + default_modes + added_modes. -# If the setting is undefined/empty, the default_modes from the global configuration (serena_config.yml) apply. -# Otherwise, this overrides the setting from the global configuration (serena_config.yml). -# Therefore, you can set this to [] if you do not want the default modes defined in the global config to apply -# for this project. -# This setting can, in turn, be overridden by CLI parameters (--mode). -# See https://oraios.github.io/serena/02-usage/050_configuration.html#modes -default_modes: - -# list of mode names to be activated additionally for this project, e.g. ["query-projects"] -# The full set of modes to be activated is base_modes (from global config) + default_modes + added_modes. -# See https://oraios.github.io/serena/02-usage/050_configuration.html#modes -added_modes: - -# initial prompt for the project. It will always be given to the LLM upon activating the project -# (contrary to the memories, which are loaded on demand). -initial_prompt: "" - -# time budget (seconds) per tool call for the retrieval of additional symbol information -# such as docstrings or parameter information. -# This overrides the corresponding setting in the global configuration; see the documentation there. -# If null or missing, use the setting from the global configuration. -symbol_info_budget: - -# list of regex patterns which, when matched, mark a memory entry as read‑only. -# Extends the list from the global configuration, merging the two lists. -read_only_memory_patterns: [] - -# list of regex patterns for memories to completely ignore. -# Matching memories will not appear in list_memories or activate_project output -# and cannot be accessed via read_memory or write_memory. -# To access ignored memory files, use the read_file tool on the raw file path. -# Extends the list from the global configuration, merging the two lists. -# Example: ["_archive/.*", "_episodes/.*"] -ignored_memory_patterns: [] diff --git a/github-run-opencode/__pycache__/run-github-opencode.cpython-311.pyc b/github-run-opencode/__pycache__/run-github-opencode.cpython-311.pyc deleted file mode 100644 index 9fd1df35f6dd15605a06c0e319babc761611721e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19730 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 Date: Fri, 15 May 2026 00:40:33 +0800 Subject: [PATCH 11/11] refactor: address review suggestions for language fallback and env handling - Split 'zh' into explicit branch so future languages hit debug warning - Add comment explaining intentional os.environ use in extra-env - Add maintenance comment to SENSITIVE_ENV_KEYS --- github-run-opencode/run-github-opencode.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/github-run-opencode/run-github-opencode.py b/github-run-opencode/run-github-opencode.py index 19f99c1..69d5421 100755 --- a/github-run-opencode/run-github-opencode.py +++ b/github-run-opencode/run-github-opencode.py @@ -13,6 +13,8 @@ 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"} @@ -218,10 +220,10 @@ def main() -> int: "Use English for all analysis, explanations, and output. " "For any verdict keywords listed in the prompt, use their English equivalents." )) - # When adding a new language to SUPPORTED_LANGUAGES, add a dedicated - # if/elif branch above with the correct instruction; otherwise the - # new language falls through to the zh default here. + 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( @@ -252,6 +254,8 @@ def main() -> int: 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", "")