9274282b8979e33bd4894eae0639522402f713ac

Author
Wilhelm Van Der Walt <va3093@gmail.com>
Committer
GitHub <noreply@github.com>
Date

Message

Resolve {env:VAR} and {file:PATH} placeholders in captured API key (#8)

Diff

 1diff --git a/src/api.ts b/src/api.ts
 2index e4ab27852f7174fb20d70d890d49f186a16018cd..aa95c81df5cbb4aee0aa64e8d24583495f178ad3 100644
 3--- a/src/api.ts
 4+++ b/src/api.ts
 5@@ -1,3 +1,5 @@
 6+import { readFileSync } from "node:fs"
 7+
 8 const DEFAULT_MODEL = "claude-haiku-4-5-20251001"
 9 
10 let capturedApiKey: string | undefined
11@@ -6,9 +8,30 @@ export function setCapturedApiKey(key: string) {
12   capturedApiKey = key
13 }
14 
15+// Resolve OpenCode config placeholders like "{env:VAR}" or "{file:/path}".
16+// Returns the input unchanged if no placeholder is present, or an empty
17+// string if a placeholder cannot be resolved.
18+function resolvePlaceholder(value: string): string {
19+  const trimmed = value.trim()
20+  const envMatch = trimmed.match(/^\{env:([^}]+)\}$/)
21+  if (envMatch) return process.env[envMatch[1]]?.trim() ?? ""
22+  const fileMatch = trimmed.match(/^\{file:([^}]+)\}$/)
23+  if (fileMatch) {
24+    try {
25+      return readFileSync(fileMatch[1], "utf8").trim()
26+    } catch {
27+      return ""
28+    }
29+  }
30+  return trimmed
31+}
32+
33 function resolveApiKey(): string {
34-  if (!capturedApiKey) throw new Error("No Anthropic API key available")
35-  return capturedApiKey
36+  const captured = resolvePlaceholder(capturedApiKey ?? "")
37+  if (captured) return captured
38+  const envKey = process.env.ANTHROPIC_API_KEY?.trim()
39+  if (envKey) return envKey
40+  throw new Error("No Anthropic API key available")
41 }
42 
43 function resolveModel(): string {