2026-02-08 22:35:16 +09:00
|
|
|
import { readFileSync, writeFileSync } from "node:fs"
|
2026-02-08 15:01:42 +09:00
|
|
|
import type { ConfigMergeResult, InstallConfig } from "../types"
|
|
|
|
|
import { getConfigDir } from "./config-context"
|
|
|
|
|
import { ensureConfigDirectoryExists } from "./ensure-config-directory-exists"
|
|
|
|
|
import { formatErrorWithSuggestion } from "./format-error-with-suggestion"
|
|
|
|
|
import { detectConfigFormat } from "./opencode-config-format"
|
|
|
|
|
import { parseOpenCodeConfigFileWithError, type OpenCodeConfig } from "./parse-opencode-config-file"
|
|
|
|
|
import { ANTIGRAVITY_PROVIDER_CONFIG } from "./antigravity-provider-configuration"
|
|
|
|
|
|
|
|
|
|
export function addProviderConfig(config: InstallConfig): ConfigMergeResult {
|
|
|
|
|
try {
|
|
|
|
|
ensureConfigDirectoryExists()
|
|
|
|
|
} catch (err) {
|
|
|
|
|
return {
|
|
|
|
|
success: false,
|
|
|
|
|
configPath: getConfigDir(),
|
|
|
|
|
error: formatErrorWithSuggestion(err, "create config directory"),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { format, path } = detectConfigFormat()
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
let existingConfig: OpenCodeConfig | null = null
|
|
|
|
|
if (format !== "none") {
|
|
|
|
|
const parseResult = parseOpenCodeConfigFileWithError(path)
|
|
|
|
|
if (parseResult.error && !parseResult.config) {
|
2026-02-08 15:31:32 +09:00
|
|
|
return {
|
|
|
|
|
success: false,
|
|
|
|
|
configPath: path,
|
|
|
|
|
error: `Failed to parse config file: ${parseResult.error}`,
|
|
|
|
|
}
|
2026-02-08 15:01:42 +09:00
|
|
|
}
|
2026-02-08 15:31:32 +09:00
|
|
|
existingConfig = parseResult.config
|
2026-02-08 15:01:42 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const newConfig = { ...(existingConfig ?? {}) }
|
|
|
|
|
const providers = (newConfig.provider ?? {}) as Record<string, unknown>
|
|
|
|
|
|
|
|
|
|
if (config.hasGemini) {
|
|
|
|
|
providers.google = ANTIGRAVITY_PROVIDER_CONFIG.google
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Object.keys(providers).length > 0) {
|
|
|
|
|
newConfig.provider = providers
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-08 22:35:16 +09:00
|
|
|
if (format === "jsonc") {
|
|
|
|
|
const content = readFileSync(path, "utf-8")
|
|
|
|
|
const providerJson = JSON.stringify(newConfig.provider, null, 2)
|
|
|
|
|
.split("\n")
|
|
|
|
|
.map((line, i) => (i === 0 ? line : ` ${line}`))
|
|
|
|
|
.join("\n")
|
2026-02-08 22:38:51 +09:00
|
|
|
// Match "provider" key with any indentation and nested brace depth
|
|
|
|
|
const providerIdx = content.indexOf('"provider"')
|
|
|
|
|
if (providerIdx !== -1) {
|
|
|
|
|
const colonIdx = content.indexOf(":", providerIdx + '"provider"'.length)
|
2026-02-08 22:43:02 +09:00
|
|
|
const braceStart = colonIdx !== -1 ? content.indexOf("{", colonIdx) : -1
|
|
|
|
|
if (braceStart === -1) {
|
|
|
|
|
writeFileSync(path, JSON.stringify(newConfig, null, 2) + "\n")
|
|
|
|
|
} else {
|
|
|
|
|
let depth = 0
|
|
|
|
|
let braceEnd = braceStart
|
2026-02-09 11:59:50 +09:00
|
|
|
let inString = false
|
|
|
|
|
let escape = false
|
2026-02-08 22:43:02 +09:00
|
|
|
for (let i = braceStart; i < content.length; i++) {
|
2026-02-09 11:59:50 +09:00
|
|
|
const ch = content[i]
|
|
|
|
|
if (escape) {
|
|
|
|
|
escape = false
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if (ch === "\\") {
|
|
|
|
|
escape = true
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if (ch === '"') {
|
|
|
|
|
inString = !inString
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if (inString) continue
|
|
|
|
|
if (ch === "{") depth++
|
|
|
|
|
else if (ch === "}") {
|
2026-02-08 22:43:02 +09:00
|
|
|
depth--
|
|
|
|
|
if (depth === 0) {
|
|
|
|
|
braceEnd = i
|
|
|
|
|
break
|
|
|
|
|
}
|
2026-02-08 22:38:51 +09:00
|
|
|
}
|
|
|
|
|
}
|
2026-02-08 22:43:02 +09:00
|
|
|
const newContent =
|
|
|
|
|
content.slice(0, providerIdx) +
|
|
|
|
|
`"provider": ${providerJson}` +
|
|
|
|
|
content.slice(braceEnd + 1)
|
|
|
|
|
writeFileSync(path, newContent)
|
2026-02-08 22:38:51 +09:00
|
|
|
}
|
2026-02-08 22:35:16 +09:00
|
|
|
} else {
|
|
|
|
|
const newContent = content.replace(/(\{)/, `$1\n "provider": ${providerJson},`)
|
|
|
|
|
writeFileSync(path, newContent)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
writeFileSync(path, JSON.stringify(newConfig, null, 2) + "\n")
|
|
|
|
|
}
|
2026-02-08 15:01:42 +09:00
|
|
|
return { success: true, configPath: path }
|
|
|
|
|
} catch (err) {
|
|
|
|
|
return {
|
|
|
|
|
success: false,
|
|
|
|
|
configPath: path,
|
|
|
|
|
error: formatErrorWithSuggestion(err, "add provider config"),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|