Browse Source

Refine TUI sidebar

Alvin Unreal 3 months ago
parent
commit
82fa4fc354
5 changed files with 44 additions and 41 deletions
  1. 3 4
      README.md
  2. 3 2
      src/hooks/task-session-manager/index.ts
  3. 21 10
      src/tui-state.ts
  4. 1 0
      src/tui.test.ts
  5. 16 25
      src/tui.ts

+ 3 - 4
README.md

@@ -38,10 +38,9 @@ bunx oh-my-opencode-slim@latest install
 ```
 
 The installer also registers the companion TUI plugin in OpenCode's
-`tui.json`, which adds an `OMOS <version>` badge beside the prompt and a small
-sidebar showing specialist-agent status plus active/reusable task sessions. For
-manual setups, add `oh-my-opencode-slim` to the `plugin` array in both
-`opencode.json` and `tui.json`.
+`tui.json`, which adds a small sidebar showing specialist-agent status plus
+active/reusable task sessions. For manual setups, add `oh-my-opencode-slim` to
+the `plugin` array in both `opencode.json` and `tui.json`.
 
 ### Getting Started
 

+ 3 - 2
src/hooks/task-session-manager/index.ts

@@ -189,10 +189,11 @@ export function createTaskSessionManagerHook(
 
   function pendingCallId(input: {
     callID?: string;
-    sessionID: string;
+    sessionID?: string;
   }): string {
     return (
-      input.callID ?? `${input.sessionID}:anonymous-${++anonymousPendingCallId}`
+      input.callID ??
+      `${input.sessionID ?? 'unknown'}:anonymous-${++anonymousPendingCallId}`
     );
   }
 

+ 21 - 10
src/tui-state.ts

@@ -29,18 +29,29 @@ function emptySnapshot(): TuiSnapshot {
   };
 }
 
+function parseSnapshot(value: string): TuiSnapshot {
+  const parsed = JSON.parse(value) as Partial<TuiSnapshot> | undefined;
+  if (parsed?.version !== 1) return emptySnapshot();
+
+  return {
+    version: 1,
+    updatedAt:
+      typeof parsed.updatedAt === 'number' ? parsed.updatedAt : Date.now(),
+    agentModels: parsed.agentModels ?? {},
+  };
+}
+
 export function readTuiSnapshot(): TuiSnapshot {
   try {
-    const parsed = JSON.parse(fs.readFileSync(getTuiStatePath(), 'utf8')) as
-      | Partial<TuiSnapshot>
-      | undefined;
-    if (parsed?.version !== 1) return emptySnapshot();
-    return {
-      version: 1,
-      updatedAt:
-        typeof parsed.updatedAt === 'number' ? parsed.updatedAt : Date.now(),
-      agentModels: parsed.agentModels ?? {},
-    };
+    return parseSnapshot(fs.readFileSync(getTuiStatePath(), 'utf8'));
+  } catch {
+    return emptySnapshot();
+  }
+}
+
+export async function readTuiSnapshotAsync(): Promise<TuiSnapshot> {
+  try {
+    return parseSnapshot(await fs.promises.readFile(getTuiStatePath(), 'utf8'));
   } catch {
     return emptySnapshot();
   }

+ 1 - 0
src/tui.test.ts

@@ -30,6 +30,7 @@ describe('tui sidebar agents', () => {
     expect(agentNames).toContain('explorer');
     expect(agentNames).toContain('fixer');
     expect(agentNames).not.toContain('observer');
+    expect(agentNames).not.toContain('council');
     expect(agentNames).not.toContain('councillor');
   });
 });

+ 16 - 25
src/tui.ts

@@ -2,12 +2,18 @@ import type { TuiPluginModule } from '@opencode-ai/plugin/tui';
 import type { JSX } from '@opentui/solid';
 import { createElement, insert, setProp } from '@opentui/solid';
 import { DEFAULT_DISABLED_AGENTS, SUBAGENT_NAMES } from './config/constants';
-import { readTuiSnapshot, type TuiSnapshot } from './tui-state';
+import {
+  readTuiSnapshot,
+  readTuiSnapshotAsync,
+  type TuiSnapshot,
+} from './tui-state';
 
 const PLUGIN_NAME = 'oh-my-opencode-slim';
-const PLUGIN_LABEL = 'OMOS';
 const FALLBACK_SIDEBAR_AGENTS = SUBAGENT_NAMES.filter(
-  (agent) => agent !== 'councillor' && !DEFAULT_DISABLED_AGENTS.includes(agent),
+  (agent) =>
+    agent !== 'councillor' &&
+    agent !== 'council' &&
+    !DEFAULT_DISABLED_AGENTS.includes(agent),
 );
 const BORDER = { type: 'single' };
 
@@ -87,7 +93,7 @@ function row(
 
 function renderSidebar(
   snapshot: TuiSnapshot,
-  versionText: string,
+  version: string,
   theme: {
     accent: unknown;
     background: unknown;
@@ -118,11 +124,9 @@ function renderSidebar(
         [
           box(
             { paddingLeft: 1, paddingRight: 1, backgroundColor: theme.accent },
-            [text({ fg: theme.background }, ['Oh My OpenCode Slim'])],
+            [text({ fg: theme.background }, ['OMO-Slim'])],
           ),
-          text({ fg: theme.textMuted }, [
-            versionText.replace(`${PLUGIN_LABEL} `, 'v'),
-          ]),
+          text({ fg: theme.textMuted }, [`v${version}`]),
         ],
       ),
       box({ width: '100%', marginTop: 1 }, [
@@ -145,9 +149,10 @@ const plugin: TuiPluginModule & { id: string } = {
   id: `${PLUGIN_NAME}:tui`,
   tui: async (api, _options, meta) => {
     const version = meta.version ?? (await readPackageVersion()) ?? 'dev';
-    const versionText = `${PLUGIN_LABEL} ${version}`;
-    const renderTimer = setInterval(() => {
+    let snapshot = readTuiSnapshot();
+    const renderTimer = setInterval(async () => {
       try {
+        snapshot = await readTuiSnapshotAsync();
         api.renderer.requestRender();
       } catch {
         // Ignore render errors; this is best-effort live status.
@@ -161,22 +166,8 @@ const plugin: TuiPluginModule & { id: string } = {
     api.slots.register({
       order: 900,
       slots: {
-        home_prompt_right() {
-          const theme = api.theme.current;
-
-          return text({ fg: theme.textMuted }, [versionText]);
-        },
-        session_prompt_right() {
-          const theme = api.theme.current;
-
-          return text({ fg: theme.textMuted }, [versionText]);
-        },
         sidebar_content() {
-          return renderSidebar(
-            readTuiSnapshot(),
-            versionText,
-            api.theme.current,
-          );
+          return renderSidebar(snapshot, version, api.theme.current);
         },
       },
     });