claude-code-best/src/server/server.ts
DoSun ca147a40b7 fix: 修复 serve 模式 SSE 事件流、权限响应、协议对齐
- 修复 emitEvent 无限递归(调用自身→调用 eventBus.publishSessionEvent)
- 修复 prompt() 用户消息缺失 uuid/content 字段
- session.ready 事件映射为 session.updated(非重复 session.created)
- 新增用户消息事件(message.updated role:user + message.part.updated)
- 新增 session.status busy/idle、step-start/step-finish、session.idle/diff
- 清理 heartbeat properties 为空对象
- 仅 assistant 类型消息作为 session.message 转发,过滤 system/其他杂消息
- 权限响应映射 once/always/reject → allow/deny
- 会话创建支持 permission ruleset 推导 permission mode
- prompt 路由支持 model 字段切换模型
- 初始化消息支持 hooks 配置
- 新增 HookCallback/ControlCancelRequest 处理
- 权限响应支持 updatedPermissions 和 interrupt
- 新增 --resume-session-at、--permission-prompt-tool stdio 参数
- 追踪 lastMessageUuid 用于消息级回退
- EventBus dead client 清理
2026-05-08 16:59:45 +08:00

63 lines
2.0 KiB
TypeScript

import { Hono } from 'hono'
import { cors } from 'hono/cors'
import type { Server as BunServer } from 'bun'
import { EventBus } from './eventBus.js'
import { SessionManager } from './sessionManager.js'
import { errorHandler } from './errors.js'
import { createHealthRoutes } from './routes/health.js'
import { createInfoRoutes } from './routes/info.js'
import { createSessionRoutes } from './routes/session.js'
import { createEventRoutes } from './routes/event.js'
import { createPermissionRoutes } from './routes/permission.js'
import { createQuestionRoutes } from './routes/question.js'
import { createMessageRoutes } from './routes/message.js'
import { createProviderRoutes } from './routes/provider.js'
import { createFindRoutes } from './routes/find.js'
import type { ServerConfig } from './types.js'
export function startServer(
config: ServerConfig,
sessionManager: SessionManager,
eventBus: EventBus,
): BunServer & { port?: number } {
eventBus.startHeartbeat()
const app = new Hono()
app.onError(errorHandler)
// Auth is intentionally disabled for now so multiple local serve instances
// can be started and consumed without token plumbing.
app.use(
'*',
cors({
maxAge: 86400,
origin: (input) => {
if (!input) return
if (input.startsWith('http://localhost:')) return input
if (input.startsWith('http://127.0.0.1:')) return input
return
},
}),
)
app.route('/', createHealthRoutes(sessionManager))
app.route('/', createInfoRoutes(sessionManager))
app.route('/', createSessionRoutes(sessionManager))
app.route('/', createEventRoutes(eventBus))
app.route('/', createPermissionRoutes(sessionManager))
app.route('/', createQuestionRoutes(sessionManager))
app.route('/', createMessageRoutes(sessionManager))
app.route('/', createProviderRoutes(sessionManager))
app.route('/', createFindRoutes())
const server = Bun.serve({
hostname: config.host,
port: config.port,
fetch: app.fetch,
})
return server
}