Skip to content

Commit e1eb62e

Browse files
didacogTarquinen
authored andcommitted
feat: support DCP config in OPENCODE_CONFIG_DIR
1 parent 4b5c3b4 commit e1eb62e

File tree

2 files changed

+57
-5
lines changed

2 files changed

+57
-5
lines changed

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ LLM providers like Anthropic and OpenAI cache prompts based on exact prefix matc
4343

4444
## Configuration
4545

46-
DCP uses its own config file (`~/.config/opencode/dcp.jsonc` or `.opencode/dcp.jsonc`), created automatically on first run.
46+
DCP uses its own config file:
47+
48+
- Global: `~/.config/opencode/dcp.jsonc` (or `dcp.json`), created automatically on first run
49+
- Custom config directory: `$OPENCODE_CONFIG_DIR/dcp.jsonc` (or `dcp.json`), if `OPENCODE_CONFIG_DIR` is set
50+
- Project: `.opencode/dcp.jsonc` (or `dcp.json`) in your project’s `.opencode` directory
4751

4852
<details>
4953
<summary><strong>Default Configuration</strong> (click to expand)</summary>
@@ -104,7 +108,9 @@ The `protectedTools` arrays in each strategy add to this default list.
104108

105109
### Config Precedence
106110

107-
Settings are merged in order: **Defaults****Global** (`~/.config/opencode/dcp.jsonc`) → **Project** (`.opencode/dcp.jsonc`). Each level overrides the previous, so project settings take priority over global, which takes priority over defaults.
111+
Settings are merged in order:
112+
Defaults → Global (`~/.config/opencode/dcp.jsonc`) → Config Dir (`$OPENCODE_CONFIG_DIR/dcp.jsonc`) → Project (`.opencode/dcp.jsonc`).
113+
Each level overrides the previous, so project settings take priority over config-dir and global, which take priority over defaults.
108114

109115
Restart OpenCode after making config changes.
110116

lib/config.ts

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,14 +259,30 @@ function findOpencodeDir(startDir: string): string | null {
259259
return null
260260
}
261261

262-
function getConfigPaths(ctx?: PluginInput): { global: string | null, project: string | null } {
262+
function getConfigPaths(ctx?: PluginInput): { global: string | null, configDir: string | null, project: string | null} {
263+
264+
// Global: ~/.config/opencode/dcp.jsonc|json
263265
let globalPath: string | null = null
264266
if (existsSync(GLOBAL_CONFIG_PATH_JSONC)) {
265267
globalPath = GLOBAL_CONFIG_PATH_JSONC
266268
} else if (existsSync(GLOBAL_CONFIG_PATH_JSON)) {
267269
globalPath = GLOBAL_CONFIG_PATH_JSON
268270
}
269-
271+
272+
// Custom config directory: $OPENCODE_CONFIG_DIR/dcp.jsonc|json
273+
let configDirPath: string | null = null
274+
const opencodeConfigDir = process.env.OPENCODE_CONFIG_DIR
275+
if (opencodeConfigDir) {
276+
const configJsonc = join(opencodeConfigDir, 'dcp.jsonc')
277+
const configJson = join(opencodeConfigDir, 'dcp.json')
278+
if (existsSync(configJsonc)) {
279+
configDirPath = configJsonc
280+
} else if (existsSync(configJson)) {
281+
configDirPath = configJson
282+
}
283+
}
284+
285+
// Project: <project>/.opencode/dcp.jsonc|json
270286
let projectPath: string | null = null
271287
if (ctx?.directory) {
272288
const opencodeDir = findOpencodeDir(ctx.directory)
@@ -281,7 +297,7 @@ function getConfigPaths(ctx?: PluginInput): { global: string | null, project: st
281297
}
282298
}
283299

284-
return { global: globalPath, project: projectPath }
300+
return { global: globalPath, configDir: configDirPath, project: projectPath }
285301
}
286302

287303
function createDefaultConfig(): void {
@@ -425,6 +441,7 @@ function deepCloneConfig(config: PluginConfig): PluginConfig {
425441
}
426442
}
427443

444+
428445
export function getConfig(ctx: PluginInput): PluginConfig {
429446
let config = deepCloneConfig(defaultConfig)
430447
const configPaths = getConfigPaths(ctx)
@@ -461,6 +478,35 @@ export function getConfig(ctx: PluginInput): PluginConfig {
461478
createDefaultConfig()
462479
}
463480

481+
// Load and merge $OPENCODE_CONFIG_DIR/dcp.jsonc|json (overrides global)
482+
if (configPaths.configDir) {
483+
const result = loadConfigFile(configPaths.configDir)
484+
if (result.parseError) {
485+
setTimeout(async () => {
486+
try {
487+
ctx.client.tui.showToast({
488+
body: {
489+
title: "DCP: Invalid configDir config",
490+
message: `${configPaths.configDir}\n${result.parseError}\nUsing global/default values`,
491+
variant: "warning",
492+
duration: 7000
493+
}
494+
})
495+
} catch {}
496+
}, 7000)
497+
} else if (result.data) {
498+
// Validate config keys and types
499+
showConfigValidationWarnings(ctx, configPaths.configDir, result.data, true)
500+
config = {
501+
enabled: result.data.enabled ?? config.enabled,
502+
debug: result.data.debug ?? config.debug,
503+
showUpdateToasts: result.data.showUpdateToasts ?? config.showUpdateToasts,
504+
pruningSummary: result.data.pruningSummary ?? config.pruningSummary,
505+
strategies: mergeStrategies(config.strategies, result.data.strategies as any)
506+
}
507+
}
508+
}
509+
464510
// Load and merge project config (overrides global)
465511
if (configPaths.project) {
466512
const result = loadConfigFile(configPaths.project)

0 commit comments

Comments
 (0)