feat: 全面清除用户/AI可见的 opencode 痕迹
compliance-close / close-non-compliant (push) Has been cancelled
beta / sync (push) Has been cancelled

- system.ts 不再把真实 model id 喂给 LLM(修复"底层是opencode/big-pickle")
- TUI 首页 tips、窗口标题、ACP 弹窗、命令提示文案全部 → zmo
- config schema URL → zmo.dev;配置路径提示 → ~/.config/zmo、.zmo/
- 发给各家 LLM API 的标识头(X-Title/Referer/Source/UA/originator)→ zmo
- 保留:opencode provider 路由id、@opencode-ai 包名、opencode.json/OPENCODE_* 兼容

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-05 17:49:47 +08:00
co-authored by Claude Opus 4.7
parent 9970e6c1ad
commit 5bd92a3535
21 changed files with 81 additions and 82 deletions
@@ -10,7 +10,7 @@ export const CerebrasPlugin = PluginV2.define({
if (item.provider.api.type !== "aisdk") continue if (item.provider.api.type !== "aisdk") continue
if (item.provider.api.package !== "@ai-sdk/cerebras") continue if (item.provider.api.package !== "@ai-sdk/cerebras") continue
ctx.provider.update(item.provider.id, (provider) => { ctx.provider.update(item.provider.id, (provider) => {
provider.request.headers["X-Cerebras-3rd-Party-Integration"] = "opencode" provider.request.headers["X-Cerebras-3rd-Party-Integration"] = "zmo"
}) })
} }
}), }),
@@ -71,7 +71,7 @@ function gatewayOptions(options: Record<string, unknown>, metadata: unknown) {
skipCache: options.skipCache, skipCache: options.skipCache,
collectLog: options.collectLog, collectLog: options.collectLog,
headers: { headers: {
"User-Agent": `opencode/${InstallationVersion} cloudflare-ai-gateway (${os.platform()} ${os.release()}; ${os.arch()})`, "User-Agent": `zmo/${InstallationVersion} cloudflare-ai-gateway (${os.platform()} ${os.release()}; ${os.arch()})`,
}, },
} }
} }
@@ -54,7 +54,7 @@ function sdkOptions(options: Record<string, any>) {
baseURL: expandAccountId(options.baseURL), baseURL: expandAccountId(options.baseURL),
apiKey: process.env.CLOUDFLARE_API_KEY ?? options.apiKey, apiKey: process.env.CLOUDFLARE_API_KEY ?? options.apiKey,
headers: { headers: {
"User-Agent": `opencode/${InstallationVersion} cloudflare-workers-ai (${os.platform()} ${os.release()}; ${os.arch()})`, "User-Agent": `zmo/${InstallationVersion} cloudflare-workers-ai (${os.platform()} ${os.release()}; ${os.arch()})`,
...options.headers, ...options.headers,
}, },
name: providerID, name: providerID,
+1 -1
View File
@@ -19,7 +19,7 @@ export const GitLabPlugin = PluginV2.define({
: (process.env.GITLAB_INSTANCE_URL ?? "https://gitlab.com"), : (process.env.GITLAB_INSTANCE_URL ?? "https://gitlab.com"),
apiKey: typeof evt.options.apiKey === "string" ? evt.options.apiKey : process.env.GITLAB_TOKEN, apiKey: typeof evt.options.apiKey === "string" ? evt.options.apiKey : process.env.GITLAB_TOKEN,
aiGatewayHeaders: { aiGatewayHeaders: {
"User-Agent": `opencode/${InstallationVersion} gitlab-ai-provider/${mod.VERSION} (${os.platform()} ${os.release()}; ${os.arch()})`, "User-Agent": `zmo/${InstallationVersion} gitlab-ai-provider/${mod.VERSION} (${os.platform()} ${os.release()}; ${os.arch()})`,
"anthropic-beta": "context-1m-2025-08-07", "anthropic-beta": "context-1m-2025-08-07",
...evt.options.aiGatewayHeaders, ...evt.options.aiGatewayHeaders,
}, },
+2 -2
View File
@@ -11,8 +11,8 @@ export const KiloPlugin = PluginV2.define({
if (item.provider.api.package !== "@ai-sdk/openai-compatible") continue if (item.provider.api.package !== "@ai-sdk/openai-compatible") continue
if (item.provider.api.url !== "https://api.kilo.ai/api/gateway") continue if (item.provider.api.url !== "https://api.kilo.ai/api/gateway") continue
evt.provider.update(item.provider.id, (provider) => { evt.provider.update(item.provider.id, (provider) => {
provider.request.headers["HTTP-Referer"] = "https://opencode.ai/" provider.request.headers["HTTP-Referer"] = "https://github.com/helpLogin/zmo-cli"
provider.request.headers["X-Title"] = "opencode" provider.request.headers["X-Title"] = "zmo"
}) })
} }
}), }),
@@ -12,9 +12,9 @@ export const LLMGatewayPlugin = PluginV2.define({
if (item.provider.api.package !== "@ai-sdk/openai-compatible") continue if (item.provider.api.package !== "@ai-sdk/openai-compatible") continue
if (item.provider.api.url !== "https://api.llmgateway.io/v1") continue if (item.provider.api.url !== "https://api.llmgateway.io/v1") continue
evt.provider.update(item.provider.id, (provider) => { evt.provider.update(item.provider.id, (provider) => {
provider.request.headers["HTTP-Referer"] = "https://opencode.ai/" provider.request.headers["HTTP-Referer"] = "https://github.com/helpLogin/zmo-cli"
provider.request.headers["X-Title"] = "opencode" provider.request.headers["X-Title"] = "zmo"
provider.request.headers["X-Source"] = "opencode" provider.request.headers["X-Source"] = "zmo"
}) })
} }
}), }),
+3 -3
View File
@@ -11,9 +11,9 @@ export const NvidiaPlugin = PluginV2.define({
if (item.provider.api.package !== "@ai-sdk/openai-compatible") continue if (item.provider.api.package !== "@ai-sdk/openai-compatible") continue
if (item.provider.api.url !== "https://integrate.api.nvidia.com/v1") continue if (item.provider.api.url !== "https://integrate.api.nvidia.com/v1") continue
evt.provider.update(item.provider.id, (provider) => { evt.provider.update(item.provider.id, (provider) => {
provider.request.headers["HTTP-Referer"] = "https://opencode.ai/" provider.request.headers["HTTP-Referer"] = "https://github.com/helpLogin/zmo-cli"
provider.request.headers["X-Title"] = "opencode" provider.request.headers["X-Title"] = "zmo"
provider.request.headers["X-BILLING-INVOKE-ORIGIN"] ??= "OpenCode" provider.request.headers["X-BILLING-INVOKE-ORIGIN"] ??= "zmo"
}) })
} }
}), }),
@@ -11,8 +11,8 @@ export const OpenRouterPlugin = PluginV2.define({
if (item.provider.api.type !== "aisdk") continue if (item.provider.api.type !== "aisdk") continue
if (item.provider.api.package !== "@openrouter/ai-sdk-provider") continue if (item.provider.api.package !== "@openrouter/ai-sdk-provider") continue
evt.provider.update(item.provider.id, (provider) => { evt.provider.update(item.provider.id, (provider) => {
provider.request.headers["HTTP-Referer"] = "https://opencode.ai/" provider.request.headers["HTTP-Referer"] = "https://github.com/helpLogin/zmo-cli"
provider.request.headers["X-Title"] = "opencode" provider.request.headers["X-Title"] = "zmo"
}) })
for (const modelID of [ModelV2.ID.make("gpt-5-chat-latest"), ModelV2.ID.make("openai/gpt-5-chat")]) { for (const modelID of [ModelV2.ID.make("gpt-5-chat-latest"), ModelV2.ID.make("openai/gpt-5-chat")]) {
if (!item.models.has(modelID)) continue if (!item.models.has(modelID)) continue
+2 -2
View File
@@ -10,8 +10,8 @@ export const VercelPlugin = PluginV2.define({
if (item.provider.api.type !== "aisdk") continue if (item.provider.api.type !== "aisdk") continue
if (item.provider.api.package !== "@ai-sdk/vercel") continue if (item.provider.api.package !== "@ai-sdk/vercel") continue
evt.provider.update(item.provider.id, (provider) => { evt.provider.update(item.provider.id, (provider) => {
provider.request.headers["http-referer"] = "https://opencode.ai/" provider.request.headers["http-referer"] = "https://github.com/helpLogin/zmo-cli"
provider.request.headers["x-title"] = "opencode" provider.request.headers["x-title"] = "zmo"
}) })
} }
}), }),
+5 -5
View File
@@ -93,17 +93,17 @@ export function make(input: {
const initialize = Effect.fn("ACP.initialize")(function* (params: InitializeRequest) { const initialize = Effect.fn("ACP.initialize")(function* (params: InitializeRequest) {
const started = performance.now() const started = performance.now()
const authMethod: AuthMethod = { const authMethod: AuthMethod = {
description: "Run `opencode auth login` in the terminal", description: "Run `zmo auth login` in the terminal",
name: "Login with opencode", name: "Login with zmo",
id: AuthMethodID, id: AuthMethodID,
} }
if (params.clientCapabilities?._meta?.["terminal-auth"] === true) { if (params.clientCapabilities?._meta?.["terminal-auth"] === true) {
authMethod._meta = { authMethod._meta = {
"terminal-auth": { "terminal-auth": {
command: "opencode", command: "zmo",
args: ["auth", "login"], args: ["auth", "login"],
label: "OpenCode Login", label: "zmo Login",
}, },
} }
} }
@@ -129,7 +129,7 @@ export function make(input: {
}, },
authMethods: [authMethod], authMethods: [authMethod],
agentInfo: { agentInfo: {
name: "OpenCode", name: "zmo",
version: InstallationVersion, version: InstallationVersion,
}, },
} }
+1 -1
View File
@@ -301,7 +301,7 @@ export const ProvidersLoginCommand = effectCmd({
builder: (yargs) => builder: (yargs) =>
yargs yargs
.positional("url", { .positional("url", {
describe: "opencode auth provider", describe: "zmo auth provider",
type: "string", type: "string",
}) })
.option("provider", { .option("provider", {
+1 -1
View File
@@ -263,7 +263,7 @@ function build(input: SplashWriterInput, kind: "entry" | "exit", ctx: Scrollback
lines, lines,
body_left + label.length, body_left + label.length,
top + 1, top + 1,
`opencode run -i -s ${meta.session_id}`, `zmo run -i -s ${meta.session_id}`,
right, right,
undefined, undefined,
TextAttributes.BOLD, TextAttributes.BOLD,
@@ -40,7 +40,7 @@ type TuiAttentionHost = TuiAttention & {
const log = Log.create({ service: "tui.attention" }) const log = Log.create({ service: "tui.attention" })
const DEFAULT_TITLE = "opencode" const DEFAULT_TITLE = "zmo"
const DEFAULT_PACK_ID = "opencode.default" const DEFAULT_PACK_ID = "opencode.default"
const KV_SOUND_PACK = "attention_sound_pack" const KV_SOUND_PACK = "attention_sound_pack"
const TITLE_LIMIT = 80 const TITLE_LIMIT = 80
@@ -11,7 +11,7 @@ import * as ConfigPaths from "@/config/paths"
const log = Log.create({ service: "tui.migrate" }) const log = Log.create({ service: "tui.migrate" })
const TUI_SCHEMA_URL = "https://opencode.ai/tui.json" const TUI_SCHEMA_URL = "https://zmo.dev/tui.json"
const decodeTheme = Schema.decodeUnknownOption(Schema.String) const decodeTheme = Schema.decodeUnknownOption(Schema.String)
const decodeRecord = Schema.decodeUnknownOption(Schema.Record(Schema.String, Schema.Unknown)) const decodeRecord = Schema.decodeUnknownOption(Schema.Record(Schema.String, Schema.Unknown))
@@ -167,7 +167,7 @@ const TIPS: Tip[] = [
(shortcuts) => press(shortcuts.agentCycle(), "to cycle between Build and Plan agents"), (shortcuts) => press(shortcuts.agentCycle(), "to cycle between Build and Plan agents"),
"Use {highlight}/undo{/highlight} to revert the last message and file changes", "Use {highlight}/undo{/highlight} to revert the last message and file changes",
"Use {highlight}/redo{/highlight} to restore previously undone messages and file changes", "Use {highlight}/redo{/highlight} to restore previously undone messages and file changes",
"Run {highlight}/share{/highlight} to create a public link to your conversation at opencode.ai", "Run {highlight}/share{/highlight} to create a public link to your conversation",
"Drag and drop images or PDFs into the terminal to add them as context", "Drag and drop images or PDFs into the terminal to add them as context",
(shortcuts) => press(shortcuts.inputPaste(), "to paste images from your clipboard into the prompt"), (shortcuts) => press(shortcuts.inputPaste(), "to paste images from your clipboard into the prompt"),
(shortcuts) => `Use ${commandText("/editor", shortcuts.editorOpen())} to compose messages in your external editor`, (shortcuts) => `Use ${commandText("/editor", shortcuts.editorOpen())} to compose messages in your external editor`,
@@ -210,17 +210,17 @@ const TIPS: Tip[] = [
if (!items.length) return undefined if (!items.length) return undefined
return `Use ${items.map(shortcutText).join(" / ")} to move between parent and child sessions` return `Use ${items.map(shortcutText).join(" / ")} to move between parent and child sessions`
}, },
"Create {highlight}opencode.json{/highlight} for server settings and {highlight}tui.json{/highlight} for TUI settings", "Create {highlight}zmo.json{/highlight} for server settings and {highlight}tui.json{/highlight} for TUI settings",
"Place TUI settings in {highlight}~/.config/opencode/tui.json{/highlight} for global config", "Place TUI settings in {highlight}~/.config/zmo/tui.json{/highlight} for global config",
"Add {highlight}$schema{/highlight} to your config for autocomplete in your editor", "Add {highlight}$schema{/highlight} to your config for autocomplete in your editor",
"Configure {highlight}model{/highlight} in config to set your default model", "Configure {highlight}model{/highlight} in config to set your default model",
"Override any keybind in {highlight}tui.json{/highlight} via the {highlight}keybinds{/highlight} section", "Override any keybind in {highlight}tui.json{/highlight} via the {highlight}keybinds{/highlight} section",
"Set any keybind to {highlight}none{/highlight} to disable it completely", "Set any keybind to {highlight}none{/highlight} to disable it completely",
"Configure local or remote MCP servers in the {highlight}mcp{/highlight} config section", "Configure local or remote MCP servers in the {highlight}mcp{/highlight} config section",
"Add {highlight}.md{/highlight} files to {highlight}.opencode/commands/{/highlight} to define reusable custom prompts", "Add {highlight}.md{/highlight} files to {highlight}.zmo/commands/{/highlight} to define reusable custom prompts",
"Use {highlight}$ARGUMENTS{/highlight}, {highlight}$1{/highlight}, {highlight}$2{/highlight} in custom commands for dynamic input", "Use {highlight}$ARGUMENTS{/highlight}, {highlight}$1{/highlight}, {highlight}$2{/highlight} in custom commands for dynamic input",
"Use backticks in commands to inject shell output (e.g., {highlight}`git status`{/highlight})", "Use backticks in commands to inject shell output (e.g., {highlight}`git status`{/highlight})",
"Add {highlight}.md{/highlight} files to {highlight}.opencode/agents/{/highlight} for specialized AI personas", "Add {highlight}.md{/highlight} files to {highlight}.zmo/agents/{/highlight} for specialized AI personas",
"Configure per-agent permissions for {highlight}edit{/highlight}, {highlight}bash{/highlight}, and {highlight}webfetch{/highlight} tools", "Configure per-agent permissions for {highlight}edit{/highlight}, {highlight}bash{/highlight}, and {highlight}webfetch{/highlight} tools",
'Use patterns like {highlight}"git *": "allow"{/highlight} for granular bash permissions', 'Use patterns like {highlight}"git *": "allow"{/highlight} for granular bash permissions',
'Set {highlight}"rm -rf *": "deny"{/highlight} to block destructive commands', 'Set {highlight}"rm -rf *": "deny"{/highlight} to block destructive commands',
@@ -229,26 +229,25 @@ const TIPS: Tip[] = [
'Set {highlight}"formatter": false{/highlight} in config to disable formatters enabled by another config layer', 'Set {highlight}"formatter": false{/highlight} in config to disable formatters enabled by another config layer',
"Define custom formatter commands with file extensions in config", "Define custom formatter commands with file extensions in config",
'Set {highlight}"lsp": true{/highlight} in config to enable built-in LSP servers for code analysis', 'Set {highlight}"lsp": true{/highlight} in config to enable built-in LSP servers for code analysis',
"Create {highlight}.ts{/highlight} files in {highlight}.opencode/tools/{/highlight} to define new LLM tools", "Create {highlight}.ts{/highlight} files in {highlight}.zmo/tools/{/highlight} to define new LLM tools",
"Tool definitions can invoke scripts written in Python, Go, etc", "Tool definitions can invoke scripts written in Python, Go, etc",
"Add {highlight}.ts{/highlight} files to {highlight}.opencode/plugins/{/highlight} for event hooks", "Add {highlight}.ts{/highlight} files to {highlight}.zmo/plugins/{/highlight} for event hooks",
"Use plugins to send OS notifications when sessions complete", "Use plugins to send OS notifications when sessions complete",
"Create a plugin to prevent OpenCode from reading sensitive files", "Create a plugin to prevent zmo from reading sensitive files",
"Use {highlight}opencode run{/highlight} for non-interactive scripting", "Use {highlight}zmo run{/highlight} for non-interactive scripting",
"Use {highlight}opencode --continue{/highlight} to resume the last session", "Use {highlight}zmo --continue{/highlight} to resume the last session",
"Use {highlight}opencode run -f file.ts{/highlight} to attach files via CLI", "Use {highlight}zmo run -f file.ts{/highlight} to attach files via CLI",
"Use {highlight}--format json{/highlight} for machine-readable output in scripts", "Use {highlight}--format json{/highlight} for machine-readable output in scripts",
"Run {highlight}opencode serve{/highlight} for headless API access to OpenCode", "Run {highlight}zmo serve{/highlight} for headless API access to zmo",
"Use {highlight}opencode run --attach{/highlight} to connect to a running server", "Use {highlight}zmo run --attach{/highlight} to connect to a running server",
"Run {highlight}opencode upgrade{/highlight} to update to the latest version", "Run {highlight}zmo upgrade{/highlight} to update to the latest version",
"Run {highlight}opencode auth list{/highlight} to see all configured providers", "Run {highlight}zmo auth list{/highlight} to see all configured providers",
"Run {highlight}opencode agent create{/highlight} for guided agent creation", "Run {highlight}zmo agent create{/highlight} for guided agent creation",
"Use {highlight}/opencode{/highlight} in GitHub issues/PRs to trigger AI actions", "Use {highlight}--format json{/highlight} to integrate zmo into your scripts",
"Run {highlight}opencode github install{/highlight} to set up the GitHub workflow", "Use {highlight}zmo run --continue{/highlight} to continue the last session non-interactively",
"Comment {highlight}/opencode fix this{/highlight} on issues to auto-create PRs",
"Comment {highlight}/oc{/highlight} on PR code lines for targeted code reviews", "Comment {highlight}/oc{/highlight} on PR code lines for targeted code reviews",
'Use {highlight}"theme": "system"{/highlight} to match your terminal\'s colors', 'Use {highlight}"theme": "system"{/highlight} to match your terminal\'s colors',
"Create JSON theme files in {highlight}.opencode/themes/{/highlight} directory", "Create JSON theme files in {highlight}.zmo/themes/{/highlight} directory",
"Themes support dark/light variants for both modes", "Themes support dark/light variants for both modes",
"Use numeric xterm color codes 0-255 in custom theme JSON", "Use numeric xterm color codes 0-255 in custom theme JSON",
"Use {highlight}{env:VAR_NAME}{/highlight} syntax to reference environment variables in config", "Use {highlight}{env:VAR_NAME}{/highlight} syntax to reference environment variables in config",
@@ -264,7 +263,7 @@ const TIPS: Tip[] = [
"Run {highlight}/unshare{/highlight} to remove a session from public access", "Run {highlight}/unshare{/highlight} to remove a session from public access",
"Permission {highlight}doom_loop{/highlight} prevents infinite tool call loops", "Permission {highlight}doom_loop{/highlight} prevents infinite tool call loops",
"Permission {highlight}external_directory{/highlight} protects files outside project", "Permission {highlight}external_directory{/highlight} protects files outside project",
"Run {highlight}opencode debug config{/highlight} to troubleshoot configuration", "Run {highlight}zmo debug config{/highlight} to troubleshoot configuration",
"Use {highlight}--print-logs{/highlight} flag to see detailed logs in stderr", "Use {highlight}--print-logs{/highlight} flag to see detailed logs in stderr",
(shortcuts) => `Use ${commandText("/timeline", shortcuts.sessionTimeline())} to jump to specific messages`, (shortcuts) => `Use ${commandText("/timeline", shortcuts.sessionTimeline())} to jump to specific messages`,
(shortcuts) => press(shortcuts.messagesToggleConceal(), "to toggle code block visibility in messages"), (shortcuts) => press(shortcuts.messagesToggleConceal(), "to toggle code block visibility in messages"),
@@ -274,8 +273,8 @@ const TIPS: Tip[] = [
shortcuts.commandList() shortcuts.commandList()
? `Toggle username display in chat via the command palette (${shortcutText(shortcuts.commandList())})` ? `Toggle username display in chat via the command palette (${shortcutText(shortcuts.commandList())})`
: "Toggle username display in chat via the command palette", : "Toggle username display in chat via the command palette",
"Run {highlight}docker run -it --rm ghcr.io/anomalyco/opencode{/highlight} for containerized use", "Switch between models mid-session to use the best tool for each task",
"Use {highlight}/connect{/highlight} with OpenCode Zen for curated, tested models", "Configure any OpenAI-compatible provider via {highlight}baseURL{/highlight} in your config",
"Commit your project's {highlight}AGENTS.md{/highlight} file to Git for team sharing", "Commit your project's {highlight}AGENTS.md{/highlight} file to Git for team sharing",
"Use {highlight}/review{/highlight} to review uncommitted changes, branches, or PRs", "Use {highlight}/review{/highlight} to review uncommitted changes, branches, or PRs",
(shortcuts) => `Use ${commandText("/help", shortcuts.helpShow())} to show the help dialog`, (shortcuts) => `Use ${commandText("/help", shortcuts.helpShow())} to show the help dialog`,
+1 -1
View File
@@ -28,7 +28,7 @@ export const UpgradeCommand = {
const detectedMethod = await Installation.method() const detectedMethod = await Installation.method()
const method = (args.method as Installation.Method) ?? detectedMethod const method = (args.method as Installation.Method) ?? detectedMethod
if (method === "unknown") { if (method === "unknown") {
prompts.log.error(`opencode is installed to ${process.execPath} and may be managed by a package manager`) prompts.log.error(`zmo is installed to ${process.execPath} and may be managed by a package manager`)
const install = await prompts.select({ const install = await prompts.select({
message: "Install anyways?", message: "Install anyways?",
options: [ options: [
+5 -5
View File
@@ -221,8 +221,8 @@ export const layer = Layer.effect(
yield* Effect.promise(() => resolveLoadedPlugins(data, options.path)) yield* Effect.promise(() => resolveLoadedPlugins(data, options.path))
if (!data.$schema) { if (!data.$schema) {
data.$schema = "https://opencode.ai/config.json" data.$schema = "https://zmo.dev/config.json"
const updated = text.replace(/^\s*\{/, '{\n "$schema": "https://opencode.ai/config.json",') const updated = text.replace(/^\s*\{/, '{\n "$schema": "https://zmo.dev/config.json",')
yield* fs.writeFileString(options.path, updated).pipe(Effect.catch(() => Effect.void)) yield* fs.writeFileString(options.path, updated).pipe(Effect.catch(() => Effect.void))
} }
return data return data
@@ -243,7 +243,7 @@ export const layer = Layer.effect(
const file = globalConfigFile() const file = globalConfigFile()
if (!existsSync(file)) { if (!existsSync(file)) {
yield* fs yield* fs
.writeWithDirs(file, JSON.stringify({ $schema: "https://opencode.ai/config.json" }, null, 2)) .writeWithDirs(file, JSON.stringify({ $schema: "https://zmo.dev/config.json" }, null, 2))
.pipe(Effect.catch(() => Effect.void)) .pipe(Effect.catch(() => Effect.void))
} }
} }
@@ -258,7 +258,7 @@ export const layer = Layer.effect(
.then(async (mod) => { .then(async (mod) => {
const { provider, model, ...rest } = mod.default const { provider, model, ...rest } = mod.default
if (provider && model) result.model = `${provider}/${model}` if (provider && model) result.model = `${provider}/${model}`
result["$schema"] = "https://opencode.ai/config.json" result["$schema"] = "https://zmo.dev/config.json"
result = mergeConfig(result, rest) result = mergeConfig(result, rest)
await fsNode.writeFile(path.join(Global.Path.config, "config.json"), JSON.stringify(result, null, 2)) await fsNode.writeFile(path.join(Global.Path.config, "config.json"), JSON.stringify(result, null, 2))
await fsNode.unlink(legacy) await fsNode.unlink(legacy)
@@ -371,7 +371,7 @@ export const layer = Layer.effect(
}) })
: {} : {}
const remoteConfig = mergeConfig(isRecord(wellknown.config) ? wellknown.config : {}, fetchedConfig) const remoteConfig = mergeConfig(isRecord(wellknown.config) ? wellknown.config : {}, fetchedConfig)
if (!remoteConfig.$schema) remoteConfig.$schema = "https://opencode.ai/config.json" if (!remoteConfig.$schema) remoteConfig.$schema = "https://zmo.dev/config.json"
const source = wellknownURL const source = wellknownURL
const next = yield* loadConfig( const next = yield* loadConfig(
JSON.stringify(remoteConfig), JSON.stringify(remoteConfig),
+5 -5
View File
@@ -87,7 +87,7 @@ function buildAuthorizeUrl(redirectUri: string, pkce: PkceCodes, state: string):
id_token_add_organizations: "true", id_token_add_organizations: "true",
codex_cli_simplified_flow: "true", codex_cli_simplified_flow: "true",
state, state,
originator: "opencode", originator: "zmo",
}) })
return `${ISSUER}/oauth/authorize?${params.toString()}` return `${ISSUER}/oauth/authorize?${params.toString()}`
} }
@@ -547,7 +547,7 @@ export async function CodexAuthPlugin(input: PluginInput, options: CodexAuthPlug
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
"User-Agent": `opencode/${InstallationVersion}`, "User-Agent": `zmo/${InstallationVersion}`,
}, },
body: JSON.stringify({ client_id: CLIENT_ID }), body: JSON.stringify({ client_id: CLIENT_ID }),
}) })
@@ -571,7 +571,7 @@ export async function CodexAuthPlugin(input: PluginInput, options: CodexAuthPlug
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
"User-Agent": `opencode/${InstallationVersion}`, "User-Agent": `zmo/${InstallationVersion}`,
}, },
body: JSON.stringify({ body: JSON.stringify({
device_auth_id: deviceData.device_auth_id, device_auth_id: deviceData.device_auth_id,
@@ -630,8 +630,8 @@ export async function CodexAuthPlugin(input: PluginInput, options: CodexAuthPlug
}, },
"chat.headers": async (input, output) => { "chat.headers": async (input, output) => {
if (input.model.providerID !== "openai") return if (input.model.providerID !== "openai") return
output.headers.originator = "opencode" output.headers.originator = "zmo"
output.headers["User-Agent"] = `opencode/${InstallationVersion} (${os.platform()} ${os.release()}; ${os.arch()})` output.headers["User-Agent"] = `zmo/${InstallationVersion} (${os.platform()} ${os.release()}; ${os.arch()})`
output.headers["session-id"] = input.sessionID output.headers["session-id"] = input.sessionID
// Temporary fetch-layer hack: title generation currently shares the conversation // Temporary fetch-layer hack: title generation currently shares the conversation
// session ID, so the OpenAI plugin marks it for HTTP fallback until transport // session ID, so the OpenAI plugin marks it for HTTP fallback until transport
+3 -3
View File
@@ -109,7 +109,7 @@ function authHeaders() {
return { return {
"Content-Type": "application/x-www-form-urlencoded", "Content-Type": "application/x-www-form-urlencoded",
Accept: "application/json", Accept: "application/json",
"User-Agent": `opencode/${InstallationVersion}`, "User-Agent": `zmo/${InstallationVersion}`,
} }
} }
@@ -157,7 +157,7 @@ export function buildAuthorizeUrl(
state, state,
nonce, nonce,
plan: "generic", plan: "generic",
referrer: "opencode", referrer: "zmo",
}) })
return `${options.authorizeUrl ?? AUTHORIZE_URL}?${params.toString()}` return `${options.authorizeUrl ?? AUTHORIZE_URL}?${params.toString()}`
} }
@@ -655,7 +655,7 @@ export async function XaiAuthPlugin(input: PluginInput, options: XaiAuthPluginOp
} }
} }
headers.set("authorization", `Bearer ${currentAuth.access}`) headers.set("authorization", `Bearer ${currentAuth.access}`)
headers.set("User-Agent", `opencode/${InstallationVersion}`) headers.set("User-Agent", `zmo/${InstallationVersion}`)
return fetch(requestInput, { ...init, headers }) return fetch(requestInput, { ...init, headers })
}, },
+19 -19
View File
@@ -435,9 +435,9 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
autoload: false, autoload: false,
options: { options: {
headers: { headers: {
"HTTP-Referer": "https://opencode.ai/", "HTTP-Referer": "https://github.com/helpLogin/zmo-cli",
"X-Title": "opencode", "X-Title": "zmo",
"X-Source": "opencode", "X-Source": "zmo",
}, },
}, },
}), }),
@@ -446,8 +446,8 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
autoload: false, autoload: false,
options: { options: {
headers: { headers: {
"HTTP-Referer": "https://opencode.ai/", "HTTP-Referer": "https://github.com/helpLogin/zmo-cli",
"X-Title": "opencode", "X-Title": "zmo",
}, },
}, },
}), }),
@@ -456,9 +456,9 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
autoload: provider.source === "config", autoload: provider.source === "config",
options: { options: {
headers: { headers: {
"HTTP-Referer": "https://opencode.ai/", "HTTP-Referer": "https://github.com/helpLogin/zmo-cli",
"X-Title": "opencode", "X-Title": "zmo",
"X-BILLING-INVOKE-ORIGIN": "OpenCode", "X-BILLING-INVOKE-ORIGIN": "zmo",
}, },
}, },
}), }),
@@ -467,8 +467,8 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
autoload: false, autoload: false,
options: { options: {
headers: { headers: {
"http-referer": "https://opencode.ai/", "http-referer": "https://github.com/helpLogin/zmo-cli",
"x-title": "opencode", "x-title": "zmo",
}, },
}, },
}), }),
@@ -573,8 +573,8 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
autoload: false, autoload: false,
options: { options: {
headers: { headers: {
"HTTP-Referer": "https://opencode.ai/", "HTTP-Referer": "https://github.com/helpLogin/zmo-cli",
"X-Title": "opencode", "X-Title": "zmo",
}, },
}, },
}), }),
@@ -595,7 +595,7 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
const directory = yield* InstanceState.directory const directory = yield* InstanceState.directory
const aiGatewayHeaders = { const aiGatewayHeaders = {
"User-Agent": `opencode/${InstallationVersion} gitlab-ai-provider/${GITLAB_PROVIDER_VERSION} (${os.platform()} ${os.release()}; ${os.arch()})`, "User-Agent": `zmo/${InstallationVersion} gitlab-ai-provider/${GITLAB_PROVIDER_VERSION} (${os.platform()} ${os.release()}; ${os.arch()})`,
"anthropic-beta": "context-1m-2025-08-07", "anthropic-beta": "context-1m-2025-08-07",
...providerConfig?.options?.aiGatewayHeaders, ...providerConfig?.options?.aiGatewayHeaders,
} }
@@ -743,7 +743,7 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
options: { options: {
apiKey, apiKey,
headers: { headers: {
"User-Agent": `opencode/${InstallationVersion} cloudflare-workers-ai (${os.platform()} ${os.release()}; ${os.arch()})`, "User-Agent": `zmo/${InstallationVersion} cloudflare-workers-ai (${os.platform()} ${os.release()}; ${os.arch()})`,
}, },
}, },
async getModel(sdk: any, modelID: string) { async getModel(sdk: any, modelID: string) {
@@ -788,7 +788,7 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
if (!apiToken) { if (!apiToken) {
throw new Error( throw new Error(
"CLOUDFLARE_API_TOKEN (or CF_AIG_TOKEN) is required for Cloudflare AI Gateway. " + "CLOUDFLARE_API_TOKEN (or CF_AIG_TOKEN) is required for Cloudflare AI Gateway. " +
"Set it via environment variable or run `opencode auth cloudflare-ai-gateway`.", "Set it via environment variable or run `zmo auth cloudflare-ai-gateway`.",
) )
} }
@@ -811,7 +811,7 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
skipCache: input.options?.skipCache, skipCache: input.options?.skipCache,
collectLog: input.options?.collectLog, collectLog: input.options?.collectLog,
headers: { headers: {
"User-Agent": `opencode/${InstallationVersion} cloudflare-ai-gateway (${os.platform()} ${os.release()}; ${os.arch()})`, "User-Agent": `zmo/${InstallationVersion} cloudflare-ai-gateway (${os.platform()} ${os.release()}; ${os.arch()})`,
}, },
} }
@@ -837,7 +837,7 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
autoload: false, autoload: false,
options: { options: {
headers: { headers: {
"X-Cerebras-3rd-Party-Integration": "opencode", "X-Cerebras-3rd-Party-Integration": "zmo",
}, },
}, },
}), }),
@@ -846,8 +846,8 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
autoload: false, autoload: false,
options: { options: {
headers: { headers: {
"HTTP-Referer": "https://opencode.ai/", "HTTP-Referer": "https://github.com/helpLogin/zmo-cli",
"X-Title": "opencode", "X-Title": "zmo",
}, },
}, },
}), }),
+1 -1
View File
@@ -49,7 +49,7 @@ export const layer = Layer.effect(
const ctx = yield* InstanceState.context const ctx = yield* InstanceState.context
return [ return [
[ [
`You are powered by the model named ${model.api.id}. The exact model ID is ${model.providerID}/${model.api.id}`, `You are zmo, an AI coding assistant running in the terminal.`,
`Here is some useful information about the environment you are running in:`, `Here is some useful information about the environment you are running in:`,
`<env>`, `<env>`,
` Working directory: ${ctx.directory}`, ` Working directory: ${ctx.directory}`,