Compare commits

..
4 Commits
Author SHA1 Message Date
lminandClaude Opus 4.7 ccd881c689 build: 精简构建目标为 5 个主平台
compliance-close / close-non-compliant (push) Has been cancelled
beta / sync (push) Has been cancelled
docs-update / update-docs (push) Has been cancelled
close-prs / close (push) Has been cancelled
close-issues / close (push) Has been cancelled
stats / stats (push) Has been cancelled
allTargets 只保留 win-x64/darwin-arm64/darwin-x64/linux-x64/linux-arm64,
去掉 musl/baseline 变体,加快构建、减少体积。
去掉 --single 即一次构建全部 5 平台(Bun 交叉编译)。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-05 21:17:28 +08:00
lminandClaude Opus 4.7 698ce2fa31 feat: zmo providers login 支持填写自定义 base URL(中转地址)
compliance-close / close-non-compliant (push) Has been cancelled
beta / sync (push) Has been cancelled
login 填完 API key 后新增一步询问 base URL(留空=官方默认)。
若填写则写入 ~/.config/zmo/zmo.json 的 provider.<id>.options.baseURL,
后续请求自动走中转。key 仍存 auth.json,baseURL 走 config。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-05 20:54:26 +08:00
lminandClaude Opus 4.7 6953fce7c6 feat: config 加载支持 zmo.json/zmo.jsonc 文件名(优先于 opencode.*)
全局配置加载、globalConfigFile、项目/.opencode 目录、managed 目录
均加入 zmo.json/zmo.jsonc 查找,优先级高于 opencode.* 兼容名。
用户可直接用 ~/.config/zmo/zmo.jsonc 配置。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-05 20:46:49 +08:00
lminandClaude Opus 4.7 52eb90e7c3 feat: 支持用环境变量配 provider baseURL(所有 provider 通用)
resolveSDK 在 config 未设 baseURL 时,回退读环境变量:
专属 <PROVIDER>_BASE_URL(如 OPENAI_BASE_URL/ANTHROPIC_BASE_URL)
> 通用 ZMO_BASE_URL。env.all() 含 process.env,用户设系统环境变量即可。
优先级:config options.baseURL > 专属env > 通用 ZMO_BASE_URL > 官方默认。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-05 20:43:59 +08:00
4 changed files with 49 additions and 38 deletions
-35
View File
@@ -56,34 +56,13 @@ const allTargets: {
abi?: "musl"
avx2?: false
}[] = [
{
os: "linux",
arch: "arm64",
},
{
os: "linux",
arch: "x64",
},
{
os: "linux",
arch: "x64",
avx2: false,
},
{
os: "linux",
arch: "arm64",
abi: "musl",
},
{
os: "linux",
arch: "x64",
abi: "musl",
},
{
os: "linux",
arch: "x64",
abi: "musl",
avx2: false,
},
{
os: "darwin",
@@ -93,24 +72,10 @@ const allTargets: {
os: "darwin",
arch: "x64",
},
{
os: "darwin",
arch: "x64",
avx2: false,
},
{
os: "win32",
arch: "arm64",
},
{
os: "win32",
arch: "x64",
},
{
os: "win32",
arch: "x64",
avx2: false,
},
]
const targets = singleFlag
@@ -8,6 +8,7 @@ import { ModelsDev } from "@opencode-ai/core/models-dev"
import { map, pipe, sortBy, values } from "remeda"
import path from "path"
import os from "os"
import fsNode from "node:fs"
import { Config } from "@/config/config"
import { Global } from "@opencode-ai/core/global"
import { Plugin } from "../../plugin"
@@ -481,6 +482,38 @@ export const ProvidersLoginCommand = effectCmd({
const apiKey = yield* promptValue(key)
yield* Effect.orDie(authSvc.set(provider, { type: "api", key: apiKey }))
// zmo: 询问自定义 base URL(中转地址),留空则用官方默认。
// baseURL 不存 auth.json,写入 config 文件的 provider.<id>.options.baseURL。
const baseURLInput = yield* Prompt.text({
message: "Base URL (中转地址,留空使用官方默认)",
placeholder: "https://your-proxy.example.com/v1",
})
const baseURL = (yield* promptValue(baseURLInput))?.trim()
if (baseURL) {
try {
const configDir = Global.Path.config
fsNode.mkdirSync(configDir, { recursive: true })
const file = path.join(configDir, "zmo.json")
let data: any = {}
if (fsNode.existsSync(file)) {
try {
data = JSON.parse(fsNode.readFileSync(file, "utf8")) ?? {}
} catch {
data = {}
}
}
if (!data.$schema) data.$schema = "https://zmo.dev/config.json"
data.provider ??= {}
data.provider[provider] ??= {}
data.provider[provider].options ??= {}
data.provider[provider].options.baseURL = baseURL
fsNode.writeFileSync(file, JSON.stringify(data, null, 2))
yield* Prompt.log.info(`Base URL 已保存到 ${file}`)
} catch {
yield* Prompt.log.warn("Base URL 保存失败,请手动写入 zmo.json")
}
}
yield* Prompt.outro("Done")
}),
})
+5 -3
View File
@@ -138,7 +138,7 @@ export class Service extends Context.Service<Service, Interface>()("@opencode/Co
export const use = serviceUse(Service)
function globalConfigFile() {
const candidates = ["opencode.jsonc", "opencode.json", "config.json"].map((file) =>
const candidates = ["zmo.jsonc", "zmo.json", "opencode.jsonc", "opencode.json", "config.json"].map((file) =>
path.join(Global.Path.config, file),
)
for (const file of candidates) {
@@ -250,6 +250,8 @@ export const layer = Layer.effect(
result = mergeConfig(result, yield* loadFile(path.join(Global.Path.config, "config.json"), env))
result = mergeConfig(result, yield* loadFile(path.join(Global.Path.config, "opencode.json"), env))
result = mergeConfig(result, yield* loadFile(path.join(Global.Path.config, "opencode.jsonc"), env))
result = mergeConfig(result, yield* loadFile(path.join(Global.Path.config, "zmo.json"), env))
result = mergeConfig(result, yield* loadFile(path.join(Global.Path.config, "zmo.jsonc"), env))
const legacy = path.join(Global.Path.config, "config")
if (existsSync(legacy)) {
@@ -414,7 +416,7 @@ export const layer = Layer.effect(
for (const dir of directories) {
if (dir.endsWith(".opencode") || dir === Flag.OPENCODE_CONFIG_DIR) {
for (const file of ["opencode.json", "opencode.jsonc"]) {
for (const file of ["zmo.json", "zmo.jsonc", "opencode.json", "opencode.jsonc"]) {
const source = path.join(dir, file)
log.debug(`loading config from ${source}`)
yield* merge(source, yield* loadFile(source, authEnv))
@@ -509,7 +511,7 @@ export const layer = Layer.effect(
const managedDir = ConfigManaged.managedConfigDir()
if (existsSync(managedDir)) {
for (const file of ["opencode.json", "opencode.jsonc"]) {
for (const file of ["zmo.json", "zmo.jsonc", "opencode.json", "opencode.jsonc"]) {
const source = path.join(managedDir, file)
yield* merge(source, yield* loadFile(source), "global")
}
@@ -1540,6 +1540,17 @@ export const layer = Layer.effect(
const provider = s.providers[model.providerID]
const options = { ...provider.options }
// zmo: 支持用环境变量配 baseURL(所有 provider 通用)。
// 优先级:config options.baseURL > 专属 <PROVIDER>_BASE_URL > 通用 ZMO_BASE_URL。
// 仅当 config 未显式设置 baseURL 时才用环境变量回退。
if (typeof options["baseURL"] !== "string" || options["baseURL"] === "") {
const envName = model.providerID.toUpperCase().replace(/-/g, "_") + "_BASE_URL"
const envBaseURL = envs[envName] ?? envs["ZMO_BASE_URL"]
if (typeof envBaseURL === "string" && envBaseURL !== "") {
options["baseURL"] = envBaseURL
}
}
if (
model.providerID === "google-vertex" &&
model.api.npm === "@ai-sdk/google-vertex/anthropic" &&