@koreanhole/opencodex 2.95.2 → 2.95.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,484 @@
1
+ <p align="center">
2
+ <img src="../assets/banner.png" alt="opencodex — 連接 Codex、Claude Code、Claude Desktop、Grok Build 等工具的本機閘道" width="100%">
3
+ </p>
4
+
5
+ <h3 align="center">一個本機閘道,連接你的 AI 程式開發工具與模型。</h3>
6
+ <p align="center"><b>在 Codex、Claude Code、Claude Desktop 和 Grok Build 中使用你選擇的模型,<br>並透過受管理的設定連接 OpenCode、Pi、Qoder、WorkBuddy、Kilo、Cline、T3 Code 等工具。</b><br>
7
+ <a href="https://opencodex.me/zh-tw/reference/client-support/">查看所有支援的工具 →</a></p>
8
+
9
+ <p align="center">
10
+ <a href="https://x.com/claudeebum"><img src="https://img.shields.io/badge/%40claudeebum-000000?logo=x&logoColor=white" alt="在 X 上關注 @claudeebum"></a>
11
+ <a href="https://www.npmjs.com/package/@koreanhole/opencodex"><img src="https://img.shields.io/npm/v/@koreanhole/opencodex?color=cb3837&label=npm&logo=npm" alt="npm 版本"></a>
12
+ <a href="https://github.com/koreanhole/opencodex-cli/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@koreanhole/opencodex?color=blue" alt="授權"></a>
13
+ <img src="https://img.shields.io/node/v/@koreanhole/opencodex?logo=node.js&label=node" alt="Node 版本">
14
+ </p>
15
+
16
+ ```bash
17
+ npm install -g @koreanhole/opencodex
18
+ ocx start
19
+ ```
20
+
21
+ <p align="center">
22
+ <a href="https://github.com/lidge-jun/opencodex/releases/latest"><img src="https://img.shields.io/badge/macOS-.dmg-24292f?logo=apple&logoColor=white" alt="下載 macOS 版 (.dmg)"></a>
23
+ <a href="https://github.com/lidge-jun/opencodex/releases/latest"><img src="https://img.shields.io/badge/Windows-.msi-24292f?logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiPjxwYXRoIGQ9Ik0zIDNoOC41djguNUgzem05LjUgMEgyMXY4LjVoLTguNXpNMyAxMi41aDguNVYyMUgzem05LjUgMEgyMVYyMWgtOC41eiIvPjwvc3ZnPg==" alt="下載 Windows 版 (.msi)"></a>
24
+ <a href="https://github.com/lidge-jun/opencodex/releases/latest"><img src="https://img.shields.io/badge/Linux-.AppImage-24292f?logo=linux&logoColor=white" alt="下載 Linux 版 (.AppImage)"></a>
25
+ <a href="https://github.com/lidge-jun/opencodex/releases/latest"><img src="https://img.shields.io/badge/Linux-.deb-24292f?logo=debian&logoColor=white" alt="下載 Linux 版 (.deb)"></a>
26
+ </p>
27
+
28
+ <table>
29
+ <tr>
30
+ <td width="50%" valign="middle">
31
+
32
+ ### Claude Code,執行任意模型
33
+
34
+ 選擇器還是 Claude Code 原本的,換掉的只是背後的大腦。
35
+
36
+ </td>
37
+ <td width="50%">
38
+ <img src="../assets/claude-code-models.gif" alt="透過 opencodex 執行路由模型的 Claude Code——狀態列顯示 gpt-5.6-luna-medium 為目前模型" width="100%">
39
+ </td>
40
+ </tr>
41
+ <tr>
42
+ <td width="50%" valign="middle">
43
+
44
+ ### Codex,執行任意模型
45
+
46
+ 選好供應商就能開始——同樣的工作流程,換顆大腦。
47
+
48
+ </td>
49
+ <td width="50%">
50
+ <img src="../assets/demo.gif" alt="opencodex 示範——在 Codex 應用中用路由的非 OpenAI 模型執行任務" width="100%">
51
+ </td>
52
+ </tr>
53
+ <tr>
54
+ <td width="50%" valign="middle">
55
+
56
+ ### Claude Desktop,執行任意模型
57
+
58
+ Opus 先回答,再把任務交給 GPT-5.6 Sol 子代理。
59
+
60
+ </td>
61
+ <td width="50%">
62
+ <img src="../assets/claude-desktop-subagent.gif" alt="Claude Desktop 以 Claude Opus 4.8 回答,再透過 opencodex 派發 GPT-5.6 Sol 子代理" width="100%">
63
+ </td>
64
+ </tr>
65
+ <tr>
66
+ <td width="50%" valign="middle">
67
+
68
+ ### Grok Build,執行任意模型
69
+
70
+ Sol 主導會話,並呼叫 Kimi K3 子代理。
71
+
72
+ </td>
73
+ <td width="50%">
74
+ <img src="../assets/grok-build-subagent.gif" alt="Grok Build 透過 opencodex 執行 GPT-5.6 Sol,並呼叫 Kimi K3 子代理" width="100%">
75
+ </td>
76
+ </tr>
77
+ </table>
78
+
79
+ <p align="center">
80
+ <a href="../README.md">English</a> · <a href="README.fr.md">Français</a> · <a href="README.ko.md">한국어</a> · <a href="README.zh-CN.md">简体中文</a> · <b>繁體中文</b> · <a href="README.ru.md">Русский</a> · <a href="README.ja.md">日本語</a> · <a href="README.tr.md">Türkçe</a> · 📖 <a href="https://opencodex.me/zh-tw/"><b>完整文件 →</b></a>
81
+ </p>
82
+
83
+ opencodex 是連接程式開發工具與模型供應商的輕量級本機閘道。它接收 Responses、Chat Completions 和 Anthropic Messages API 請求,並轉換成供應商使用的協定;在用戶端、模型和供應商支援的情況下,傳遞串流、工具呼叫、推理和影像。你可以在 Codex、Claude Code、Claude Desktop、Grok Build 及[用戶端支援頁面](https://opencodex.me/zh-tw/reference/client-support/)列出的工具中使用 Claude、Gemini、Grok、GLM、DeepSeek、Kimi、Qwen、Ollama 等供應商。它也能管理 Codex 驗證用的 **ChatGPT 帳號池**:新增帳號並在儀表板重新整理配額,新工作階段會自動路由至用量最低的健康帳號,既有對話則保持綁定原始帳號。
84
+
85
+ ## 快速開始
86
+
87
+ ### 個人安裝(CLI)
88
+
89
+ ```bash
90
+ npm install -g @koreanhole/opencodex # Node 18+;Bun 執行環境會自動打包
91
+ ocx start # 代理 + 儀表板位於 localhost:10100
92
+ ```
93
+
94
+ 用 `ocx service` 在背景執行。
95
+
96
+ 開啟 **http://localhost:10100**,在網頁儀表板完成所有設定——新增供應商
97
+ (40+ 內建,或任何 OpenAI 相容端點)、挑選模型、管理帳號。隨時可用 `ocx gui`
98
+ 重新開啟儀表板。
99
+
100
+ ### 連接你的工具
101
+
102
+ 連接你正在使用的工具:
103
+
104
+ | 工具 | 連接方式 |
105
+ |---|---|
106
+ | Codex | 開啟儀表板 **Connect** 頁面的 Codex 開關,然後照常執行 `codex`。在本機監聽時,這會讓 Codex 內建供應商指向代理。使用終端機時,請在儀表板新增供應商之前執行 `ocx init` 並接受其 Codex 提示。 |
107
+ | Claude Code | 安裝 `claude` CLI 後執行 `ocx claude`。它會在需要時啟動代理,並透過代理啟動 Claude Code。 |
108
+ | Claude Desktop | 執行 `ocx claude desktop`。全新安裝時會為整個應用程式設定閘道設定檔;既有的 first-party 設定會保留,可執行 `ocx claude desktop apply --gateway` 明確切換。詳見 [Claude Code 指南](https://opencodex.me/zh-tw/guides/claude-code/)。 切換後請完全結束並重新開啟 Claude Desktop。 |
109
+ | Grok Build | 在本機監聽且啟用 Grok 整合時,若 `~/.grok` 存在,`ocx start` 會註冊模型;在 Grok Build 中選擇 `ocx-*` 模型。遠端設定請參見 [Grok Build 指南](https://opencodex.me/zh-tw/guides/grok-build/)。新增供應商後,重新啟動代理(或在啟用 Codex 自動啟動時執行 `ocx ensure`)以更新清單。 |
110
+ | 具備受管理整合的工具 | 使用儀表板的 **Connect** 頁面,或執行 `ocx integration client enable --client <id>`。 |
111
+ | 其他工具 | 將自訂 OpenAI 相容基本 URL 設為 `http://localhost:10100/v1`,或將 Anthropic 基本 URL 設為 `http://localhost:10100`。 |
112
+
113
+ [用戶端支援頁面](https://opencodex.me/zh-tw/reference/client-support/)列出各工具的連接方式與使用的協定。
114
+
115
+ <details>
116
+ <summary><b>桌面應用程式(Beta)</b></summary>
117
+
118
+ 桌面應用程式是同一套代理與儀表板的原生視窗版本,附系統匣與內建的 `ocx`。
119
+ 它會接上已在執行的代理,或啟動內建的那一個;儀表板仍使用代理的連接埠
120
+ (除非你設定了其他連接埠,否則為 **http://localhost:10100**)。請從
121
+ [最新發行版](https://github.com/lidge-jun/opencodex/releases/latest)挑選適合你平台的檔案:
122
+
123
+ | 平台 | 檔案 | 說明 |
124
+ |---|---|---|
125
+ | macOS 13+(Apple Silicon 與 Intel) | `OpenCodex-<version>-macos.dmg` | 通用建置,以 Developer ID 簽章並經過公證 |
126
+ | Windows(x64) | `OpenCodex-<version>-windows-x64.msi` | 正透過 SignPath Foundation 推出程式碼簽章([程式碼簽章政策](https://opencodex.me/zh-tw/reference/code-signing/));在版本簽章之前,SmartScreen 會詢問一次,選擇 **More info → Run anyway** |
127
+ | Linux(x86_64) | `OpenCodex-<version>-linux-x86_64.AppImage` 或 `-linux-amd64.deb` | 系統匣需要支援 AppIndicator 的桌面環境 |
128
+
129
+ 每個檔案在發行頁面上都附有 `.sha256`。在 macOS 14+ 上,應用程式還附帶
130
+ WidgetKit 擴充套件,可顯示代理狀態、今日用量與供應商配額;它所呈現的快照模型位於
131
+ [`app/`](../app)(`MenuBarCore`)。若要自行建置應用程式,先在儲存庫根目錄執行
132
+ `bun install && bun run build:gui`,再於
133
+ `desktop/` 執行:macOS 上用 `bun install && bun run prepare-sidecar && bun run prepare-widget && bun run build:local`,Windows 與 Linux 上用 `bun install && bun run prepare-sidecar && bun run build:local`(小工具步驟只能在 macOS 上執行)。
134
+ [桌面應用程式指南](https://opencodex.me/zh-tw/guides/desktop-app/) 與
135
+ [macOS 選單列應用程式指南](https://opencodex.me/zh-tw/guides/macos-menu-bar/) 涵蓋首次啟動,
136
+ [`AGENTS_INSTALL.md`](../AGENTS_INSTALL.md#where-things-are-installed) 列出所有寫入磁碟的內容。
137
+
138
+ </details>
139
+
140
+ ### ChatGPT 帳號池
141
+
142
+ opencodex 也能為 Codex 認證管理 **ChatGPT 帳號池**。新增多個 ChatGPT / Codex 帳號,
143
+ 在儀表板重新整理 5 小時/每週/30 天配額。在配額路由下,新會話可使用
144
+ 使用量最低的健康帳號;round-robin 與 fill-first 則各自套用自己的策略。既有 Codex
145
+ 執行緒通常會維持對啟動帳號的親和性,因此長時間的 SSH、tmux 或
146
+ 行動裝置連線的會話不會在對話中途跳帳號——但配額重新評估、failover、
147
+ 帳號排除、親和性到期,或 401/403 與 429 復原,仍可能重新綁定。當其中一個帳號——通常是你的 Codex Desktop 登入——只應在其他帳號用盡後才被用到時,請為帳號設定選取順序。
148
+
149
+ ### 贊助
150
+
151
+ 贊助讓 opencodex 能跟上每一次上游協議變更。有興趣?
152
+ 見 [SPONSORS.md](../SPONSORS.md)。
153
+
154
+ <!-- sponsors:main — one banner, model developers only; empty until a Main sponsor signs -->
155
+
156
+ <!-- sponsors:standard — one row per sponsor, in order of signing -->
157
+ <table>
158
+ <tbody>
159
+ <tr>
160
+ <td width="180"><a href="https://www.orcarouter.ai/?utm_source=opencodex&utm_medium=readme"><img src="../assets/sponsors/orcarouter.png" alt="OrcaRouter" width="150"></a></td>
161
+ <td>感謝 <a href="https://www.orcarouter.ai/?utm_source=opencodex&utm_medium=readme">OrcaRouter</a> 贊助本專案!OrcaRouter 是面向正式環境的 OpenAI 相容 AI 閘道:自適應路由會為每則提示評分,送到達到你門檻的模型;自動 failover;路由規則即程式碼;供應商原價零加價並含 prompt 快取;每次呼叫都有 guardrail、agent 防火牆與請求日誌,涵蓋 200+ 模型。在「新增供應商」選擇器選 <code>OrcaRouter</code>,或執行 <code>ocx provider add orcarouter</code>;<code>orcarouter/auto</code> 就是自適應路由器。</td>
162
+ </tr>
163
+ <tr>
164
+ <td width="180"><a href="https://tokenlab.sh/r/OPENCODEX"><picture><source media="(prefers-color-scheme: dark)" srcset="../assets/sponsors/tokenlab-dark.png"><img src="../assets/sponsors/tokenlab-light.png" alt="TokenLab" width="150"></picture></a></td>
165
+ <td>感謝 <a href="https://tokenlab.sh/r/OPENCODEX">TokenLab</a> 贊助本專案!TokenLab 為程式設計智慧體提供統一的多模型 API,一把 API Key 即可接入主流模型,支援 OpenAI Responses、Chat Completions、Anthropic Messages 和 Gemini 原生 API 格式,以及串流輸出和工具呼叫。同時提供 MCP 伺服器和 Agent Skills,方便接入現有工作流程;交付模式可選,按量付費。在「新增供應商」選擇器選 <code>TokenLab</code>,或執行 <code>ocx provider add tokenlab</code>。</td>
166
+ </tr>
167
+ </tbody>
168
+ </table>
169
+
170
+ ---
171
+
172
+ <details>
173
+ <summary>Docker Compose</summary>
174
+
175
+ 本儲存庫提供 digest 釘選、非 root 的 Compose 建置。建置會根據選定的 Git 快照自行產生並驗證
176
+ 權威相容性清單。本機 clone 需要 Git 與 Docker Compose;遠端 Git context 需要 Docker Compose。
177
+ 兩種方式都不需要主機上的 Bun,也不需要準備步驟。透過 stdin 初始化一次資料平面權杖並啟動 hub:
178
+
179
+ ```bash
180
+ git clone https://github.com/lidge-jun/opencodex.git
181
+ cd opencodex
182
+ docker compose build
183
+ openssl rand -hex 32 | docker compose run --rm -T hub bun run docker/bootstrap-token.ts
184
+ docker compose up -d
185
+ curl --fail --silent http://127.0.0.1:10100/healthz
186
+ curl --fail --silent http://127.0.0.1:10100/readyz
187
+ ```
188
+
189
+ 預設主機綁定為 `127.0.0.1:10100`。遠端公開必須明確指定
190
+ `OPENCODEX_BIND_ADDRESS=<LAN-or-Tailscale-IP> docker compose up -d`;`0.0.0.0` 會加入
191
+ 所有主機介面。請用防火牆與已認證的 TLS/tailnet 前端限制存取。
192
+ 產生的 JSON 不會被追蹤。建置 context 只會納入 `.git/index` 與 `.git/HEAD`,也就是
193
+ `git ls-files` 讀取的清單;大小約為 1 MB,而不是完整的 object store。這些檔案只能透過唯讀 mount
194
+ 在建置專用的 manifest 階段看到,因此沒有任何 `COPY` 會包含 `.git`。主機上已有的 manifest 只有在
195
+ 通過驗證後才會接受;否則建置會自行產生。建置會拒絕過期清單、缺少或不相符的檔案、多餘原始碼檔案,以及符號連結。
196
+ 它會核對建置上下文與複製進去的執行檔案上每一筆記錄的 SHA-256,包括
197
+ `package.json`、`bun.lock`,以及特別納入的 `scripts/model-metadata.source.json`。
198
+
199
+ 遠端 Git context 需要 BuildKit 保留 Git metadata。以下 Compose 建置片段會選擇遠端快照,
200
+ 並傳入所需的內建參數:
201
+
202
+ ```yaml
203
+ services:
204
+ hub:
205
+ pull_policy: build
206
+ build:
207
+ context: https://github.com/lidge-jun/opencodex.git#main
208
+ dockerfile: Dockerfile
209
+ target: runtime
210
+ args:
211
+ BUILDKIT_CONTEXT_KEEP_GIT_DIR: "1"
212
+ ```
213
+
214
+ 權杖與可變狀態留在名為 `ocx-state` 的 volume;映像、Compose 檔、環境變數或 shell 引數都不會放入憑證。見
215
+ [Remote Hub 部署指南](https://opencodex.me/zh-tw/guides/remote-hub/) 以了解供應商
216
+ 設定、已認證的驗收檢查、遠端管理與還原。
217
+
218
+ </details>
219
+
220
+ <details>
221
+ <summary>從原始碼安裝(最新 dev)</summary>
222
+
223
+ **macOS / Linux:**
224
+
225
+ ```bash
226
+ curl -fsSL https://bun.sh/install | bash
227
+ git clone -b dev https://github.com/lidge-jun/opencodex.git
228
+ cd opencodex && ~/.bun/bin/bun install
229
+ ~/.bun/bin/bun run build:gui
230
+ ~/.bun/bin/bun run src/cli/index.ts start
231
+ ```
232
+
233
+ **Windows (PowerShell):**
234
+
235
+ ```powershell
236
+ irm bun.sh/install.ps1 | iex
237
+ git clone -b dev https://github.com/lidge-jun/opencodex.git
238
+ cd opencodex; bun install
239
+ bun run build:gui
240
+ bun run src/cli/index.ts start
241
+ ```
242
+
243
+ 從原始碼安裝會跑最新的 `dev` 分支。記憶體所有權
244
+ 修補、執行環境 GC 改善,以及尚未發布的修正,都會比 npm 套件更早在這裡出現。
245
+
246
+ </details>
247
+
248
+ <details>
249
+ <summary>給 agent 使用</summary>
250
+
251
+ ```bash
252
+ npm install -g @koreanhole/opencodex
253
+ ocx start # 或 `ocx service`
254
+ ocx init # 互動式設定:寫入 ~/.opencodex/config.json 並接上 Codex
255
+ ```
256
+
257
+ `ocx init` 永遠不會啟動代理;請先啟動(或之後再啟動——順序都可以,但像
258
+ `ocx provider add` 與 `ocx combo set` 這類無介面命令會跟**正在執行**的代理通訊,連不上就以非零結束碼結束)。`ocx status` / `ocx doctor` / `ocx health` 回報執行狀態。
259
+
260
+ > **正在安裝或執行 opencodex 的 agent:** 請讀
261
+ > [`AGENTS_INSTALL.md`](../AGENTS_INSTALL.md)。互動式 `ocx start` 可能會問一次要不要
262
+ > 為此儲存庫按星——那是使用者的決定,絕不是 agent 的。CLI 會在 agent 驅動的執行中隱藏該
263
+ > 提示,API 則以 `403 agent_consent_required` 拒絕。
264
+
265
+ </details>
266
+
267
+ ## 支援平台
268
+
269
+ | 作業系統 | 狀態 | 服務管理員 | 桌面應用程式(Beta) |
270
+ |---|---|---|---|
271
+ | macOS (arm64 / x64) | 完整支援 | launchd | 通用 `.dmg` |
272
+ | Linux (x64 / arm64) | 完整支援 | systemd(使用者單元) | x86_64 `.AppImage` / `.deb` |
273
+ | Windows (x64) | 完整支援 | Task Scheduler(隱藏)/可選原生服務(`--native`、WinSW) | x64 `.msi` |
274
+
275
+ CLI 安裝需要 [Node](https://nodejs.org) 18+;桌面應用程式則不需要 Node 或 Bun。Bun 執行環境在 `npm install` 時一併打包——不必另外安裝
276
+ Bun,Windows 也不需要 WSL。若 npm 攔截了打包執行環境的安裝腳本,
277
+ 見[安裝文件](https://opencodex.me/zh-tw/getting-started/installation/)。
278
+
279
+ ## 亮點
280
+
281
+ - **在 Codex、Claude Code、Claude Desktop 與 Grok Build 使用任何 LLM** — 開箱即用 40+ 供應商,
282
+ 各自保留原生 UI。
283
+ - **沿用本機 CLI 登入** —— `cline-cli/default` 與 `gemini-cli/default` 委派給已安裝且已登入的 CLI,工具核准與執行仍由 Codex 負責。
284
+ - **池化 ChatGPT 帳號** — 執行緒親和性、依配額自動切換、冷卻與
285
+ fail-closed 認證處理。
286
+
287
+ > **供應商政策說明:** 帳號池只用來做路由與營運韌性;它不保證
288
+ > 能避開供應商的速率限制、執法、停權或其他帳號
289
+ > 處置。OpenCodex 不贊成用額外帳號規避供應商限制,也不贊成
290
+ > 在人與人之間共用帳號憑證。你有責任遵守各
291
+ > 供應商的現行條款。見
292
+ > [Codex Auth 帳號池指南](https://opencodex.me/zh-tw/guides/web-dashboard/)
293
+ > 與 [OpenAI 現行使用條款](https://openai.com/policies/terms-of-use/)。
294
+ - **Combo** — 一個虛擬模型 id,可在供應商之間 failover 或加權 round-robin。見
295
+ [combo 指南](https://opencodex.me/zh-tw/guides/combos/)。
296
+ - **任何模型上的子代理** — 讓路由模型出現在 Codex 的子代理選擇器,含 v1/v2
297
+ 介面控制與 fallback 鏈。見
298
+ [子代理指南](https://opencodex.me/zh-tw/guides/sub-agent-surface/)。
299
+ <!-- sponsors:main-first-mention -->
300
+ - **登入一次,不必填 API key** — xAI、Anthropic、Kimi 支援 OAuth;也可轉發
301
+ `codex login`、貼上金鑰,或使用 `${ENV_VAR}` 引用。
302
+ - **網頁搜尋與視覺 sidecar** — 非 OpenAI 模型可透過掛在你 ChatGPT 登入上的 sidecar,獲得真正的網頁搜尋與圖片理解。
303
+ - **看清正在發生什麼** — 儀表板顯示供應商、OAuth 狀態、模型選擇,以及含快取 token 計數的即時請求日誌。
304
+ - **乾淨退出,零殘留** — `ocx stop` 把 Codex 還原成原始設定。
305
+ - **有界記憶體所有權** — 每個長生命週期的快取、環形緩衝區與協議翻譯
306
+ 儲存都有有限上限、位元組預算或主動調和。設定重新載入後,不會留下無界的 `Map` 或 `Set`。
307
+
308
+ <details>
309
+ <summary>記憶體所有權細節</summary>
310
+
311
+ OpenCodex 在下列類別中追蹤行程保留狀態。每一類都有文件化的上限:
312
+
313
+ - **14 個保留儲存**(請求日誌、除錯環形緩衝、圖片快取、模型快取、視覺
314
+ 描述、cursor blob、responses 延續等)以位元組計帳,並由
315
+ 應用程式自己的記憶體預算淘汰(預設 256 MiB);其中 native control replay
316
+ 儲存為固定,不會被淘汰。
317
+ - **4 個觀測緩衝區**(翻譯累加器、image/OAuth/Grok 尾端)會
318
+ 監控進行中的位元組壓力,但不淘汰。
319
+ - **31 個狀態儲存註冊**負責到期清掃(間隔 60 秒)與
320
+ 設定世代調和,以移除過期的供應商/帳號鍵。
321
+ - **路徑與指紋 memo**(工作區中繼資料、強化身分、安裝
322
+ salt、mode-hint 能力)使用插入順序 LRU 上限(8–128 筆)。
323
+ - **模型快取世代 tombstone** 在調和後刪除;全域
324
+ 世代遞增可避免過期、進行中的探索把已移除的供應商填回來。
325
+ - **Lab event-id 去重**在磁碟帳本鎖下執行,行程層級沒有
326
+ RAM 索引。
327
+
328
+ 執行 `GET /api/system/memory`(帶管理權杖)可檢視目前保留的位元組、
329
+ 淘汰計數與 watchdog 樣本。
330
+
331
+ </details>
332
+
333
+ ## 模型路由
334
+
335
+ 用 `provider/model` 語法指定任何已設定的供應商與模型:
336
+
337
+ ```bash
338
+ codex -m "anthropic/claude-opus-5" "解釋這個 stack trace"
339
+ codex -m "google/gemini-3-pro" "為 auth.ts 寫單元測試"
340
+ codex -m "ollama/llama3" "重構這個 function"
341
+ ```
342
+
343
+ 省略 `provider/` 字首時,會使用預設供應商,或依模型名模式自動匹配。
344
+ 供應商模型 id 若含 `/`,對外會把內部斜線別名成 `-`;原始
345
+ 全斜線形式同樣可用。細節:[模型路由文件](https://opencodex.me/zh-tw/guides/model-routing/)。
346
+
347
+ ### JEV Auto 路由(選用)
348
+
349
+ TypeSafe JEV 可以為明確啟用的 Combo 選擇第一個模型與推理強度,一般模型選擇器與所有直接路由保持不變。
350
+ 透過 `ocx login jev`、**Providers → TypeSafe JEV → Add API key** 或 `TYPESAFE_API_KEY`/`JEV_API_KEY`
351
+ 加入憑證。接著開啟 **Models → Combos → Create JEV Auto**,選擇允許的目標模型,並為每個目標勾選
352
+ JEV 可選的推理強度。未變更強度設定的目標會允許該模型目前宣告的所有強度。
353
+
354
+ JEV 只用於 `jev-auto`,且每次邏輯模型呼叫只諮詢一次。缺少憑證、網路失敗或決策無效時,會 fail-open
355
+ 到目前第一個可用目標;呼叫端取消仍會取消請求。自動化測試使用模擬的 TypeSafe 端點,
356
+ 不驗證真實的 JEV 帳戶。
357
+
358
+ JEV Combo 也可以改用自架的決策模型,例如無需金鑰的 Ollama `tev1`:新增一個 `baseUrl` 為完整
359
+ `/v1/systemone` 端點的 `jev-decision` 供應商,並將其設為 Combo 的 `decisionProvider`。TypeSafe 憑證
360
+ 絕不會傳送到該端點。詳見[自架決策模型](https://opencodex.me/zh-tw/guides/combos/)。
361
+
362
+ ## 供應商與 adapter
363
+
364
+ <!-- sponsors:main-first-mention -->
365
+ OpenAI(ChatGPT 登入或 API key)、Anthropic、Google Gemini、xAI、Kimi、Azure OpenAI、Ollama
366
+ (本機 + Cloud)、Cursor(實驗性),以及所有 OpenAI 相容端點——再加上 DeepSeek、
367
+ Groq、OpenRouter、OpenGateway、Together、Fireworks、Cerebras、Mistral、Hugging Face、NVIDIA NIM、MiniMax、
368
+ Qwen Cloud、Qoder Global 與 CN(官方 PAT + CLI)、SiliconFlow 等等。完整清單:`ocx init` 或
369
+ [供應商文件](https://opencodex.me/zh-tw/guides/providers/)。
370
+
371
+ ## CLI
372
+
373
+ ```bash
374
+ ocx init # 互動式設定(寫入設定、接上 Codex、提供 shim)
375
+ ocx start [--port 10100] [--socks5 [host:port] | --socks5-off] # SOCKS5 預設為 socks5://127.0.0.1:10808
376
+ ocx stop # 停止並還原原生 Codex
377
+ ocx service [install|repair|restart|start|stop|status|uninstall|remove] # 背景服務
378
+ ocx codex-shim install # 每次啟動 `codex` 時按需啟動代理
379
+ ocx health [--json] # 檢查代理當下是否存活
380
+ ocx ready [--json] [--wait [--timeout <seconds>]] # 檢查同步後是否就緒
381
+ ocx status # 代理是否在執行?
382
+ ocx gui # 開啟網頁儀表板
383
+ ocx provider <...> # 管理供應商(list/add/edit/test/remove)
384
+ ocx account <...> # 管理 ChatGPT 帳號與 API-key 池
385
+ ocx combo <...> # 管理 failover/round-robin combo
386
+ ocx v2 <...> # 多代理 v1/v2 介面控制
387
+ ocx update [--tag preview] # 更新 opencodex
388
+ ```
389
+
390
+ 偏好的連接埠被占用時,啟動會停止並指出占用者,而不會改用其他連接埠,因此絕不會在第一個代理旁留下另一個
391
+ 執行中的代理。請釋放該連接埠,或用 `--port` 指定其他連接埠。完整參考:[CLI 文件](https://opencodex.me/zh-tw/reference/cli/)。
392
+
393
+ ### 健康狀態與就緒
394
+
395
+ `GET /healthz` 回報代理當下是否存活。未認證的 `GET /readyz` 端點回報
396
+ 同步後就緒狀態,並附上淨化後的 JSON 身分 `{service, version, uptime, pid, port, status}`。
397
+ 當 `status` 為 `ready` 時回傳 `200`;`pending` 與終態 `failed` 回傳 `503`,並帶
398
+ `Retry-After: 1`。
399
+
400
+ `ocx ready [--json] [--wait [--timeout <seconds>]]` 預設只探測一次。`--wait` 預設最多輪詢
401
+ 45 秒,但一看到終態 `failed` 就立刻結束;
402
+ `--timeout <seconds>` 設定 1–300 秒上限,必須搭配 `--wait`,且只接受正整數。CLI `--json` 輸出為
403
+ `{ready, status, pid, port}`,其中 `status` 為 `ready`、`pending`、`failed` 或 `unreachable`。
404
+
405
+ | 結束碼 | 結果 |
406
+ | --- | --- |
407
+ | `0` | 就緒 |
408
+ | `1` | 未就緒:pending、failed、timeout 或 unreachable |
409
+ | `64` | 無效引數 |
410
+
411
+ 沒有 `/readyz` 的舊代理會 fail-closed 成 `unreachable`,結束碼為 1;`ocx health`
412
+ 仍保持相容。
413
+
414
+ ### 自動啟動:service 與 shim
415
+
416
+ 用 **service**(`ocx service`)做常駐代理,當機後會重啟。用
417
+ **shim**(`ocx codex-shim install`)做輕量、按需啟動,不必背景常駐程式。用 `ocx service uninstall` / `ocx codex-shim uninstall` 移除。
418
+
419
+ ### 解除安裝
420
+
421
+ ```bash
422
+ ocx uninstall # 停止、移除 service/shim、還原原生 Codex、清掉狀態
423
+ npm uninstall -g @koreanhole/opencodex
424
+ ```
425
+
426
+ ## 遠端存取
427
+
428
+ 預設 opencodex 綁定 `127.0.0.1`,不必額外認證。綁定超出
429
+ 迴環(`"hostname": "0.0.0.0"`)**必須**有 bearer 權杖——沒有
430
+ `OPENCODEX_API_AUTH_TOKEN` 代理會拒絕啟動,每個用戶端請求都必須以
431
+ `x-opencodex-api-key` 帶上它。細節:[設定參考](https://opencodex.me/zh-tw/reference/configuration/)。
432
+
433
+ ## 文件
434
+
435
+ 公開文件——安裝、供應商、路由、combo、子代理、sidecar、整合,以及
436
+ CLI/設定/管理 API 參考——由 [`docs-site/`](../docs-site) 建置,
437
+ 發布於 **[opencodex.me](https://opencodex.me/zh-tw/)**。
438
+
439
+ 維護者的權威筆記在 [`structure/`](../structure),貢獻者設定在
440
+ [`CONTRIBUTING.md`](../CONTRIBUTING.md),安全性回報在 [`SECURITY.md`](../SECURITY.md)。
441
+ 未公開的漏洞請透過
442
+ [GitHub 私人漏洞回報](https://github.com/lidge-jun/opencodex/security/advisories/new)
443
+ 私下回報,不要開公開 issue。
444
+ 這份表單是唯一的技術管道,沒有安全信箱。後續往來都留在這份私人回報裡;公開 issue 只能用來協調,不能放
445
+ 漏洞細節。確認收到回報不等於已經分診,也不承諾首次回應的時限。
446
+
447
+ ## 開發
448
+
449
+ 從原始碼開發需要 `PATH` 上有 `bun` CLI。已發布的 npm 套件為已安裝的 `ocx` 命令打包自己的
450
+ Bun 執行環境;套件指令碼也可能透過這個打包依賴解析 Bun。
451
+
452
+ ```bash
453
+ git clone https://github.com/lidge-jun/opencodex.git
454
+ cd opencodex
455
+ bun install
456
+ bun run typecheck
457
+ bun run test
458
+ ```
459
+
460
+ 見 **[貢獻指南](../CONTRIBUTING.md)**。
461
+
462
+ 經維護者代為帶入或重寫而落地的貢獻者工作,
463
+ 若 commit 沒有寫出原作者,會記錄在
464
+ **[CREDITS.md](../CREDITS.md)**。
465
+
466
+ ## 程式碼簽章政策 (Code signing policy)
467
+
468
+ Windows 執行檔正在改用 Authenticode 簽章([#7207](https://github.com/lidge-jun/opencodex/issues/7207))。推出進度、簽章驗證方式與完整政策請見 [Windows 程式碼簽章指南](https://opencodex.me/zh-tw/reference/code-signing/)。
469
+
470
+ Free code signing provided by [SignPath.io](https://about.signpath.io/), certificate by [SignPath Foundation](https://signpath.org/).
471
+
472
+ - Committers and reviewers: [lidge-jun](https://github.com/lidge-jun)
473
+ - Approvers: [lidge-jun](https://github.com/lidge-jun)
474
+ - Privacy: This program will not transfer any information to other networked systems unless specifically requested by the user or the person installing or operating it.
475
+
476
+ ## 免責聲明
477
+
478
+ opencodex 是獨立的社群維護專案,**與 OpenAI、Anthropic 或其他任何供應商無關,也未獲其背書。**
479
+
480
+ 部分供應商——尤其是 Anthropic(Claude)——可能會暫停或限制經第三方代理路由 API 流量的帳號。**使用風險自負(UAYOR)。** 連線供應商前,請先查其服務條款,確認是否允許代理式存取。上游供應商對帳號採取的任何處置,opencodex 維護者概不負責。
481
+
482
+ ## 授權
483
+
484
+ MIT
@@ -14,6 +14,7 @@ import {
14
14
  assertClineSelectionSafe,
15
15
  buildClineChildEnv,
16
16
  ClineSettingsError,
17
+ mergeClineDisabledTools,
17
18
  preflightClineTools,
18
19
  resolveClineProviderSettingsPath,
19
20
  stageClineTurn,
@@ -267,11 +268,26 @@ export function createClineCliAdapter(
267
268
  }
268
269
 
269
270
  const env = buildClineChildEnv(staged, sourceEnv);
270
- const preflight = await (deps.preflightTools ?? preflightClineTools)({
271
+ const preflightTools = deps.preflightTools ?? preflightClineTools;
272
+ let preflight = await preflightTools({
271
273
  binary,
272
274
  env,
273
275
  cwd: staged.workspaceDir,
274
276
  });
277
+ if (!preflight.ok && preflight.enabledTools && preflight.enabledTools.length > 0) {
278
+ try {
279
+ await mergeClineDisabledTools(staged, preflight.enabledTools.map(tool => tool.id));
280
+ } catch (error) {
281
+ await staged.cleanup();
282
+ emit(settingsError(error));
283
+ return;
284
+ }
285
+ preflight = await preflightTools({
286
+ binary,
287
+ env,
288
+ cwd: staged.workspaceDir,
289
+ });
290
+ }
275
291
  if (!preflight.ok) {
276
292
  await staged.cleanup();
277
293
  emit({
@@ -68,9 +68,15 @@ export interface ClineStagedTurn {
68
68
  cleanup: () => Promise<void>;
69
69
  }
70
70
 
71
+ export interface ClineEnabledTool {
72
+ id: string;
73
+ kind: "builtin";
74
+ }
75
+
71
76
  export interface ClineToolPreflightResult {
72
77
  ok: boolean;
73
78
  detail?: string;
79
+ enabledTools?: readonly ClineEnabledTool[];
74
80
  }
75
81
 
76
82
  export interface ClineSelection {
@@ -346,18 +352,66 @@ function runPreflightProcess(
346
352
  });
347
353
  }
348
354
 
355
+ /** Merge discovered built-in IDs into the turn's private staged disable list. */
356
+ export async function mergeClineDisabledTools(
357
+ staged: Pick<ClineStagedTurn, "globalSettingsPath">,
358
+ ids: readonly string[],
359
+ ): Promise<void> {
360
+ let parsed: unknown;
361
+ try {
362
+ parsed = JSON.parse(await readFile(staged.globalSettingsPath, "utf8"));
363
+ } catch {
364
+ throw new ClineSettingsError(
365
+ "Cline global settings are malformed; the tool preflight cannot be repaired.",
366
+ 500,
367
+ "cline_cli_setup_failed",
368
+ );
369
+ }
370
+ const settings = asRecord(parsed);
371
+ if (!settings) {
372
+ throw new ClineSettingsError(
373
+ "Cline global settings are malformed; the tool preflight cannot be repaired.",
374
+ 500,
375
+ "cline_cli_setup_failed",
376
+ );
377
+ }
378
+ const current = Array.isArray(settings.disabledTools)
379
+ ? settings.disabledTools.filter((value): value is string => typeof value === "string")
380
+ : [];
381
+ const merged = [...new Set([...current, ...ids])];
382
+ await writeFile(
383
+ staged.globalSettingsPath,
384
+ `${JSON.stringify({ ...settings, disabledTools: merged }, null, 2)}\n`,
385
+ { encoding: "utf8", mode: 0o600 },
386
+ );
387
+ }
388
+
349
389
  /** Verify the isolated Cline config advertises no executable built-in or plugin tool. */
350
390
  export function validateClineToolCatalog(parsed: unknown): ClineToolPreflightResult {
351
391
  if (!Array.isArray(parsed)) return { ok: false, detail: "Cline tool preflight returned a non-array catalog." };
392
+ const enabledTools: ClineEnabledTool[] = [];
393
+ let pluginDetail: string | undefined;
352
394
  for (const item of parsed) {
353
395
  const record = asRecord(item);
354
396
  if (!record) continue;
355
- if (record.defaultEnabled === true) {
356
- return { ok: false, detail: `Cline enabled built-in tool ${String(record.id ?? record.name ?? "unknown")}.` };
357
- }
358
- if (record.type === "plugin" && record.enabled === true) {
359
- return { ok: false, detail: `Cline enabled plugin tool ${String(record.name ?? "unknown")}.` };
397
+ if (record.type === "plugin") {
398
+ if (record.enabled === true) {
399
+ pluginDetail ??= `Cline enabled plugin tool ${String(record.name ?? "unknown")}.`;
400
+ }
401
+ continue;
360
402
  }
403
+ if (record.defaultEnabled !== true) continue;
404
+ const id = nonEmpty(record.id);
405
+ if (!id) return { ok: false, detail: "Cline enabled a built-in tool without an id." };
406
+ enabledTools.push({ id, kind: "builtin" });
407
+ }
408
+ if (pluginDetail) return { ok: false, detail: pluginDetail };
409
+ if (enabledTools.length > 0) {
410
+ return {
411
+ ok: false,
412
+ detail: `Cline enabled built-in tool ${enabledTools[0]!.id}.`,
413
+ enabledTools,
414
+ };
361
415
  }
362
416
  return { ok: true };
363
417
  }
@@ -10,7 +10,7 @@
10
10
  },
11
11
  {
12
12
  "path": "package.json",
13
- "sha256": "b60c8ba9f3ba6dbad509253691841f95d84fa4cd24ef380aeba7471ed1a48423"
13
+ "sha256": "5defa1ac2920d665f397af48488d385a55142f49dc0998e0404c1eb312e2e4fb"
14
14
  },
15
15
  {
16
16
  "path": "scripts/model-metadata.source.json",
@@ -122,11 +122,11 @@
122
122
  },
123
123
  {
124
124
  "path": "src/adapters/cli-agent/cline/adapter.ts",
125
- "sha256": "34b1c2c54834064a37f4fe698928d5581d1f0fa13c5614b7e6f8b06e5f4623f5"
125
+ "sha256": "77593a26a0956e82e07995d85ba56128f0bc7f60f2b77373d8cdff4142e998e9"
126
126
  },
127
127
  {
128
128
  "path": "src/adapters/cli-agent/cline/settings.ts",
129
- "sha256": "83b3f78351967d985c3684e1f754f3cecc466ca529320c78ba1c63dc488bbc70"
129
+ "sha256": "13287a35b87e3f68eaf0f13f0af4669c64917612012ed596d762b5d29b0be5fc"
130
130
  },
131
131
  {
132
132
  "path": "src/adapters/cli-agent/cline/stream.ts",