cc-haha/src/server/router.ts
程序员阿江(Relakkes) 7ae885a114 fix: add safe Doctor rescue path for desktop upgrades
Online upgrades can strand users on stale desktop UI state or malformed local persistence. This adds a deny-by-default Doctor path that resets only regenerable desktop UI state, reports protected local files with redacted metadata, and keeps protected repair as a dry-run no-op until a reviewed backup-first flow exists.

Constraint: Chat transcripts, model/provider config, Skills, MCP, IM bindings, adapter sessions, OAuth tokens, plugins, and team/session records are user-owned protected state.
Rejected: Automatically rewrite malformed protected JSON | unsafe without schema-specific migrations and backups.
Rejected: Continue relying only on startup migrations | users need an explicit recovery action after a white screen.
Confidence: high
Scope-risk: moderate
Directive: Keep Doctor repair deny-by-default; do not mutate protected state without an explicit reviewed backup-first manual repair flow.
Tested: bun test src/server/__tests__/doctor-service.test.ts
Tested: cd desktop && bun run test src/components/ErrorBoundary.test.tsx src/lib/doctorRepair.test.ts src/__tests__/diagnosticsSettings.test.tsx src/components/layout/StartupErrorView.test.tsx
Tested: cd desktop && bun run lint
Tested: bun run check:server
Tested: bun run verify (failed only existing agent-utils coverage baseline; changed-lines coverage 97.62%)
Not-tested: Packaged desktop manual Doctor click path.
2026-05-07 00:04:06 +08:00

112 lines
3.4 KiB
TypeScript

/**
* API Router — 将请求路由到对应的 API handler
*/
import { handleSessionsApi } from './api/sessions.js'
import { handleSettingsApi } from './api/settings.js'
import { handleModelsApi } from './api/models.js'
import { handleScheduledTasksApi } from './api/scheduled-tasks.js'
import { handleSearchApi } from './api/search.js'
import { handleAgentsApi } from './api/agents.js'
import { handleStatusApi } from './api/status.js'
import { handleConversationsApi } from './api/conversations.js'
import { handleTeamsApi } from './api/teams.js'
import { handleFilesystemRoute } from './api/filesystem.js'
import { handleProvidersApi } from './api/providers.js'
import { handleAdaptersApi } from './api/adapters.js'
import { handlePluginsApi } from './api/plugins.js'
import { handleSkillsApi } from './api/skills.js'
import { handleComputerUseApi } from './api/computer-use.js'
import { handleHahaOAuthApi } from './api/haha-oauth.js'
import { handleHahaOpenAIOAuthApi } from './api/haha-openai-oauth.js'
import { handleMcpApi } from './api/mcp.js'
import { handleDiagnosticsApi } from './api/diagnostics.js'
import { handleDoctorApi } from './api/doctor.js'
export async function handleApiRequest(req: Request, url: URL): Promise<Response> {
const path = url.pathname
const segments = path.split('/').filter(Boolean) // ['api', 'sessions', ...]
// Route to appropriate handler based on the second segment
const resource = segments[1]
switch (resource) {
case 'sessions': {
// Route /api/sessions/:id/chat/* to conversations handler
const subResource = segments[3]
if (subResource === 'chat') {
return handleConversationsApi(req, url, segments)
}
return handleSessionsApi(req, url, segments)
}
case 'conversations':
return handleConversationsApi(req, url, segments)
case 'settings':
return handleSettingsApi(req, url, segments)
case 'models':
case 'effort':
return handleModelsApi(req, url, segments)
case 'permissions':
return handleSettingsApi(req, url, segments) // permissions under settings
case 'scheduled-tasks':
return handleScheduledTasksApi(req, url, segments)
case 'search':
return handleSearchApi(req, url, segments)
case 'agents':
case 'tasks':
return handleAgentsApi(req, url, segments)
case 'status':
return handleStatusApi(req, url, segments)
case 'teams':
return handleTeamsApi(req, url, segments)
case 'providers':
return handleProvidersApi(req, url, segments)
case 'haha-oauth':
return handleHahaOAuthApi(req, url, segments)
case 'haha-openai-oauth':
return handleHahaOpenAIOAuthApi(req, url, segments)
case 'adapters':
return handleAdaptersApi(req, url, segments)
case 'skills':
return handleSkillsApi(req, url, segments)
case 'mcp':
return handleMcpApi(req, url, segments)
case 'plugins':
return handlePluginsApi(req, url, segments)
case 'computer-use':
return handleComputerUseApi(req, url, segments)
case 'diagnostics':
return handleDiagnosticsApi(req, url, segments)
case 'doctor':
return handleDoctorApi(req, url, segments)
case 'filesystem':
return handleFilesystemRoute(url.pathname, url)
default:
return Response.json(
{ error: 'Not Found', message: `Unknown API resource: ${resource}` },
{ status: 404 }
)
}
}