From 21a64dfb49ecfaae0b86d9c01ddb8014a17606b7 Mon Sep 17 00:00:00 2001 From: weishu Date: Mon, 5 Jan 2026 12:30:19 +0800 Subject: [PATCH] refactor: extract session summary utilities to shared module --- server/src/web/routes/sessions.ts | 60 +------------------------------ shared/src/index.ts | 1 + shared/src/sessionSummary.ts | 53 +++++++++++++++++++++++++++ shared/src/types.ts | 2 ++ web/src/types/api.ts | 34 ++++++------------ 5 files changed, 68 insertions(+), 82 deletions(-) create mode 100644 shared/src/sessionSummary.ts diff --git a/server/src/web/routes/sessions.ts b/server/src/web/routes/sessions.ts index 95835268..7978cc1a 100644 --- a/server/src/web/routes/sessions.ts +++ b/server/src/web/routes/sessions.ts @@ -1,69 +1,11 @@ -import { getPermissionModesForFlavor, isModelModeAllowedForFlavor, isPermissionModeAllowedForFlavor } from '@hapi/protocol' +import { getPermissionModesForFlavor, isModelModeAllowedForFlavor, isPermissionModeAllowedForFlavor, toSessionSummary } from '@hapi/protocol' import { ModelModeSchema, PermissionModeSchema } from '@hapi/protocol/schemas' import { Hono } from 'hono' import { z } from 'zod' -import type { ModelMode } from '@hapi/protocol/types' import type { SyncEngine, Session } from '../../sync/syncEngine' import type { WebAppEnv } from '../middleware/auth' import { requireSessionFromParam, requireSyncEngine } from './guards' -type SessionSummaryMetadata = { - name?: string - path: string - machineId?: string - summary?: { text: string } - flavor?: string | null - worktree?: { - basePath: string - branch: string - name: string - worktreePath?: string - createdAt?: number - } -} - -type SessionSummary = { - id: string - active: boolean - thinking: boolean - activeAt: number - updatedAt: number - metadata: SessionSummaryMetadata | null - todoProgress: { completed: number; total: number } | null - pendingRequestsCount: number - modelMode?: ModelMode -} - -function toSessionSummary(session: Session): SessionSummary { - const pendingRequestsCount = session.agentState?.requests ? Object.keys(session.agentState.requests).length : 0 - - const metadata: SessionSummaryMetadata | null = session.metadata ? { - name: session.metadata.name, - path: session.metadata.path, - machineId: session.metadata.machineId ?? undefined, - summary: session.metadata.summary ? { text: session.metadata.summary.text } : undefined, - flavor: session.metadata.flavor ?? null, - worktree: session.metadata.worktree - } : null - - const todoProgress = session.todos?.length ? { - completed: session.todos.filter(t => t.status === 'completed').length, - total: session.todos.length - } : null - - return { - id: session.id, - active: session.active, - thinking: session.thinking, - activeAt: session.activeAt, - updatedAt: session.updatedAt, - metadata, - todoProgress, - pendingRequestsCount, - modelMode: session.modelMode - } -} - const permissionModeSchema = z.object({ mode: PermissionModeSchema }) diff --git a/shared/src/index.ts b/shared/src/index.ts index 9a07266e..55d6004a 100644 --- a/shared/src/index.ts +++ b/shared/src/index.ts @@ -1,3 +1,4 @@ export * from './messages' export * from './modes' +export * from './sessionSummary' export type * from './types' diff --git a/shared/src/sessionSummary.ts b/shared/src/sessionSummary.ts new file mode 100644 index 00000000..4b693ada --- /dev/null +++ b/shared/src/sessionSummary.ts @@ -0,0 +1,53 @@ +import type { ModelMode } from './modes' +import type { Session, WorktreeMetadata } from './schemas' + +export type SessionSummaryMetadata = { + name?: string + path: string + machineId?: string + summary?: { text: string } + flavor?: string | null + worktree?: WorktreeMetadata +} + +export type SessionSummary = { + id: string + active: boolean + thinking: boolean + activeAt: number + updatedAt: number + metadata: SessionSummaryMetadata | null + todoProgress: { completed: number; total: number } | null + pendingRequestsCount: number + modelMode?: ModelMode +} + +export function toSessionSummary(session: Session): SessionSummary { + const pendingRequestsCount = session.agentState?.requests ? Object.keys(session.agentState.requests).length : 0 + + const metadata: SessionSummaryMetadata | null = session.metadata ? { + name: session.metadata.name, + path: session.metadata.path, + machineId: session.metadata.machineId ?? undefined, + summary: session.metadata.summary ? { text: session.metadata.summary.text } : undefined, + flavor: session.metadata.flavor ?? null, + worktree: session.metadata.worktree + } : null + + const todoProgress = session.todos?.length ? { + completed: session.todos.filter(t => t.status === 'completed').length, + total: session.todos.length + } : null + + return { + id: session.id, + active: session.active, + thinking: session.thinking, + activeAt: session.activeAt, + updatedAt: session.updatedAt, + metadata, + todoProgress, + pendingRequestsCount, + modelMode: session.modelMode + } +} diff --git a/shared/src/types.ts b/shared/src/types.ts index 8cdaa04d..7c573629 100644 --- a/shared/src/types.ts +++ b/shared/src/types.ts @@ -10,6 +10,8 @@ export type { WorktreeMetadata } from './schemas' +export type { SessionSummary, SessionSummaryMetadata } from './sessionSummary' + export type { AgentFlavor, ClaudePermissionMode, diff --git a/web/src/types/api.ts b/web/src/types/api.ts index 6f35a987..047c2b4c 100644 --- a/web/src/types/api.ts +++ b/web/src/types/api.ts @@ -1,12 +1,21 @@ import type { DecryptedMessage as ProtocolDecryptedMessage, - ModelMode, Session, + SessionSummary, SyncEvent as ProtocolSyncEvent, WorktreeMetadata } from '@hapi/protocol/types' -export type { AgentState, ModelMode, PermissionMode, Session, TodoItem, WorktreeMetadata } from '@hapi/protocol/types' +export type { + AgentState, + ModelMode, + PermissionMode, + Session, + SessionSummary, + SessionSummaryMetadata, + TodoItem, + WorktreeMetadata +} from '@hapi/protocol/types' export type SessionMetadataSummary = { path: string @@ -21,27 +30,6 @@ export type SessionMetadataSummary = { worktree?: WorktreeMetadata } -export type SessionSummaryMetadata = { - name?: string - path: string - machineId?: string - summary?: { text: string } - flavor?: string | null - worktree?: WorktreeMetadata -} - -export type SessionSummary = { - id: string - active: boolean - thinking: boolean - activeAt: number - updatedAt: number - metadata: SessionSummaryMetadata | null - todoProgress: { completed: number; total: number } | null - pendingRequestsCount: number - modelMode?: ModelMode -} - export type MessageStatus = 'sending' | 'sent' | 'failed' export type DecryptedMessage = ProtocolDecryptedMessage & {