+ 如果你使用第三方 API 或本站中转,不想只依赖官方 ChatGPT 登录态,可以用 Codex++ 给 Codex App 开启增强插件和中转 Provider。Codex++ 是外部启动器,不改 Codex App 安装文件,而是通过 Chromium DevTools Protocol 注入增强脚本。 +
+CodexPlusPlus Provider,让 Codex App 使用第三方 API Base URL 与 API Key。/keys 创建或复制 API Key。Codex++ 管理工具,进入中转注入 / Relay 配置。https://re.94xy.cn/v1,API Key 填本站 Key,模型按可用权限填写,例如 gpt-5.4。Codex++ 或管理工具启动 Codex App,确认当前 Provider 为 CodexPlusPlus。HOST/v1。如果你的 Codex++ 版本界面明确提示只填根地址,再按界面提示填写 HOST。
+
diff --git a/frontend/public/docs/api.i18n.js b/frontend/public/docs/api.i18n.js
index 8eb78e32..dbc4efda 100644
--- a/frontend/public/docs/api.i18n.js
+++ b/frontend/public/docs/api.i18n.js
@@ -54,6 +54,7 @@
"OpenCode",
"OpenClaw",
"Hermes",
+ "如何开启 Codex 插件",
"常见问题",
],
},
@@ -225,6 +226,35 @@
descHtml:
'站内 使用密钥 页面给 Codex CLI 生成的是 ~/.codex/config.toml 与 auth.json 两个文件。以下格式与站内模板一致。',
},
+ codexplusplus: {
+ title: "如何开启 Codex 插件(Codex++)",
+ descHtml:
+ "如果你使用第三方 API 或本站中转,不想只依赖官方 ChatGPT 登录态,可以用 Codex++ 给 Codex App 开启增强插件和中转 Provider。Codex++ 是外部启动器,不改 Codex App 安装文件,而是通过 Chromium DevTools Protocol 注入增强脚本。",
+ features: {
+ title: "它能做什么",
+ items: [
+ "开启 Codex App 的插件入口、特殊插件安装、会话删除、Markdown 导出、项目移动、Timeline 等增强能力。",
+ "通过“中转注入”写入 CodexPlusPlus Provider,让 Codex App 使用第三方 API Base URL 与 API Key。",
+ "支持多个中转配置,并可在增强 Provider 与官方 ChatGPT 登录态之间切换。",
+ "独立管理用户脚本,启动 Codex 时自动注入自定义脚本。",
+ ],
+ actions: ["打开 Codex++ 仓库", "下载 Releases"],
+ },
+ setup: {
+ title: "第三方 API 开启步骤",
+ items: [
+ "先安装官方 Codex App,再从 Codex++ Releases 下载并安装对应系统版本。",
+ "进入本站 /keys 创建或复制 API Key。",
+ "打开 Codex++ 管理工具,进入中转注入 / Relay 配置。",
+ "新增一个配置:Base URL 填 https://re.94xy.cn/v1,API Key 填本站 Key,模型按可用权限填写,例如 gpt-5.4。",
+ "保存后用 Codex++ 或管理工具启动 Codex App,确认当前 Provider 为 CodexPlusPlus。",
+ ],
+ warningHtml:
+ "Codex++ README 的中转注入示例使用 OpenAI Responses 兼容地址,通常应填写 HOST/v1。如果你的 Codex++ 版本界面明确提示只填根地址,再按界面提示填写 HOST。",
+ },
+ noteHtml:
+ "如果启动后没有看到插件或 Provider,先在 Codex++ 管理工具里运行检查 / 修复,再确认 Codex App 版本更新后是否需要等待 Codex++ 适配。",
+ },
opencode: {
title: "OpenCode",
descHtml:
@@ -388,6 +418,7 @@
"OpenCode",
"OpenClaw",
"Hermes",
+ "Enable Codex Plugins",
"FAQ",
],
},
@@ -559,6 +590,35 @@
descHtml:
'The Use Key page on this site generates two files for Codex CLI: ~/.codex/config.toml and auth.json. The format below matches that template.',
},
+ codexplusplus: {
+ title: "Enable Codex Plugins (Codex++)",
+ descHtml:
+ "If you use a third-party API or this site's relay and do not want to rely only on the official ChatGPT login state, Codex++ can enable enhanced plugins and a relay provider for Codex App. Codex++ is an external launcher: it does not modify the Codex App installation, and injects enhancement scripts through Chromium DevTools Protocol.",
+ features: {
+ title: "What it does",
+ items: [
+ "Enables the Codex App plugin entry, special plugin installation, session deletion, Markdown export, project moving, Timeline, and other enhancements.",
+ "Writes a CodexPlusPlus provider through relay injection, so Codex App can use a third-party API Base URL and API key.",
+ "Supports multiple relay configs and switching between the enhanced provider and the official ChatGPT login mode.",
+ "Manages user scripts independently and injects custom scripts when Codex starts.",
+ ],
+ actions: ["Open Codex++ repo", "Download Releases"],
+ },
+ setup: {
+ title: "Third-party API setup",
+ items: [
+ "Install the official Codex App first, then download and install the matching Codex++ build from Releases.",
+ "Open /keys on this site and create or copy an API key.",
+ "Open Codex++ Manager, then go to relay injection / Relay settings.",
+ "Add a config: set Base URL to https://re.94xy.cn/v1, paste this site's API key, and choose a model you can access, such as gpt-5.4.",
+ "Save it, launch Codex App through Codex++ or the manager, and confirm the current provider is CodexPlusPlus.",
+ ],
+ warningHtml:
+ "The Codex++ README relay injection example uses an OpenAI Responses-compatible endpoint, so HOST/v1 is usually the right value. If your Codex++ version explicitly asks for only the root host, follow its UI and use HOST.",
+ },
+ noteHtml:
+ "If plugins or the provider do not appear after launch, run check / repair in Codex++ Manager first, then verify whether a Codex App update needs a matching Codex++ update.",
+ },
opencode: {
title: "OpenCode",
descHtml:
diff --git a/frontend/public/docs/api.js b/frontend/public/docs/api.js
index e276893f..f2ba9a5e 100644
--- a/frontend/public/docs/api.js
+++ b/frontend/public/docs/api.js
@@ -235,10 +235,46 @@
return value === "home_header" || value === "both" ? value : "sidebar";
}
+ function normalizeLinkOpenMode(value) {
+ return value === "external" ? "external" : "internal";
+ }
+
+ function isCustomPageMenu(item) {
+ return Boolean(item?.page_slug) || String(item?.url || "").trim().startsWith("md:");
+ }
+
+ function escapeAttr(value) {
+ return String(value || "")
+ .replace(/&/g, "&")
+ .replace(/"/g, """)
+ .replace(//g, ">");
+ }
+
+ function escapeHtml(value) {
+ return String(value || "")
+ .replace(/&/g, "&")
+ .replace(//g, ">");
+ }
+
function buildCustomMenuHref(item) {
+ if (!isCustomPageMenu(item)) {
+ const rawUrl = String(item?.url || "").trim();
+ if (rawUrl) {
+ return rawUrl;
+ }
+ }
return `/custom/${encodeURIComponent(item.id)}`;
}
+ function buildCustomMenuTargetAttrs(item) {
+ if (normalizeLinkOpenMode(item?.link_open_mode) === "external") {
+ return ' target="_blank" rel="noopener noreferrer"';
+ }
+ return "";
+ }
+
function hostCardTemplate(item) {
const text = getText();
const labels = text.hostCard?.labels || {};
@@ -323,7 +359,7 @@
const icon = item.icon_svg
? `${item.icon_svg}`
: "";
- return `${icon}${item.label || ""}`;
+ return `${icon}${escapeHtml(item.label || "")}`;
})
.join("");
}
@@ -543,6 +579,37 @@
replaceNodeContent("#gemini-cli .section-desc", text.gemini?.descHtml || "", "html");
replaceNodeContent("#codex-cli h2", text.codex?.title || "", "text");
replaceNodeContent("#codex-cli .section-desc", text.codex?.descHtml || "", "html");
+ replaceNodeContent("#codexplusplus h2", text.codexplusplus?.title || "", "text");
+ replaceNodeContent("#codexplusplus .section-desc", text.codexplusplus?.descHtml || "", "html");
+ replaceAllText(
+ "#codexplusplus .grid-2 .card h3",
+ [
+ text.codexplusplus?.features?.title || "",
+ text.codexplusplus?.setup?.title || "",
+ ],
+ );
+ replaceAllHtml(
+ "#codexplusplus .grid-2 .card:nth-child(1) .plain-list li",
+ text.codexplusplus?.features?.items || [],
+ );
+ replaceAllText(
+ "#codexplusplus .grid-2 .card:nth-child(1) .meta-row a",
+ text.codexplusplus?.features?.actions || [],
+ );
+ replaceAllHtml(
+ "#codexplusplus .grid-2 .card:nth-child(2) .plain-list li",
+ text.codexplusplus?.setup?.items || [],
+ );
+ replaceNodeContent(
+ "#codexplusplus .grid-2 .card:nth-child(2) .note",
+ text.codexplusplus?.setup?.warningHtml || "",
+ "html",
+ );
+ replaceNodeContent(
+ "#codexplusplus > .note",
+ text.codexplusplus?.noteHtml || "",
+ "html",
+ );
replaceNodeContent("#opencode h2", text.opencode?.title || "", "text");
replaceNodeContent("#opencode .section-desc", text.opencode?.descHtml || "", "html");
replaceNodeContent("#openclaw h2", text.openclaw?.title || "", "text");