Browse Source

refactor: extract shared per-session server creation helper

Michael Henke 2 months ago
parent
commit
02b5f3076b
2 changed files with 44 additions and 46 deletions
  1. 2 19
      src/interview/dashboard-manager.ts
  2. 42 27
      src/interview/manager.ts

+ 2 - 19
src/interview/dashboard-manager.ts

@@ -1,4 +1,3 @@
-import path from 'node:path';
 import type { PluginInput } from '@opencode-ai/plugin';
 import type { PluginConfig } from '../config';
 import { log } from '../utils';
@@ -7,7 +6,7 @@ import {
   readDashboardAuthFile,
   tryBecomeDashboard,
 } from './dashboard';
-import { createInterviewServer } from './server';
+import { createPerSessionInterviewServer } from './manager';
 import { createInterviewService } from './service';
 import type {
   InterviewRecord,
@@ -187,23 +186,7 @@ export function createDashboardManager(
       );
       // Fallback: spawn a per-session server exactly like non-dashboard mode
       isDashboard = false;
-      const resolvedOutputPath = path.join(ctx.directory, outputFolder);
-      const server = createInterviewServer({
-        getState: async (interviewId) => service.getInterviewState(interviewId),
-        listInterviewFiles: async () => service.listInterviewFiles(),
-        listInterviews: () => service.listInterviews(),
-        submitAnswers: async (interviewId, answers) =>
-          service.submitAnswers(interviewId, answers),
-        submitBlockComment: async (interviewId, section, comment) =>
-          service.submitBlockComment(interviewId, section, comment),
-        submitChat: async (interviewId, message) =>
-          service.submitChat(interviewId, message),
-        handleNudgeAction: async (interviewId, action) =>
-          service.handleNudgeAction(interviewId, action),
-        outputFolder: resolvedOutputPath,
-        port: 0,
-      });
-      service.setBaseUrlResolver(() => server.ensureStarted());
+      createPerSessionInterviewServer(ctx, interviewConfig, outputFolder);
       service.setStatePushCallback(() => {}); // no-op on fallback
     } finally {
       initDone = true;

+ 42 - 27
src/interview/manager.ts

@@ -1,6 +1,6 @@
 import path from 'node:path';
 import type { PluginInput } from '@opencode-ai/plugin';
-import type { PluginConfig } from '../config';
+import type { InterviewConfig, PluginConfig } from '../config';
 import { DEFAULT_DASHBOARD_PORT } from './dashboard';
 import { createDashboardManager } from './dashboard-manager';
 import { createInterviewServer } from './server';
@@ -27,32 +27,7 @@ export function createInterviewManager(
 
   // ─── Per-session mode (upstream behavior) ───────────────────────
   if (!dashboardEnabled) {
-    const service = createInterviewService(ctx, interviewConfig);
-    const resolvedOutputPath = path.join(ctx.directory, outputFolder);
-    const server = createInterviewServer({
-      getState: async (interviewId) => service.getInterviewState(interviewId),
-      listInterviewFiles: async () => service.listInterviewFiles(),
-      listInterviews: () => service.listInterviews(),
-      submitAnswers: async (interviewId, answers) =>
-        service.submitAnswers(interviewId, answers),
-      submitBlockComment: async (interviewId, section, comment) =>
-        service.submitBlockComment(interviewId, section, comment),
-      submitChat: async (interviewId, message) =>
-        service.submitChat(interviewId, message),
-      handleNudgeAction: async (interviewId, action) =>
-        service.handleNudgeAction(interviewId, action),
-      outputFolder: resolvedOutputPath,
-      port: 0, // random port
-    });
-
-    service.setBaseUrlResolver(() => server.ensureStarted());
-
-    return {
-      registerCommand: (c) => service.registerCommand(c),
-      handleCommandExecuteBefore: async (input, output) =>
-        service.handleCommandExecuteBefore(input, output),
-      handleEvent: async (input) => service.handleEvent(input),
-    };
+    return createPerSessionInterviewServer(ctx, interviewConfig, outputFolder);
   }
 
   // ─── Dashboard mode ─────────────────────────────────────────────
@@ -61,3 +36,43 @@ export function createInterviewManager(
 
   return createDashboardManager(ctx, config, dashboardPort, outputFolder);
 }
+
+export function createPerSessionInterviewServer(
+  ctx: PluginInput,
+  interviewConfig: InterviewConfig | undefined,
+  outputFolder: string,
+): {
+  registerCommand: (config: Record<string, unknown>) => void;
+  handleCommandExecuteBefore: (
+    input: { command: string; sessionID: string; arguments: string },
+    output: { parts: Array<{ type: string; text?: string }> },
+  ) => Promise<void>;
+  handleEvent: (input: {
+    event: { type: string; properties?: Record<string, unknown> };
+  }) => Promise<void>;
+} {
+  const service = createInterviewService(ctx, interviewConfig);
+  const resolvedOutputPath = path.join(ctx.directory, outputFolder);
+  const server = createInterviewServer({
+    getState: async (interviewId) => service.getInterviewState(interviewId),
+    listInterviewFiles: async () => service.listInterviewFiles(),
+    listInterviews: () => service.listInterviews(),
+    submitAnswers: async (interviewId, answers) =>
+      service.submitAnswers(interviewId, answers),
+    submitBlockComment: async (interviewId, section, comment) =>
+      service.submitBlockComment(interviewId, section, comment),
+    submitChat: async (interviewId, message) =>
+      service.submitChat(interviewId, message),
+    handleNudgeAction: async (interviewId, action) =>
+      service.handleNudgeAction(interviewId, action),
+    outputFolder: resolvedOutputPath,
+    port: 0,
+  });
+  service.setBaseUrlResolver(() => server.ensureStarted());
+  return {
+    registerCommand: (c) => service.registerCommand(c),
+    handleCommandExecuteBefore: async (input, output) =>
+      service.handleCommandExecuteBefore(input, output),
+    handleEvent: async (input) => service.handleEvent(input),
+  };
+}