From 2346f5b2bd71b9cfedbefd9caea435d264b03d65 Mon Sep 17 00:00:00 2001 From: okxlin <61420215+okxlin@users.noreply.github.com> Date: Fri, 8 May 2026 12:42:42 +0800 Subject: [PATCH] [openclaw] add opencode-workstation app --- apps/opencode-workstation/README.md | 161 ++++ apps/opencode-workstation/data.yml | 30 + apps/opencode-workstation/latest/.env.sample | 42 ++ apps/opencode-workstation/latest/data.yml | 702 ++++++++++++++++++ .../opencode-workstation/latest/data/.gitkeep | 0 .../latest/docker-compose.yml | 83 +++ .../latest/scripts/init.sh | 15 + apps/opencode-workstation/logo.png | Bin 0 -> 4768 bytes 8 files changed, 1033 insertions(+) create mode 100644 apps/opencode-workstation/README.md create mode 100644 apps/opencode-workstation/data.yml create mode 100644 apps/opencode-workstation/latest/.env.sample create mode 100644 apps/opencode-workstation/latest/data.yml create mode 100644 apps/opencode-workstation/latest/data/.gitkeep create mode 100644 apps/opencode-workstation/latest/docker-compose.yml create mode 100755 apps/opencode-workstation/latest/scripts/init.sh create mode 100644 apps/opencode-workstation/logo.png diff --git a/apps/opencode-workstation/README.md b/apps/opencode-workstation/README.md new file mode 100644 index 000000000..37908eca7 --- /dev/null +++ b/apps/opencode-workstation/README.md @@ -0,0 +1,161 @@ +# OpenCode Workstation + +## 产品介绍 + +这是一个按 1Panel v2 应用商店目录组织的 OpenCode 运行环境。容器封装了持久化存储、运行时模式切换、oh-my-opencode 自动安装等能力,可在 1Panel 上快速部署一个带 Web UI 或 ACP 接口的 OpenCode 工作节点。 + +## 主要功能 + +- **持久化存储**:工作区、配置、缓存、运行时数据分别独立挂载,容器重建不丢失 +- **双模式运行**:`serve`(Web UI)和 `acp`(agent<->agent 协议)两种模式 +- **oh-my-opencode 集成**:支持单次执行或持久化安装,配套 DCP / GPT Unlocked 插件可选 +- **多 provider 支持**:OpenAI、Anthropic、OpenRouter、Gemini 等 API Key / Base URL 均可通过表单配置 +- **Docker 套接字可选**:通过表单可配置是否挂载宿主机 Docker 套接字 + +## 访问说明 + +- Web / serve 默认端口:`http://:4096` +- ACP 默认端口:`8765` +- `serve` 模式适合通过 1Panel 反向代理后再对外提供访问 +- `acp` 端口用于 ACP transport,不适合用浏览器页面探活 + +## 环境变量 + +所有敏感信息(API Key 等)通过表单中的 `password` 字段填写,写入 `.env` 文件。容器启动后由 `entrypoint.sh` 动态注入 OpenCode 配置。 + +## 内部升级指南 + +这个镜像的升级分成两部分: + +- **OpenCode userland**:升级 `opencode-ai` 本体 +- **oh-my-opencode**:刷新插件、安装脚本和相关配置逻辑 + +### 重建容器会更新什么 + +重建容器会拉取最新镜像,但**不会保证自动升级已持久化的 OpenCode 本体**。 + +原因是容器启动时: +- `OPENCODE_BOOTSTRAP=1` 只会在 `opencode` 不存在时执行首次安装 +- 如果 `/data/opencode` 里已经有现成的 `opencode`,bootstrap 会直接跳过 +- `OMO_AUTO_INSTALL=1` 则会在每次启动时重新执行 `oh-my-opencode` 安装/刷新流程 + +所以真实效果是: +- **重建容器**:一定会更新镜像层 +- **OpenCode 本体**:已存在时默认不会自动升级 +- **oh-my-opencode**:开启自动安装时会刷新 + +### 手动升级 OpenCode userland + +如果你要升级已持久化的 OpenCode 本体,应直接在容器内执行: + +```bash +docker exec -it bash +/app/scripts/update-opencode-userland.sh +``` + +升级完成后,可检查版本文件: + +```bash +cat /data/state/oh-my-opencode-bootstrap/opencode.version +``` + +### 刷新 oh-my-opencode + +如果你希望同步最新的 `oh-my-opencode` 安装逻辑、插件注册和配置刷新,有两种方式: + +#### 方式一:重建容器 + +前提: +- `启动时自动安装 oh-my-opencode = true` + +执行: +1. 打开 1Panel → 已安装应用 → OpenCode Workstation +2. 点击 **重建** + +#### 方式二:容器内手动刷新 + +```bash +docker exec -it bash +bunx oh-my-opencode install --no-tui ... +bunx oh-my-opencode doctor +``` + +### 什么时候用哪种方式 + +- **只更新 OpenCode 本体**:执行 `/app/scripts/update-opencode-userland.sh` +- **只刷新 oh-my-opencode 行为**:重建容器,或手动重新执行 `bunx oh-my-opencode install ...` +- **安装指定版本**: + - `OpenCode Package` 主要影响首次安装,或清空 `/data/opencode` 后重新安装 + - `oh-my-opencode Package` 可配合重建容器或手动安装流程生效 +- **镜像层也要更新**:在 1Panel 里重建容器 + +### 在 1Panel 里重建容器 + +1. 1Panel 应用商店 → 已安装应用 → OpenCode Workstation → 参数/重建 +2. 按当前表单参数重新创建容器 + +### 持久化数据说明 + +容器数据按功能拆分挂载,重建容器不会丢失: +- `APP_DATA_DIR_1`(./data/workspace):工作区代码 +- `APP_DATA_DIR_2`(./data/config):OpenCode 配置 +- `APP_DATA_DIR_3`(./data/cache):npm/opencode 缓存 +- `APP_DATA_DIR_4`(./data/runtime):运行时数据 + +销毁容器时若勾选"删除数据目录"才会丢失持久化数据。 + +## 表单填写指南 + +### 必填字段 + +| 字段 | 说明 | +|---|---| +| Serve Port | Web UI 访问端口,默认 4096 | +| ACP Port | ACP 协议端口,默认 8765 | +| 时区 | 容器时区,默认 `Asia/Shanghai` | +| 工作区/配置/缓存/运行时挂载目录 | 四个数据持久化目录,默认挂载到 `./data/` 下 | +| 运行模式 | `serve`(Web UI)或 `acp`(协议模式) | + +### oh-my-opencode 选项 + +| 字段 | 说明 | +|---|---| +| Bootstrap OpenCode on Start | 首次运行此开关打开即自动安装 OpenCode 本体 | +| 启动时自动安装 oh-my-opencode | 默认开启,自动安装 oh-my-opencode 及其配套插件 | +| Install DCP Plugin | 启用 DCP(分布式代码处理)插件,默认开启 | +| Install GPT Unlocked Plugin | 启用 GPT Unlocked 插件,默认开启 | +| Claude / Gemini / Copilot Install Mode | 控制各模型 provider 的安装模式 | +| Extra Install Args | 传递给 oh-my-opencode 安装脚本的额外参数 | +| OpenCode Package | 默认为 `opencode-ai`;可改为 `opencode-ai@版本`,主要用于首次安装或重装 | +| oh-my-opencode Package | 默认为 `oh-my-opencode`;可改为 `oh-my-opencode@版本` | + +### API Key 填写 + +| 字段 | 说明 | +|---|---| +| OpenAI API Key + Base URL | 填写 OpenAI 或兼容第三方接口(vLLM、LiteLLM、Ollama 等)的 Key 与地址 | +| Anthropic / OpenRouter / Gemini | 对应 provider 的 Key 与自定义地址(若有) | +| GitHub Token | 用于 Git 操作(拉取私有仓库等) | +| Git Author / Committer | 容器内 Git 提交的作者信息 | + +### 高级选项 + +| 字段 | 说明 | +|---|---| +| OpenCode Default Model / Small Model | 覆盖 OpenCode 默认使用的模型 ID | +| OpenCode Provider ID Override | 覆盖默认 provider ID | +| OpenCode Extra Plugins | 额外注册的 OpenCode 插件(逗号分隔的 npm 包名) | +| Docker 套接字路径 | 留空等于不挂载 Docker 套接字 | + +## Introduction + +A persistent OpenCode workstation packaged as a 1Panel v2 app. Supports serve and ACP modes, oh-my-opencode auto-install, and multi-provider LLM configuration through the deployment form. + +## Features + +- Persistent volumes for workspace, config, cache, and runtime data +- Switchable serve (Web UI) and ACP (agent protocol) modes +- oh-my-opencode integration with DCP and GPT Unlocked plugins +- Multi-provider support via form fields (OpenAI, Anthropic, OpenRouter, Gemini) +- Optional Docker socket mount +- git author identity configuration diff --git a/apps/opencode-workstation/data.yml b/apps/opencode-workstation/data.yml new file mode 100644 index 000000000..e1b3989b6 --- /dev/null +++ b/apps/opencode-workstation/data.yml @@ -0,0 +1,30 @@ +name: OpenCode Workstation +tags: + - Tool +title: OpenCode Workstation – 可持久化的多智能体开发运行环境 +description: OpenCode Workstation – 可持久化的多智能体开发运行环境 +additionalProperties: + key: opencode-workstation + name: OpenCode Workstation + tags: + - Tool + shortDescZh: OpenCode Workstation – 可持久化的多智能体开发运行环境 + shortDescEn: OpenCode Workstation – persistent multi-agent dev runtime. + description: + en: OpenCode Workstation – persistent multi-agent dev runtime with oh-my-opencode bootstrap and plugin-friendly storage. + zh: OpenCode Workstation – 可持久化的多智能体开发运行环境 + zh-Hant: OpenCode Workstation – 可持久化的多智慧體開發執行環境 + ja: OpenCode Workstation – 永続化対応マルチエージェント開発ランタイム + ko: OpenCode Workstation – 영속 스토리지를 갖춘 멀티 에이전트 개발 런타임 + ru: OpenCode Workstation – постоянное рантайм-окружение для мультиагентной разработки + ms: OpenCode Workstation – persekitaran runtime berterusan untuk pembangunan multi-ejen + pt-br: OpenCode Workstation – runtime persistente para desenvolvimento multiagente + type: tool + crossVersionUpdate: true + limit: 0 + recommend: 0 + website: "https://github.com/okxlin/release-factory" + github: "https://github.com/okxlin/release-factory" + document: "https://github.com/okxlin/release-factory" + architectures: + - amd64 diff --git a/apps/opencode-workstation/latest/.env.sample b/apps/opencode-workstation/latest/.env.sample new file mode 100644 index 000000000..715e7d1af --- /dev/null +++ b/apps/opencode-workstation/latest/.env.sample @@ -0,0 +1,42 @@ +PANEL_APP_PORT_HTTP=4096 +PANEL_APP_PORT_ACP=8765 +CONTAINER_NAME=opencode-workstation +TZ=Asia/Shanghai +DOCKER_SOCK_SRC=/var/run/docker.sock +APP_DATA_DIR_1=./data/workspace +APP_DATA_DIR_2=./data/config +APP_DATA_DIR_3=./data/cache +APP_DATA_DIR_4=./data/runtime +OPENCODE_RUNTIME_MODE=serve +OPENCODE_BOOTSTRAP=1 +OMO_AUTO_INSTALL=1 +DCP_INSTALL=1 +GPT_UNLOCKED_INSTALL=1 +OMO_CLAUDE_MODE=no +OMO_GEMINI_MODE=no +OMO_COPILOT_MODE=no +OMO_INSTALL_ARGS= +OPENCODE_NPM_PACKAGE=opencode-ai +OMO_PACKAGE=oh-my-opencode +OPENAI_API_KEY= +OPENAI_BASE_URL= +OPENCODE_MODEL= +OPENCODE_SMALL_MODEL= +OPENCODE_PROVIDER_ID= +OPENCODE_EXTRA_PLUGINS= +OPENCODE_SERVER_USERNAME=opencode +OPENCODE_SERVER_PASSWORD= +ANTHROPIC_API_KEY= +ANTHROPIC_BASE_URL= +OPENROUTER_API_KEY= +OPENROUTER_BASE_URL= +GEMINI_API_KEY= +GEMINI_BASE_URL= +GITHUB_TOKEN= +GIT_AUTHOR_NAME= +GIT_AUTHOR_EMAIL= +GIT_COMMITTER_NAME= +GIT_COMMITTER_EMAIL= +GPT_UNLOCKED_BASE_URL= +GPT_UNLOCKED_API_KEY= +GPT_UNLOCKED_MODEL= diff --git a/apps/opencode-workstation/latest/data.yml b/apps/opencode-workstation/latest/data.yml new file mode 100644 index 000000000..e00d4347f --- /dev/null +++ b/apps/opencode-workstation/latest/data.yml @@ -0,0 +1,702 @@ +additionalProperties: + formFields: + - default: 4096 + edit: true + envKey: PANEL_APP_PORT_HTTP + type: number + required: true + rule: paramPort + labelEn: Serve Port + labelZh: Serve 端口 + label: + en: Serve Port + zh: Serve 端口 + zh-Hant: Serve 端口 + ja: Serve ポート + ko: Serve 포트 + ru: Порт Serve + ms: Port Serve + pt-br: Porta do Serve + - default: 8765 + edit: true + envKey: PANEL_APP_PORT_ACP + type: number + required: true + rule: paramPort + labelEn: ACP Port + labelZh: ACP 端口 + label: + en: ACP Port + zh: ACP 端口 + zh-Hant: ACP 端口 + ja: ACP ポート + ko: ACP 포트 + ru: Порт ACP + ms: Port ACP + pt-br: Porta ACP + - default: Asia/Shanghai + edit: true + envKey: TZ + type: text + required: true + labelEn: Timezone + labelZh: 时区 + label: + en: Timezone + zh: 时区 + zh-Hant: 時區 + ja: タイムゾーン + ko: 시간대 + ru: Часовой пояс + ms: Zon waktu + pt-br: Fuso horário + - default: "./data/workspace" + edit: true + envKey: APP_DATA_DIR_1 + type: text + required: true + labelEn: Workspace Mount Path + labelZh: 工作区挂载目录 + label: + en: Workspace Mount Path + zh: 工作区挂载目录 + zh-Hant: 工作區掛載目錄 + ja: ワークスペースマウントパス + ko: 작업공간 마운트 경로 + ru: Путь монтирования рабочей области + ms: Laluan lekap ruang kerja + pt-br: Caminho de montagem do workspace + - default: "./data/config" + edit: true + envKey: APP_DATA_DIR_2 + type: text + required: true + labelEn: Config Mount Path + labelZh: 配置挂载目录 + label: + en: Config Mount Path + zh: 配置挂载目录 + zh-Hant: 配置掛載目錄 + ja: 設定マウントパス + ko: 설정 마운트 경로 + ru: Путь монтирования конфигурации + ms: Laluan lekap konfigurasi + pt-br: Caminho de montagem da configuração + - default: "./data/cache" + edit: true + envKey: APP_DATA_DIR_3 + type: text + required: true + labelEn: Cache Mount Path + labelZh: 缓存挂载目录 + label: + en: Cache Mount Path + zh: 缓存挂载目录 + zh-Hant: 快取掛載目錄 + ja: キャッシュマウントパス + ko: 캐시 마운트 경로 + ru: Путь монтирования кэша + ms: Laluan lekap cache + pt-br: Caminho de montagem do cache + - default: "./data/runtime" + edit: true + envKey: APP_DATA_DIR_4 + type: text + required: true + labelEn: Runtime Mount Path + labelZh: 运行时挂载目录 + label: + en: Runtime Mount Path + zh: 运行时挂载目录 + zh-Hant: 運行時掛載目錄 + ja: ランタイムマウントパス + ko: 런타임 마운트 경로 + ru: Путь монтирования рантайма + ms: Laluan lekap runtime + pt-br: Caminho de montagem do runtime + - default: /var/run/docker.sock + edit: true + envKey: DOCKER_SOCK_SRC + type: text + required: false + labelEn: Docker Socket Path (leave empty to disable) + labelZh: Docker 套接字路径(留空禁用) + label: + en: Docker Socket Path (leave empty to disable) + zh: Docker 套接字路径(留空禁用) + zh-Hant: Docker 套接字路徑(留空禁用) + ja: Docker ソケットパス(空欄で無効) + ko: Docker 소켓 경로 (비우면 비활성화) + ru: Путь к Docker-сокету (оставьте пустым для отключения) + ms: Laluan soket Docker (kosongkan untuk lumpuhkan) + pt-br: Caminho do socket Docker (deixe em branco para desabilitar) + - default: serve + edit: true + envKey: OPENCODE_RUNTIME_MODE + type: select + required: true + labelEn: Runtime Mode + labelZh: 运行模式 + label: + en: Runtime Mode + zh: 运行模式 + zh-Hant: 運行模式 + ja: 実行モード + ko: 실행 모드 + ru: Режим запуска + ms: Mod runtime + pt-br: Modo de execução + values: + - label: serve + value: serve + - label: acp + value: acp + - default: "1" + edit: true + envKey: OPENCODE_BOOTSTRAP + type: select + required: true + labelEn: Bootstrap OpenCode on Start + labelZh: 启动时安装 OpenCode + label: + en: Bootstrap OpenCode on Start + zh: 启动时安装 OpenCode + zh-Hant: 啟動時安裝 OpenCode + ja: 起動時にOpenCodeをインストール + ko: 시작 시 OpenCode 설치 + ru: Установить OpenCode при запуске + ms: Pasang OpenCode semasa mula + pt-br: Instalar OpenCode na inicialização + values: + - label: "true" + value: "1" + - label: "false" + value: "0" + - default: "1" + edit: true + envKey: OMO_AUTO_INSTALL + type: select + required: true + labelEn: Auto Install oh-my-opencode + labelZh: 启动时自动安装 oh-my-opencode + label: + en: Auto Install oh-my-opencode + zh: 启动时自动安装 oh-my-opencode + zh-Hant: 啟動時自動安裝 oh-my-opencode + ja: 起動時にoh-my-opencodeを自動インストール + ko: 시작 시 oh-my-opencode 자동 설치 + ru: Автоустановка oh-my-opencode при запуске + ms: Pasang oh-my-opencode secara automatik semasa mula + pt-br: Instalar oh-my-opencode automaticamente na inicialização + values: + - label: "true" + value: "1" + - label: "false" + value: "0" + - default: "1" + edit: true + envKey: DCP_INSTALL + type: select + required: true + labelEn: Install DCP Plugin + labelZh: 安装 DCP 插件 + label: + en: Install DCP Plugin + zh: 安装 DCP 插件 + zh-Hant: 安裝 DCP 外掛 + ja: DCPプラグインをインストール + ko: DCP 플러그인 설치 + ru: Установить плагин DCP + ms: Pasang plugin DCP + pt-br: Instalar plugin DCP + values: + - label: "true" + value: "1" + - label: "false" + value: "0" + - default: "1" + edit: true + envKey: GPT_UNLOCKED_INSTALL + type: select + required: true + labelEn: Install GPT Unlocked Plugin + labelZh: 安装 GPT Unlocked 插件 + label: + en: Install GPT Unlocked Plugin + zh: 安装 GPT Unlocked 插件 + zh-Hant: 安裝 GPT Unlocked 外掛 + ja: GPT Unlockedプラグインをインストール + ko: GPT Unlocked 플러그인 설치 + ru: Установить плагин GPT Unlocked + ms: Pasang plugin GPT Unlocked + pt-br: Instalar plugin GPT Unlocked + values: + - label: "true" + value: "1" + - label: "false" + value: "0" + - default: "no" + edit: true + envKey: OMO_CLAUDE_MODE + type: select + required: true + labelEn: Claude Install Mode + labelZh: Claude 安装模式 + label: + en: Claude Install Mode + zh: Claude 安装模式 + zh-Hant: Claude 安裝模式 + ja: Claudeインストールモード + ko: Claude 설치 모드 + ru: Режим установки Claude + ms: Mod pemasangan Claude + pt-br: Modo de instalação do Claude + values: + - label: "no" + value: "no" + - label: "yes" + value: "yes" + - label: max20 + value: max20 + - default: "no" + edit: true + envKey: OMO_GEMINI_MODE + type: select + required: true + labelEn: Gemini Install Mode + labelZh: Gemini 安装模式 + label: + en: Gemini Install Mode + zh: Gemini 安装模式 + zh-Hant: Gemini 安裝模式 + ja: Geminiインストールモード + ko: Gemini 설치 모드 + ru: Режим установки Gemini + ms: Mod pemasangan Gemini + pt-br: Modo de instalação do Gemini + values: + - label: "no" + value: "no" + - label: "yes" + value: "yes" + - default: "no" + edit: true + envKey: OMO_COPILOT_MODE + type: select + required: true + labelEn: Copilot Install Mode + labelZh: Copilot 安装模式 + label: + en: Copilot Install Mode + zh: Copilot 安装模式 + zh-Hant: Copilot 安裝模式 + ja: Copilotインストールモード + ko: Copilot 설치 모드 + ru: Режим установки Copilot + ms: Mod pemasangan Copilot + pt-br: Modo de instalação do Copilot + values: + - label: "no" + value: "no" + - label: "yes" + value: "yes" + - default: "" + edit: true + envKey: OMO_INSTALL_ARGS + type: text + required: false + labelEn: Extra Install Args + labelZh: 额外安装参数 + label: + en: Extra Install Args + zh: 额外安装参数 + zh-Hant: 額外安裝參數 + ja: 追加インストール引数 + ko: 추가 설치 인수 + ru: Дополнительные аргументы установки + ms: Argumen pemasangan tambahan + pt-br: Argumentos extras de instalação + - default: "opencode-ai" + edit: true + envKey: OPENCODE_NPM_PACKAGE + type: text + required: false + labelEn: OpenCode Package + labelZh: OpenCode 安装包 + label: + en: OpenCode Package + zh: OpenCode 安装包 + zh-Hant: OpenCode 安裝包 + ja: OpenCode パッケージ + ko: OpenCode 패키지 + ru: Пакет OpenCode + ms: Pakej OpenCode + pt-br: Pacote do OpenCode + - default: "oh-my-opencode" + edit: true + envKey: OMO_PACKAGE + type: text + required: false + labelEn: oh-my-opencode Package + labelZh: oh-my-opencode 安装包 + label: + en: oh-my-opencode Package + zh: oh-my-opencode 安装包 + zh-Hant: oh-my-opencode 安裝包 + ja: oh-my-opencode パッケージ + ko: oh-my-opencode 패키지 + ru: Пакет oh-my-opencode + ms: Pakej oh-my-opencode + pt-br: Pacote do oh-my-opencode + - default: "" + edit: true + envKey: OPENAI_API_KEY + type: password + required: false + labelEn: OpenAI API Key + labelZh: OpenAI API Key + label: + en: OpenAI API Key + zh: OpenAI API Key + zh-Hant: OpenAI API Key + ja: OpenAI API Key + ko: OpenAI API Key + ru: OpenAI API Key + ms: OpenAI API Key + pt-br: OpenAI API Key + - default: "" + edit: true + envKey: OPENAI_BASE_URL + type: text + required: false + labelEn: OpenAI Base URL + labelZh: OpenAI 接口地址(兼容第三方) + label: + en: OpenAI Base URL + zh: OpenAI 接口地址(兼容第三方) + zh-Hant: OpenAI 接口地址(兼容第三方) + ja: OpenAI APIエンドポイント(互換可) + ko: OpenAI API 엔드포인트(호환 가능) + ru: OpenAI endpoint(совместим с аналогами) + ms: OpenAI URL endpoint(serasi pihak ketiga) + pt-br: OpenAI endpoint(compatível com terceiros) + - default: "" + edit: true + envKey: OPENCODE_MODEL + type: text + required: false + labelEn: OpenCode Default Model + labelZh: OpenCode 默认模型 + label: + en: OpenCode Default Model + zh: OpenCode 默认模型 + zh-Hant: OpenCode 預設模型 + ja: OpenCodeデフォルトモデル + ko: OpenCode 기본 모델 + ru: Модель OpenCode по умолчанию + ms: Model lalai OpenCode + pt-br: Modelo padrão do OpenCode + - default: "" + edit: true + envKey: OPENCODE_SMALL_MODEL + type: text + required: false + labelEn: OpenCode Small Model + labelZh: OpenCode 轻量模型 + label: + en: OpenCode Small Model + zh: OpenCode 轻量模型 + zh-Hant: OpenCode 輕量模型 + ja: OpenCode軽量モデル + ko: OpenCode 경량 모델 + ru: Лёгкая модель OpenCode + ms: Model ringan OpenCode + pt-br: Modelo leve do OpenCode + - default: "" + edit: true + envKey: OPENCODE_PROVIDER_ID + type: text + required: false + labelEn: OpenCode Provider ID Override + labelZh: OpenCode Provider ID 覆盖 + label: + en: OpenCode Provider ID Override + zh: OpenCode Provider ID 覆盖 + zh-Hant: OpenCode Provider ID 覆寫 + ja: OpenCode Provider IDの上書き + ko: OpenCode Provider ID 재정의 + ru: Переопределение Provider ID OpenCode + ms: Override ID provider OpenCode + pt-br: Sobrescrever Provider ID do OpenCode + - default: "" + edit: true + envKey: OPENCODE_EXTRA_PLUGINS + type: text + required: false + labelEn: OpenCode Extra Plugins + labelZh: OpenCode 额外插件 + label: + en: OpenCode Extra Plugins + zh: OpenCode 额外插件 + zh-Hant: OpenCode 額外插件 + ja: OpenCode追加プラグイン + ko: OpenCode 추가 플러그인 + ru: Дополнительные плагины OpenCode + ms: Plugin tambahan OpenCode + pt-br: Plugins extras do OpenCode + - default: "opencode" + edit: true + envKey: OPENCODE_SERVER_USERNAME + type: text + required: false + labelEn: Serve Basic Auth Username + labelZh: Serve 基本认证用户名 + label: + en: Serve Basic Auth Username + zh: Serve 基本认证用户名 + zh-Hant: Serve 基本認證使用者名稱 + ja: Serve Basic認証ユーザー名 + ko: Serve 기본 인증 사용자 이름 + ru: Имя пользователя Basic Auth для serve + ms: Nama pengguna Basic Auth untuk serve + pt-br: Usuário de autenticação básica do serve + - default: "" + edit: true + envKey: OPENCODE_SERVER_PASSWORD + type: password + required: false + labelEn: Serve Basic Auth Password + labelZh: Serve 基本认证密码 + label: + en: Serve Basic Auth Password + zh: Serve 基本认证密码 + zh-Hant: Serve 基本認證密碼 + ja: Serve Basic認証パスワード + ko: Serve 기본 인증 비밀번호 + ru: Пароль Basic Auth для serve + ms: Kata laluan Basic Auth untuk serve + pt-br: Senha de autenticação básica do serve + - default: "" + edit: true + envKey: ANTHROPIC_API_KEY + type: password + required: false + labelEn: Anthropic API Key + labelZh: Anthropic API Key + label: + en: Anthropic API Key + zh: Anthropic API Key + zh-Hant: Anthropic API Key + ja: Anthropic API Key + ko: Anthropic API Key + ru: Anthropic API Key + ms: Anthropic API Key + pt-br: Anthropic API Key + - default: "" + edit: true + envKey: ANTHROPIC_BASE_URL + type: text + required: false + labelEn: Anthropic Base URL + labelZh: Anthropic Base URL + label: + en: Anthropic Base URL + zh: Anthropic Base URL + zh-Hant: Anthropic Base URL + ja: Anthropic Base URL + ko: Anthropic Base URL + ru: Anthropic Base URL + ms: Anthropic Base URL + pt-br: Anthropic Base URL + - default: "" + edit: true + envKey: OPENROUTER_API_KEY + type: password + required: false + labelEn: OpenRouter API Key + labelZh: OpenRouter API Key + label: + en: OpenRouter API Key + zh: OpenRouter API Key + zh-Hant: OpenRouter API Key + ja: OpenRouter API Key + ko: OpenRouter API Key + ru: OpenRouter API Key + ms: OpenRouter API Key + pt-br: OpenRouter API Key + - default: "" + edit: true + envKey: OPENROUTER_BASE_URL + type: text + required: false + labelEn: OpenRouter Base URL + labelZh: OpenRouter Base URL + label: + en: OpenRouter Base URL + zh: OpenRouter Base URL + zh-Hant: OpenRouter Base URL + ja: OpenRouter Base URL + ko: OpenRouter Base URL + ru: OpenRouter Base URL + ms: OpenRouter Base URL + pt-br: OpenRouter Base URL + - default: "" + edit: true + envKey: GEMINI_API_KEY + type: password + required: false + labelEn: Gemini API Key + labelZh: Gemini API Key + label: + en: Gemini API Key + zh: Gemini API Key + zh-Hant: Gemini API Key + ja: Gemini API Key + ko: Gemini API Key + ru: Gemini API Key + ms: Gemini API Key + pt-br: Gemini API Key + - default: "" + edit: true + envKey: GEMINI_BASE_URL + type: text + required: false + labelEn: Gemini Base URL + labelZh: Gemini Base URL + label: + en: Gemini Base URL + zh: Gemini Base URL + zh-Hant: Gemini Base URL + ja: Gemini Base URL + ko: Gemini Base URL + ru: Gemini Base URL + ms: Gemini Base URL + pt-br: Gemini Base URL + - default: "" + edit: true + envKey: GITHUB_TOKEN + type: password + required: false + labelEn: GitHub Token + labelZh: GitHub Token + label: + en: GitHub Token + zh: GitHub Token + zh-Hant: GitHub Token + ja: GitHub Token + ko: GitHub Token + ru: GitHub Token + ms: GitHub Token + pt-br: GitHub Token + - default: "" + edit: true + envKey: GIT_AUTHOR_NAME + type: text + required: false + labelEn: Git Author Name + labelZh: Git 作者名 + label: + en: Git Author Name + zh: Git 作者名 + zh-Hant: Git 作者名 + ja: Git作成者名 + ko: Git 작성자 이름 + ru: Имя автора Git + ms: Nama pengarang Git + pt-br: Nome do autor Git + - default: "" + edit: true + envKey: GIT_AUTHOR_EMAIL + type: text + required: false + labelEn: Git Author Email + labelZh: Git 作者邮箱 + label: + en: Git Author Email + zh: Git 作者邮箱 + zh-Hant: Git 作者郵箱 + ja: Git作成者メール + ko: Git 작성자 이메일 + ru: Email автора Git + ms: E-mel pengarang Git + pt-br: Email do autor Git + - default: "" + edit: true + envKey: GIT_COMMITTER_NAME + type: text + required: false + labelEn: Git Committer Name + labelZh: Git 提交者名 + label: + en: Git Committer Name + zh: Git 提交者名 + zh-Hant: Git 提交者名 + ja: Gitコミッター名 + ko: Git 커미터 이름 + ru: Имя коммиттера Git + ms: Nama komit Git + pt-br: Nome do committer Git + - default: "" + edit: true + envKey: GIT_COMMITTER_EMAIL + type: text + required: false + labelEn: Git Committer Email + labelZh: Git 提交者邮箱 + label: + en: Git Committer Email + zh: Git 提交者邮箱 + zh-Hant: Git 提交者郵箱 + ja: Gitコミッターメール + ko: Git 커미터 이메일 + ru: Email коммиттера Git + ms: E-mel komit Git + pt-br: Email do committer Git + - default: "" + edit: true + envKey: GPT_UNLOCKED_BASE_URL + type: text + required: false + labelEn: GPT Unlocked Base URL + labelZh: GPT Unlocked Base URL + label: + en: GPT Unlocked Base URL + zh: GPT Unlocked Base URL + zh-Hant: GPT Unlocked Base URL + ja: GPT Unlocked Base URL + ko: GPT Unlocked Base URL + ru: GPT Unlocked Base URL + ms: GPT Unlocked Base URL + pt-br: GPT Unlocked Base URL + - default: "" + edit: true + envKey: GPT_UNLOCKED_API_KEY + type: password + required: false + labelEn: GPT Unlocked API Key + labelZh: GPT Unlocked API Key + label: + en: GPT Unlocked API Key + zh: GPT Unlocked API Key + zh-Hant: GPT Unlocked API Key + ja: GPT Unlocked API Key + ko: GPT Unlocked API Key + ru: GPT Unlocked API Key + ms: GPT Unlocked API Key + pt-br: GPT Unlocked API Key + - default: "" + edit: true + envKey: GPT_UNLOCKED_MODEL + type: text + required: false + labelEn: GPT Unlocked Model + labelZh: GPT Unlocked 模型 + label: + en: GPT Unlocked Model + zh: GPT Unlocked 模型 + zh-Hant: GPT Unlocked 模型 + ja: GPT Unlockedモデル + ko: GPT Unlocked 모델 + ru: Модель GPT Unlocked + ms: Model GPT Unlocked + pt-br: Modelo GPT Unlocked diff --git a/apps/opencode-workstation/latest/data/.gitkeep b/apps/opencode-workstation/latest/data/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/apps/opencode-workstation/latest/docker-compose.yml b/apps/opencode-workstation/latest/docker-compose.yml new file mode 100644 index 000000000..b31ef3d14 --- /dev/null +++ b/apps/opencode-workstation/latest/docker-compose.yml @@ -0,0 +1,83 @@ +services: + opencode-workstation: + image: "ghcr.io/okxlin/opencode-workstation:latest" + container_name: ${CONTAINER_NAME} + labels: + createdBy: "Apps" + user: "0:0" + restart: unless-stopped + tty: true + stdin_open: true + ports: + - "${PANEL_APP_PORT_HTTP}:4096" + - "${PANEL_APP_PORT_ACP}:8765" + environment: + - TZ=${TZ} + - OPENCODE_RUNTIME_MODE=${OPENCODE_RUNTIME_MODE} + - ACP_HOST=0.0.0.0 + - ACP_PORT=8765 + - SERVE_HOST=0.0.0.0 + - SERVE_PORT=4096 + - OPENCODE_BOOTSTRAP=${OPENCODE_BOOTSTRAP} + - OMO_AUTO_INSTALL=${OMO_AUTO_INSTALL} + - DCP_INSTALL=${DCP_INSTALL} + - GPT_UNLOCKED_INSTALL=${GPT_UNLOCKED_INSTALL} + - OMO_CLAUDE_MODE=${OMO_CLAUDE_MODE} + - OMO_GEMINI_MODE=${OMO_GEMINI_MODE} + - OMO_COPILOT_MODE=${OMO_COPILOT_MODE} + - OMO_INSTALL_ARGS=${OMO_INSTALL_ARGS} + - OPENCODE_NPM_PACKAGE=${OPENCODE_NPM_PACKAGE} + - OMO_PACKAGE=${OMO_PACKAGE} + - OPENCODE_INSTALL_DIR=/data/opencode + - XDG_DATA_HOME=/data/xdg-data + - OPENCODE_NPM_BIN_DIR=/data/bin + - OPENCODE_CONFIG_DIR=/config/opencode + - OMO_INSTALL_DIR=/data/oh-my-opencode + - OPENAI_API_KEY=${OPENAI_API_KEY} + - OPENAI_BASE_URL=${OPENAI_BASE_URL} + - OPENCODE_MODEL=${OPENCODE_MODEL} + - OPENCODE_SMALL_MODEL=${OPENCODE_SMALL_MODEL} + - OPENCODE_PROVIDER_ID=${OPENCODE_PROVIDER_ID} + - OPENCODE_EXTRA_PLUGINS=${OPENCODE_EXTRA_PLUGINS} + - OPENCODE_SERVER_USERNAME=${OPENCODE_SERVER_USERNAME} + - OPENCODE_SERVER_PASSWORD=${OPENCODE_SERVER_PASSWORD} + - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} + - ANTHROPIC_BASE_URL=${ANTHROPIC_BASE_URL} + - OPENROUTER_API_KEY=${OPENROUTER_API_KEY} + - OPENROUTER_BASE_URL=${OPENROUTER_BASE_URL} + - GEMINI_API_KEY=${GEMINI_API_KEY} + - GEMINI_BASE_URL=${GEMINI_BASE_URL} + - GITHUB_TOKEN=${GITHUB_TOKEN} + - GIT_AUTHOR_NAME=${GIT_AUTHOR_NAME} + - GIT_AUTHOR_EMAIL=${GIT_AUTHOR_EMAIL} + - GIT_COMMITTER_NAME=${GIT_COMMITTER_NAME} + - GIT_COMMITTER_EMAIL=${GIT_COMMITTER_EMAIL} + - GPT_UNLOCKED_BASE_URL=${GPT_UNLOCKED_BASE_URL} + - GPT_UNLOCKED_API_KEY=${GPT_UNLOCKED_API_KEY} + - GPT_UNLOCKED_MODEL=${GPT_UNLOCKED_MODEL} + volumes: + - ${APP_DATA_DIR_1}:/workspace + - ${APP_DATA_DIR_2}:/config + - ${APP_DATA_DIR_3}:/cache + - ${APP_DATA_DIR_4}:/data + - ${DOCKER_SOCK_SRC}:/var/run/docker.sock + healthcheck: + test: + - CMD-SHELL + - >- + if [ "$OPENCODE_RUNTIME_MODE" = "serve" ]; then + ps -ef | grep -v grep | grep "opencode serve" >/dev/null; + else + ps -ef | grep -v grep | grep "opencode acp" >/dev/null; + fi + interval: 30s + timeout: 10s + retries: 5 + start_period: 30s + command: ["runtime"] + networks: + - 1panel-network + +networks: + 1panel-network: + external: true diff --git a/apps/opencode-workstation/latest/scripts/init.sh b/apps/opencode-workstation/latest/scripts/init.sh new file mode 100755 index 000000000..1782ff658 --- /dev/null +++ b/apps/opencode-workstation/latest/scripts/init.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -euo pipefail + +mkdir -p "${APP_DATA_DIR_1:-./data/workspace}" \ + "${APP_DATA_DIR_2:-./data/config}" \ + "${APP_DATA_DIR_3:-./data/cache}" \ + "${APP_DATA_DIR_4:-./data/runtime}" + +echo '[opencode-workstation:init] initialized persistent directories:' +echo " ${APP_DATA_DIR_1:-./data/workspace} -> /workspace" +echo " ${APP_DATA_DIR_2:-./data/config} -> /config" +echo " ${APP_DATA_DIR_3:-./data/cache} -> /cache" +echo " ${APP_DATA_DIR_4:-./data/runtime} -> /data" +echo '[opencode-workstation:init] default serve address: http://0.0.0.0:4096' +echo '[opencode-workstation:init] ACP port: 8765' diff --git a/apps/opencode-workstation/logo.png b/apps/opencode-workstation/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..9cec3e62d1817bf3fe702d0d21ccdd15beb049a2 GIT binary patch literal 4768 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

!}0k@$uIak@e=yjlY=N3BnWaKW~gk*dW)%cD3KH zwneSf(5a7)G8=QG9&G%o^pIm^L|i@bbY{D?PdIy50b`l(y!p* u)zeQLhv-{v{-Yu3Xm({aFaH6