Skip to content

Commit 6b914af

Browse files
committed
review
1 parent bc0462c commit 6b914af

3 files changed

Lines changed: 90 additions & 7 deletions

File tree

src/cli/install.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ function handleStepResult(result: ConfigMergeResult, successMsg: string): boolea
8282

8383
function formatConfigSummary(config: InstallConfig): string {
8484
const liteConfig = generateLiteConfig(config)
85-
const preset = liteConfig.preset as string
85+
const preset = (liteConfig.preset as string) || "unknown"
8686

8787
const lines: string[] = []
8888
lines.push(`${BOLD}Configuration Summary${RESET}`)
@@ -97,9 +97,9 @@ function formatConfigSummary(config: InstallConfig): string {
9797

9898
function printAgentModels(config: InstallConfig): void {
9999
const liteConfig = generateLiteConfig(config)
100-
const presetName = liteConfig.preset as string
100+
const presetName = (liteConfig.preset as string) || "unknown"
101101
const presets = liteConfig.presets as Record<string, any>
102-
const agents = presets[presetName] as Record<string, { model: string; skills: string[] }>
102+
const agents = presets?.[presetName] as Record<string, { model: string; skills: string[] }>
103103

104104
if (!agents || Object.keys(agents).length === 0) return
105105

src/config/loader.test.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,52 @@ describe("preset resolution", () => {
391391
// Should return empty config due to validation failure
392392
expect(loadPluginConfig(projectDir)).toEqual({})
393393
})
394+
395+
test("nonexistent preset from config warns and falls back to root agents", () => {
396+
const projectDir = path.join(tempDir, "project")
397+
const projectConfigDir = path.join(projectDir, ".opencode")
398+
fs.mkdirSync(projectConfigDir, { recursive: true })
399+
fs.writeFileSync(
400+
path.join(projectConfigDir, "oh-my-opencode-slim.json"),
401+
JSON.stringify({
402+
preset: "nonexistent",
403+
presets: {
404+
other: { oracle: { model: "other" } }
405+
},
406+
agents: { oracle: { model: "root" } }
407+
})
408+
)
409+
410+
const consoleWarnSpy = spyOn(console, "warn")
411+
const config = loadPluginConfig(projectDir)
412+
expect(config.agents?.oracle?.model).toBe("root")
413+
expect(consoleWarnSpy).toHaveBeenCalled()
414+
const warningMessage = consoleWarnSpy.mock.calls[0][0] as string
415+
expect(warningMessage).toContain('Preset "nonexistent" not found')
416+
expect(warningMessage).toContain('Available presets: other')
417+
})
418+
419+
test("nonexistent preset with no root agents returns empty agents", () => {
420+
const projectDir = path.join(tempDir, "project")
421+
const projectConfigDir = path.join(projectDir, ".opencode")
422+
fs.mkdirSync(projectConfigDir, { recursive: true })
423+
fs.writeFileSync(
424+
path.join(projectConfigDir, "oh-my-opencode-slim.json"),
425+
JSON.stringify({
426+
preset: "nonexistent",
427+
presets: {
428+
other: { oracle: { model: "other" } }
429+
}
430+
})
431+
)
432+
433+
const consoleWarnSpy = spyOn(console, "warn")
434+
const config = loadPluginConfig(projectDir)
435+
expect(config.agents).toBeUndefined()
436+
expect(consoleWarnSpy).toHaveBeenCalled()
437+
const warningMessage = consoleWarnSpy.mock.calls[0][0] as string
438+
expect(warningMessage).toContain('Preset "nonexistent" not found')
439+
})
394440
})
395441

396442
describe("environment variable preset override", () => {
@@ -487,4 +533,34 @@ describe("environment variable preset override", () => {
487533
expect(config.preset).toBe("config-preset")
488534
expect(config.agents?.oracle?.model).toBe("config-model")
489535
})
536+
537+
test("Env var with nonexistent preset warns and falls back", () => {
538+
const projectDir = path.join(tempDir, "project")
539+
const projectConfigDir = path.join(projectDir, ".opencode")
540+
fs.mkdirSync(projectConfigDir, { recursive: true })
541+
fs.writeFileSync(
542+
path.join(projectConfigDir, "oh-my-opencode-slim.json"),
543+
JSON.stringify({
544+
preset: "config-preset",
545+
presets: {
546+
"config-preset": { oracle: { model: "config-model" } }
547+
},
548+
agents: { oracle: { model: "fallback" } }
549+
})
550+
)
551+
552+
process.env.OH_MY_OPENCODE_SLIM_PRESET = "typo-preset"
553+
const consoleWarnSpy = spyOn(console, "warn")
554+
const config = loadPluginConfig(projectDir)
555+
expect(config.preset).toBe("typo-preset")
556+
expect(config.agents?.oracle?.model).toBe("fallback")
557+
expect(consoleWarnSpy).toHaveBeenCalled()
558+
const calls = consoleWarnSpy.mock.calls as string[][]
559+
const warningMessage = calls.find(call =>
560+
call[0]?.includes("typo-preset")
561+
)?.[0] || ""
562+
expect(warningMessage).toContain('Preset "typo-preset" not found')
563+
expect(warningMessage).toContain('environment variable')
564+
expect(warningMessage).toContain('config-preset')
565+
})
490566
})

src/config/loader.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,17 @@ export function loadPluginConfig(directory: string): PluginConfig {
119119
}
120120

121121
// Resolve preset and merge with root agents
122-
if (config.preset && config.presets?.[config.preset]) {
123-
const preset = config.presets[config.preset];
124-
// Merge preset agents with root agents (root overrides)
125-
config.agents = deepMerge(preset, config.agents);
122+
if (config.preset) {
123+
const preset = config.presets?.[config.preset];
124+
if (preset) {
125+
// Merge preset agents with root agents (root overrides)
126+
config.agents = deepMerge(preset, config.agents);
127+
} else {
128+
// Preset name specified but doesn't exist - warn user
129+
const presetSource = envPreset === config.preset ? "environment variable" : "config file";
130+
const availablePresets = config.presets ? Object.keys(config.presets).join(", ") : "none";
131+
console.warn(`[oh-my-opencode-slim] Preset "${config.preset}" not found (from ${presetSource}). Available presets: ${availablePresets}`);
132+
}
126133
}
127134

128135
return config;

0 commit comments

Comments
 (0)