Skip to content

Commit c517f0c

Browse files
committed
feat: support DCP config in OPENCODE_CONFIG_DIR
1 parent cecaff1 commit c517f0c

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>
@@ -108,7 +112,9 @@ The `protectedTools` arrays in each strategy add to this default list.
108112

109113
### Config Precedence
110114

111-
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.
115+
Settings are merged in order:
116+
Defaults → Global (`~/.config/opencode/dcp.jsonc`) → Config Dir (`$OPENCODE_CONFIG_DIR/dcp.jsonc`) → Project (`.opencode/dcp.jsonc`).
117+
Each level overrides the previous, so project settings take priority over config-dir and global, which take priority over defaults.
112118

113119
Restart OpenCode after making config changes.
114120

lib/config.ts

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -275,14 +275,30 @@ function findOpencodeDir(startDir: string): string | null {
275275
return null
276276
}
277277

278-
function getConfigPaths(ctx?: PluginInput): { global: string | null, project: string | null } {
278+
function getConfigPaths(ctx?: PluginInput): { global: string | null, configDir: string | null, project: string | null} {
279+
280+
// Global: ~/.config/opencode/dcp.jsonc|json
279281
let globalPath: string | null = null
280282
if (existsSync(GLOBAL_CONFIG_PATH_JSONC)) {
281283
globalPath = GLOBAL_CONFIG_PATH_JSONC
282284
} else if (existsSync(GLOBAL_CONFIG_PATH_JSON)) {
283285
globalPath = GLOBAL_CONFIG_PATH_JSON
284286
}
285-
287+
288+
// Custom config directory: $OPENCODE_CONFIG_DIR/dcp.jsonc|json
289+
let configDirPath: string | null = null
290+
const opencodeConfigDir = process.env.OPENCODE_CONFIG_DIR
291+
if (opencodeConfigDir) {
292+
const configJsonc = join(opencodeConfigDir, 'dcp.jsonc')
293+
const configJson = join(opencodeConfigDir, 'dcp.json')
294+
if (existsSync(configJsonc)) {
295+
configDirPath = configJsonc
296+
} else if (existsSync(configJson)) {
297+
configDirPath = configJson
298+
}
299+
}
300+
301+
// Project: <project>/.opencode/dcp.jsonc|json
286302
let projectPath: string | null = null
287303
if (ctx?.directory) {
288304
const opencodeDir = findOpencodeDir(ctx.directory)
@@ -297,7 +313,7 @@ function getConfigPaths(ctx?: PluginInput): { global: string | null, project: st
297313
}
298314
}
299315

300-
return { global: globalPath, project: projectPath }
316+
return { global: globalPath, configDir: configDirPath, project: projectPath }
301317
}
302318

303319
function createDefaultConfig(): void {
@@ -449,6 +465,7 @@ function deepCloneConfig(config: PluginConfig): PluginConfig {
449465
}
450466
}
451467

468+
452469
export function getConfig(ctx: PluginInput): PluginConfig {
453470
let config = deepCloneConfig(defaultConfig)
454471
const configPaths = getConfigPaths(ctx)
@@ -485,6 +502,35 @@ export function getConfig(ctx: PluginInput): PluginConfig {
485502
createDefaultConfig()
486503
}
487504

505+
// Load and merge $OPENCODE_CONFIG_DIR/dcp.jsonc|json (overrides global)
506+
if (configPaths.configDir) {
507+
const result = loadConfigFile(configPaths.configDir)
508+
if (result.parseError) {
509+
setTimeout(async () => {
510+
try {
511+
ctx.client.tui.showToast({
512+
body: {
513+
title: "DCP: Invalid configDir config",
514+
message: `${configPaths.configDir}\n${result.parseError}\nUsing global/default values`,
515+
variant: "warning",
516+
duration: 7000
517+
}
518+
})
519+
} catch {}
520+
}, 7000)
521+
} else if (result.data) {
522+
// Validate config keys and types
523+
showConfigValidationWarnings(ctx, configPaths.configDir, result.data, true)
524+
config = {
525+
enabled: result.data.enabled ?? config.enabled,
526+
debug: result.data.debug ?? config.debug,
527+
showUpdateToasts: result.data.showUpdateToasts ?? config.showUpdateToasts,
528+
pruningSummary: result.data.pruningSummary ?? config.pruningSummary,
529+
strategies: mergeStrategies(config.strategies, result.data.strategies as any)
530+
}
531+
}
532+
}
533+
488534
// Load and merge project config (overrides global)
489535
if (configPaths.project) {
490536
const result = loadConfigFile(configPaths.project)

0 commit comments

Comments
 (0)