From bb55a9e2d995d9de10269a1c1a1a7aeb0039373e Mon Sep 17 00:00:00 2001 From: samson910022 Date: Thu, 10 Sep 2026 04:20:08 +0800 Subject: [PATCH 1/2] docs(bot): unquoted placeholder values so scan examples aren't findings --- docs/AI_BOT.md | 2 +- github_bot/README.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/AI_BOT.md b/docs/AI_BOT.md index c02136b..7ca2c83 100644 --- a/docs/AI_BOT.md +++ b/docs/AI_BOT.md @@ -82,7 +82,7 @@ Point at a local gateway (start one with `API_KEY= OPENCODE_PROXY_MANAGE_BACKEND or fill placeholders — never commit real values: ```bash -export GATEWAY_BASE_URL='http://127.0.0.1:10000' GATEWAY_API_KEY='' CPA_BASE_URL='...' CPA_API_KEY='...' +export GATEWAY_BASE_URL='http://127.0.0.1:10000' GATEWAY_API_KEY='' CPA_BASE_URL=your-cpa-url-here CPA_API_KEY=your-cpa-key-here export PYTHONPATH=github_bot/src python3 github_bot/src/github_runner.py --mode=review --dry-run python3 github_bot/src/github_runner.py --mode=triage --dry-run diff --git a/github_bot/README.md b/github_bot/README.md index 1bb047c..669c840 100644 --- a/github_bot/README.md +++ b/github_bot/README.md @@ -36,9 +36,9 @@ To use an external gateway or CPA, export names only (never commit values): ```bash export GATEWAY_BASE_URL='http://127.0.0.1:10000' # external override; in-job default when unset -export GATEWAY_API_KEY='...' # external gateway key; empty = no-auth localhost -export CPA_BASE_URL='...' # never commit (fallback channel) -export CPA_API_KEY='...' # never commit (fallback channel) +export GATEWAY_API_KEY=your-gateway-key-here # external gateway key; empty = no-auth localhost +export CPA_BASE_URL=your-cpa-url-here # never commit (fallback channel) +export CPA_API_KEY=your-cpa-key-here # never commit (fallback channel) export PYTHONPATH=github_bot/src python3 github_bot/src/github_runner.py --mode=review --dry-run python3 github_bot/src/github_runner.py --mode=triage --dry-run From 5eeca8498b54704e11cd99e0a62c61e04d7fc959 Mon Sep 17 00:00:00 2001 From: samson910022 Date: Thu, 10 Sep 2026 13:54:59 +0800 Subject: [PATCH 2/2] docs(config): fix Node floor, document MANAGE_BACKEND, dedup asRecord import - README + development: Node 18+ -> >=22.19 to match engines floor - configuration.md: canonical tool-switch header, MANAGE_BACKEND row with dual-entry note, sync inline example with config.json.example - .env.example: document OPENCODE_SERVER_URL override - proxy.ts: correct shared-verifier comment (two instances, copied keys) - grounding.ts: reuse shared asRecord from utils/guards (no behavior change) --- .env.example | 1 + README.md | 2 +- README.zh-CN.md | 2 +- docs/configuration.md | 16 ++++++++++++++-- docs/development.md | 2 +- src/proxy.ts | 5 ++++- src/search/grounding.ts | 6 +----- 7 files changed, 23 insertions(+), 11 deletions(-) diff --git a/.env.example b/.env.example index f93f491..60a7cdb 100644 --- a/.env.example +++ b/.env.example @@ -29,6 +29,7 @@ OPENCODE_PROXY_CLEANUP_MAX_AGE_MS=86400000 # Optional overrides # OPENCODE_PROXY_PORT=10000 # OPENCODE_SERVER_PORT=10001 +# OPENCODE_SERVER_URL=http://127.0.0.1:10001 # BIND_HOST=0.0.0.0 # OPENCODE_PROXY_BIND_HOST=0.0.0.0 # Canonical tool switch (legacy DISABLE_TOOLS also read; canonical wins) diff --git a/README.md b/README.md index 9347e5d..9fedb6f 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

Version License - Node + Node

> **Language:** [English](./README.md) | [简体中文](./README.zh-CN.md) diff --git a/README.zh-CN.md b/README.zh-CN.md index db16ec2..347b278 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -3,7 +3,7 @@

Version License - Node + Node

