feat(opencode): Windows PowerShell installer and Desktop key file
CLI and Desktop share %USERPROFILE%\.config\opencode. Persist the API key in .arka-api-key so GUI apps do not need a login-shell export.
This commit is contained in:
1 parent
3e440b9365
commit
cb17ce8d2a
6 files changed
+531
-12
No files matched your search
@@ -6,9 +6,35 @@ const PROVIDER_ID = "Arka-AI"
|
||||
const API_URL = "https://api.arka-ai.ru/v1"
|
||||
const CATALOG_URL =
|
||||
"https://git.arka-ai.ru/arka/public/raw/branch/main/opencode/catalog.json"
|
||||
const CACHE_FILE = join(homedir(), ".cache", "opencode", "arka-ai-models.json")
|
||||
const TTL_MS = 24 * 60 * 60 * 1000
|
||||
|
||||
function configDir(): string {
|
||||
const xdg = process.env.XDG_CONFIG_HOME
|
||||
if (xdg) return join(xdg, "opencode")
|
||||
return join(homedir(), ".config", "opencode")
|
||||
}
|
||||
|
||||
function cacheDir(): string {
|
||||
const xdg = process.env.XDG_CACHE_HOME
|
||||
if (xdg) return join(xdg, "opencode")
|
||||
return join(homedir(), ".cache", "opencode")
|
||||
}
|
||||
|
||||
const CACHE_FILE = join(cacheDir(), "arka-ai-models.json")
|
||||
const KEY_FILE = join(configDir(), ".arka-api-key")
|
||||
|
||||
function readApiKey(): string | undefined {
|
||||
const fromEnv = process.env.ARKA_API_KEY?.trim()
|
||||
if (fromEnv) return fromEnv
|
||||
try {
|
||||
if (existsSync(KEY_FILE)) {
|
||||
const fromFile = readFileSync(KEY_FILE, "utf8").trim()
|
||||
if (fromFile) return fromFile
|
||||
}
|
||||
} catch {}
|
||||
return undefined
|
||||
}
|
||||
|
||||
// Ids that must always be exposed, even if the filter would drop them.
|
||||
const FORCED_MODELS = [
|
||||
"DeepSeek-V4-Pro",
|
||||
@@ -50,7 +76,7 @@ function loadCache(): Cache | null {
|
||||
|
||||
function saveCache(models: ModelMap): void {
|
||||
try {
|
||||
mkdirSync(join(homedir(), ".cache", "opencode"), { recursive: true })
|
||||
mkdirSync(cacheDir(), { recursive: true })
|
||||
writeFileSync(CACHE_FILE, JSON.stringify({ ts: Date.now(), models }))
|
||||
} catch {}
|
||||
}
|
||||
@@ -99,7 +125,7 @@ async function resolveModels(): Promise<ModelMap | null> {
|
||||
} catch {}
|
||||
|
||||
try {
|
||||
const key = process.env.ARKA_API_KEY
|
||||
const key = readApiKey()
|
||||
const json = await fetchJson(
|
||||
`${API_URL}/models`,
|
||||
key ? { Authorization: `Bearer ${key}` } : {},
|
||||
@@ -115,6 +141,7 @@ async function resolveModels(): Promise<ModelMap | null> {
|
||||
|
||||
export default async function ArkaAIProviderPlugin() {
|
||||
const models = await resolveModels()
|
||||
const apiKey = readApiKey()
|
||||
|
||||
return {
|
||||
config: (cfg: any) => {
|
||||
@@ -124,12 +151,18 @@ export default async function ArkaAIProviderPlugin() {
|
||||
// Static models from opencode.json act as a fallback; the fetched
|
||||
// catalog is layered on top so the configured default model never
|
||||
// disappears even if the catalog drops it.
|
||||
// apiKey from env or ~/.config/opencode/.arka-api-key so Desktop /
|
||||
// Windows GUI works without a login-shell export.
|
||||
cfg.provider[PROVIDER_ID] = {
|
||||
name: "Arka-AI",
|
||||
api: API_URL,
|
||||
env: ["ARKA_API_KEY"],
|
||||
...prev,
|
||||
models: { ...(prev.models ?? {}), ...(models ?? {}) },
|
||||
options: {
|
||||
...(prev.options ?? {}),
|
||||
...(apiKey ? { apiKey } : {}),
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user