소스 검색

test: cover TUI config status refinements

maou-shonen 3 달 전
부모
커밋
46fb2829b0
4개의 변경된 파일57개의 추가작업 그리고 4개의 파일을 삭제
  1. 1 1
      docs/configuration.md
  2. 30 0
      src/config/loader.test.ts
  3. 18 1
      src/tui.test.ts
  4. 8 2
      src/tui.ts

+ 1 - 1
docs/configuration.md

@@ -15,7 +15,7 @@ Complete reference for all configuration files and options in oh-my-opencode-sli
 
 > **💡 JSONC recommended:** Use the `.jsonc` extension to add comments and trailing commas. If both `.jsonc` and `.json` exist, `.jsonc` takes precedence.
 
-If OMO-Slim detects an invalid plugin config during OpenCode startup, it falls back to defaults and shows a warning in the TUI sidebar. Run `oh-my-opencode-slim doctor` from your project root for full diagnostics.
+If OMO-Slim detects an invalid plugin config for the current project, the TUI sidebar shows a warning. Run `oh-my-opencode-slim doctor` from your project root for full diagnostics.
 
 ---
 

+ 30 - 0
src/config/loader.test.ts

@@ -387,6 +387,36 @@ describe('onWarning callback', () => {
     expect(config.agents?.oracle?.model).toBe('root');
   });
 
+  test('silent: true on missing preset still calls onWarning but not console.warn', () => {
+    const projectDir = path.join(tempDir, 'project');
+    const projectConfigDir = path.join(projectDir, '.opencode');
+    fs.mkdirSync(projectConfigDir, { recursive: true });
+    fs.writeFileSync(
+      path.join(projectConfigDir, 'oh-my-opencode-slim.json'),
+      JSON.stringify({
+        preset: 'nonexistent',
+        presets: { other: { oracle: { model: 'other' } } },
+        agents: { oracle: { model: 'root' } },
+      }),
+    );
+
+    const warnSpy = spyOn(console, 'warn').mockImplementation(() => {});
+    try {
+      const warnings: ConfigLoadWarning[] = [];
+      const config = loadPluginConfig(projectDir, {
+        silent: true,
+        onWarning: (warning) => warnings.push(warning),
+      });
+
+      expect(warnings).toHaveLength(1);
+      expect(warnings[0]?.kind).toBe('missing-preset');
+      expect(config.agents?.oracle?.model).toBe('root');
+      expect(warnSpy).not.toHaveBeenCalled();
+    } finally {
+      warnSpy.mockRestore();
+    }
+  });
+
   test('valid config does not call onWarning', () => {
     const projectDir = path.join(tempDir, 'project');
     const projectConfigDir = path.join(projectDir, '.opencode');

+ 18 - 1
src/tui.test.ts

@@ -1,4 +1,4 @@
-import { describe, expect, test } from 'bun:test';
+import { afterEach, beforeEach, describe, expect, test } from 'bun:test';
 import * as fs from 'node:fs';
 import * as os from 'node:os';
 import * as path from 'node:path';
@@ -61,6 +61,23 @@ describe('formatSidebarModelName', () => {
 });
 
 describe('readConfigInvalid', () => {
+  let originalEnv: typeof process.env;
+  let configHome: string;
+
+  beforeEach(() => {
+    originalEnv = { ...process.env };
+    // Isolate from real user config and env presets
+    delete process.env.OPENCODE_CONFIG_DIR;
+    delete process.env.OH_MY_OPENCODE_SLIM_PRESET;
+    configHome = fs.mkdtempSync(path.join(os.tmpdir(), 'omos-tui-env-'));
+    process.env.XDG_CONFIG_HOME = configHome;
+  });
+
+  afterEach(() => {
+    fs.rmSync(configHome, { recursive: true, force: true });
+    process.env = originalEnv;
+  });
+
   test('detects invalid config from the current directory without persisted state', () => {
     const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'omos-tui-'));
     try {

+ 8 - 2
src/tui.ts

@@ -65,6 +65,12 @@ function truncate(value: string, max = 24): string {
   return value.length > max ? `${value.slice(0, max - 1)}…` : value;
 }
 
+function getTuiDirectory(api: {
+  state?: { path?: { directory?: string } };
+}): string {
+  return api.state?.path?.directory ?? process.cwd();
+}
+
 export function formatSidebarModelName(model: string): string {
   const lastSlash = model.lastIndexOf('/');
   return lastSlash === -1 ? model : model.slice(lastSlash + 1);
@@ -185,13 +191,13 @@ const plugin: TuiPluginModule & { id: string } = {
   id: `${PLUGIN_NAME}:tui`,
   tui: async (api, _options, meta) => {
     const version = meta.version ?? (await readPackageVersion()) ?? 'dev';
-    let configDirectory = api.state.path.directory;
+    let configDirectory = getTuiDirectory(api);
     let configInvalid = readConfigInvalid(configDirectory);
     let snapshot = readTuiSnapshot();
     const renderTimer = setInterval(async () => {
       try {
         snapshot = await readTuiSnapshotAsync();
-        const currentDirectory = api.state.path.directory;
+        const currentDirectory = getTuiDirectory(api);
         if (currentDirectory !== configDirectory) {
           configDirectory = currentDirectory;
           configInvalid = readConfigInvalid(configDirectory);