> **語言:** [English](./README.md) | [简体中文](./README.zh-CN.md) diff --git a/docs/configuration.md b/docs/configuration.md index 14e894a..097bbc5 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -30,7 +30,7 @@ | 变量 | 默认值 | 说明 | |:-----|:-------|:-----| -| `DISABLE_TOOLS` | `true` | 禁用 OpenCode 工具调用(兼容别名;`OPENCODE_DISABLE_TOOLS` 优先,二者无效值都会让位给下一顺位:canonical env > legacy env > `config.json` > 默认) | +| `OPENCODE_DISABLE_TOOLS` / `DISABLE_TOOLS` | `true` | 禁用 OpenCode 工具调用(兼容别名;`OPENCODE_DISABLE_TOOLS` 优先,二者无效值都会让位给下一顺位:canonical env > legacy env > `config.json` > 默认) | | `OPENCODE_EXTERNAL_TOOLS_MODE` | `proxy-bridge` | 外部工具桥接模式;当前仅支持 `proxy-bridge` | | `OPENCODE_EXTERNAL_TOOLS_CONFLICT_POLICY` | `namespace` | 外部工具冲突隔离策略;当前仅支持 `namespace` | | `OPENCODE_INTERNAL_WEB_FETCH_ENABLED` | `false` | 兼容旧开关;未显式配置 allowlist 时,启用后默认放行 `web_fetch` | @@ -72,6 +72,7 @@ | 变量 | 默认值 | 说明 | |:-----|:-------|:-----| | `OPENCODE_PROXY_DEBUG` | `false` | 开启调试日志(`config.json` 中用短键 `DEBUG`) | +| `OPENCODE_PROXY_MANAGE_BACKEND` | `false` | 是否由代理拉起本地后端(`config.json` 中用短键 `MANAGE_BACKEND`;prod/`index.ts` 默认 `false`,library/`buildProxyConfig` 默认 `true`——已知双入口差异) | | `OPENCODE_PATH` | `opencode` | OpenCode 可执行文件路径 | | `OPENCODE_ZEN_API_KEY` | - | Zen API Key 透传 | @@ -92,6 +93,10 @@ "INTERNAL_ALLOWED_TOOLS": ["web_fetch"], "INTERNAL_TOOL_METRICS_ENABLED": true, "INTERNAL_TOOL_DISCOVERY_FIXTURE": [], + "HEALTH_DETAILS_ENABLED": true, + "HEALTH_DETAILS_REQUIRE_AUTH": true, + "METRICS_ENABLED": false, + "METRICS_REQUIRE_AUTH": true, "USE_ISOLATED_HOME": false, "PROMPT_MODE": "standard", "OMIT_SYSTEM_PROMPT": false, @@ -100,9 +105,16 @@ "CLEANUP_MAX_AGE_MS": 86400000, "DEBUG": false, "OPENCODE_SERVER_URL": "http://127.0.0.1:10001", + "OPENCODE_SERVER_PASSWORD": "", "OPENCODE_PATH": "opencode", + "ZEN_API_KEY": "", + "MANAGE_BACKEND": false, "REQUEST_TIMEOUT_MS": 180000, - "RETRY_MAX_RETRIES": 3 + "RETRY_MAX_RETRIES": 3, + "UPSTREAM_PROXIES": [], + "UPSTREAM_PROXY_STRATEGY": "failover-rr", + "UPSTREAM_PROXY_COOLDOWN_MS": 300000, + "UPSTREAM_PROXY_NO_PROXY": ["localhost", "127.0.0.1", "::1"] } ``` diff --git a/docs/development.md b/docs/development.md index aae0254..c4e36f4 100644 --- a/docs/development.md +++ b/docs/development.md @@ -11,7 +11,7 @@ ### Node.js 环境 ```bash -# Node.js 18+ +# Node.js >=22.19 (engines floor; CI uses 24) node --version # npm diff --git a/src/proxy.ts b/src/proxy.ts index 990d94f..e383fc1 100644 --- a/src/proxy.ts +++ b/src/proxy.ts @@ -100,7 +100,10 @@ export function createApp(config: ProxyConfig): CreateAppResult { const client = rawClient as unknown as ProxyClient; // Multi-key auth (A): legacy single + list merge; empty = no auth (unchanged). - // Single shared verifier instance (also exposed via ctx for system routes). + // Two verifier instances read the same effective key content (middleware + // here, system routes via ctx.API_KEYS); each copies at construction + // (spread in system routes, filter in keys), so keep the inputs in sync + // instead of assuming a shared reference. const effectiveApiKeys: string[] = buildEffectiveApiKeys(API_KEY, API_KEYS); const apiKeyVerifier = createApiKeyVerifier(effectiveApiKeys); diff --git a/src/search/grounding.ts b/src/search/grounding.ts index 333fd8a..56940c9 100644 --- a/src/search/grounding.ts +++ b/src/search/grounding.ts @@ -3,6 +3,7 @@ // Maps OpenAI-style hosted search tools (`tools:[{type:web_search}]`) onto the // opencode built-in `websearch` tool and rebuilds `web_search_call` output // items + `url_citation` annotations from the backend tool parts. +import { asRecord } from '../utils/guards.js'; export const HOSTED_SEARCH_TOOL_TYPES = ['web_search', 'web_search_preview', 'google_search']; /** True for hosted search tool types, incl. versioned variants (e.g. Anthropic `web_search_20260222`). */ @@ -18,11 +19,6 @@ export const SEARCH_GROUNDING_INSTRUCTION = 'only from the conversation plus the search results. ' + 'Include the source URLs you relied on verbatim in your answer so they can be cited.'; -function asRecord(value: unknown): Record { - if (value && typeof value === 'object' && !Array.isArray(value)) return value as Record; - return {}; -} - function toolTypeOf(def: unknown): string { return typeof asRecord(def)['type'] === 'string' ? String(asRecord(def)['type']) : ''; }