Skip to content

Commit 1530983

Browse files
DhruvBhatia0claude
andauthored
feat: allow API key via opencode config file (#11) (#22)
Desktop users can set `morph.apiKey` in opencode.json instead of the MORPH_API_KEY env var. Env var still takes precedence. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 79dcb11 commit 1530983

2 files changed

Lines changed: 45 additions & 31 deletions

File tree

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ export MORPH_API_KEY="sk-..."
2727

2828
Add this to your shell profile (`~/.zshrc`, `~/.bashrc`, etc.) so it persists.
2929

30+
Alternatively (handy for desktop users who can't set env vars), put the key
31+
directly in `opencode.json` — the `MORPH_API_KEY` env var takes precedence when both are set:
32+
33+
```json
34+
{
35+
"morph": { "apiKey": "sk-..." }
36+
}
37+
```
38+
3039
### 2. Install the plugin
3140

3241
```bash

index.ts

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ import type { WarpGrepResult, CompactResult } from "@morphllm/morphsdk";
1313
import type { Part, TextPart, ToolPart, Message } from "@opencode-ai/sdk";
1414
import { isAbsolute, resolve as resolvePath } from "node:path";
1515

16-
// Config from environment — only MORPH_API_KEY is required
17-
const MORPH_API_KEY = process.env.MORPH_API_KEY;
16+
// API key from MORPH_API_KEY env var, or the `morph.apiKey` field in
17+
// opencode config (resolved during plugin init for desktop users).
18+
let MORPH_API_KEY = process.env.MORPH_API_KEY;
1819
const MORPH_API_URL = "https://api.morphllm.com";
1920
const MORPH_TIMEOUT = 30000;
2021
const MORPH_WARP_GREP_TIMEOUT = 60000;
@@ -75,37 +76,30 @@ const EXISTING_CODE_MARKER = "// ... existing code ...";
7576
const MORPH_ROUTING_HINT_HEADER = "Morph plugin routing hints:";
7677

7778
/**
78-
* Shared MorphClient — FastApply uses morph.fastApply.applyEdit()
79-
* with MORPH_API_URL passed as per-call override.
79+
* Morph SDK clients (FastApply, WarpGrep, Compact). Built by initMorphClients()
80+
* once MORPH_API_KEY is known — at module load for the env var, and again during
81+
* plugin init if the key comes from opencode config.
8082
*/
81-
const morph = MORPH_API_KEY
82-
? new MorphClient({
83-
apiKey: MORPH_API_KEY,
84-
timeout: MORPH_TIMEOUT,
85-
})
86-
: null;
83+
let morph: MorphClient | null = null;
84+
let warpGrep: WarpGrepClient | null = null;
85+
let compactClient: CompactClient | null = null;
86+
87+
function initMorphClients() {
88+
if (!MORPH_API_KEY) return;
89+
morph = new MorphClient({ apiKey: MORPH_API_KEY, timeout: MORPH_TIMEOUT });
90+
warpGrep = new WarpGrepClient({
91+
morphApiKey: MORPH_API_KEY,
92+
morphApiUrl: MORPH_API_URL,
93+
timeout: MORPH_WARP_GREP_TIMEOUT,
94+
});
95+
compactClient = new CompactClient({
96+
morphApiKey: MORPH_API_KEY,
97+
morphApiUrl: MORPH_API_URL,
98+
timeout: MORPH_COMPACT_TIMEOUT,
99+
});
100+
}
87101

88-
/**
89-
* Separate WarpGrep client with its own timeout (typically longer than fast apply).
90-
*/
91-
const warpGrep = MORPH_API_KEY
92-
? new WarpGrepClient({
93-
morphApiKey: MORPH_API_KEY,
94-
morphApiUrl: MORPH_API_URL,
95-
timeout: MORPH_WARP_GREP_TIMEOUT,
96-
})
97-
: null;
98-
99-
/**
100-
* Separate CompactClient for context compaction.
101-
*/
102-
const compactClient = MORPH_API_KEY
103-
? new CompactClient({
104-
morphApiKey: MORPH_API_KEY,
105-
morphApiUrl: MORPH_API_URL,
106-
timeout: MORPH_COMPACT_TIMEOUT,
107-
})
108-
: null;
102+
initMorphClients();
109103

110104
/**
111105
* Model context window size in tokens. Updated from chat.params hook.
@@ -752,6 +746,17 @@ const MorphPlugin: Plugin = async ({ directory, worktree, client }) => {
752746
} catch {}
753747
};
754748

749+
// Fall back to the `morph.apiKey` field in opencode config (for desktop
750+
// users who can't set env vars). Env var still takes precedence.
751+
if (!MORPH_API_KEY) {
752+
const cfg = await client.config?.get().catch(() => null);
753+
const key = (cfg?.data as { morph?: { apiKey?: string } })?.morph?.apiKey;
754+
if (key) {
755+
MORPH_API_KEY = key;
756+
initMorphClients();
757+
}
758+
}
759+
755760
if (!MORPH_API_KEY) {
756761
await log(
757762
"warn",

0 commit comments

Comments
 (0)