Files
proxycast/eslint.config.js
T
2026-04-18 02:43:24 +08:00

1221 lines
43 KiB
JavaScript

import js from "@eslint/js";
import tseslint from "@typescript-eslint/eslint-plugin";
import tsparser from "@typescript-eslint/parser";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import globals from "globals";
import agentCommandCatalog from "./src/lib/governance/agentCommandCatalog.json" with { type: "json" };
const legacyChatRestrictedPatterns = [
"@/components/chat",
"@/components/chat/*",
"@/components/chat/**",
"**/components/chat",
"**/components/chat/*",
"**/components/chat/**",
];
const agentCompatRestrictedPatterns = [
{
group: [
"@/components/agent/chat/hooks/useAgentChat",
"@/components/agent/chat/hooks/useAgentChat.*",
"**/useAgentChat",
"**/useAgentChat.*",
],
message:
"useAgentChat 属于零引用 compat Hook,请改用 useAgentChatUnified 或 useAsterAgentChat;仅兼容回归测试允许引用。",
},
{
group: [
"@/stores/agentStore",
"@/stores/agentStore.*",
"**/agentStore",
"**/agentStore.*",
],
message:
"agentStore 属于零引用遗留状态容器,请改用 useAgentChatUnified / useAsterAgentChat;仅兼容回归测试允许引用。",
},
];
const deprecatedAgentRuntimeHelperNames = Object.keys(
agentCommandCatalog.deprecatedHelperReplacements,
);
const generalChatRestrictedPaths = [
{
name: "@/components/general-chat",
importNames: ["useChat"],
message:
"general-chat 的 useChat 属于旧路径,请优先使用 useAgentChatUnified / useAsterAgentChat 或当前现役聊天入口。",
},
{
name: "@/components/general-chat",
importNames: ["useSession", "useStreaming"],
message:
"general-chat 当前属于兼容链路,请不要在新代码中继续引入页面入口或旧 Hook。",
},
{
name: "@/components/general-chat",
importNames: ["GeneralChatPage"],
message:
"general-chat 当前属于兼容链路,请不要在新代码中继续引入页面入口或旧 Hook。",
},
{
name: "@/components/general-chat/hooks",
importNames: ["useChat"],
message:
"general-chat/hooks/useChat 属于旧路径,请优先使用 useAgentChatUnified / useAsterAgentChat 或当前现役聊天入口。",
},
{
name: "@/components/general-chat/hooks",
importNames: ["useSession", "useStreaming"],
message:
"general-chat/hooks 下的 useSession/useStreaming 属于兼容实现,请优先接入 useAgentChatUnified / useAsterAgentChat / agent_runtime_*。",
},
{
name: "@/components/general-chat/hooks/useChat",
message:
"general-chat/hooks/useChat 属于旧路径,请优先使用 useAgentChatUnified / useAsterAgentChat 或当前现役聊天入口。",
},
{
name: "@/components/general-chat/GeneralChatPage",
message:
"GeneralChatPage 属于旧版 general-chat 入口,请不要在新代码中继续引入。",
},
{
name: "@/components/general-chat/hooks/useSession",
message:
"general-chat/hooks/useSession 属于旧版会话兼容 Hook,请优先接入统一对话链路。",
},
{
name: "@/components/general-chat/hooks/useStreaming",
message:
"general-chat/hooks/useStreaming 依赖旧流事件协议,请优先接入统一对话链路。",
},
{
name: "@/components/general-chat/canvas",
message:
"请不要直接深导入 general-chat/canvas;跨模块复用请改用 @/components/general-chat/bridge。",
},
{
name: "@/components/general-chat/types",
message:
"请不要直接深导入 general-chat/types;跨模块复用请改用 @/components/general-chat/bridge 或现役共享类型。",
},
{
name: "@/components/general-chat/store/useGeneralChatStore",
message:
"请不要直接深导入 general-chat 内部 store;如需兼容桥接,请显式放在 compat 层。",
},
{
name: "@/lib/api/generalChatCompat",
message:
"generalChatCompat 属于兼容网关,请仅在 general-chat store 中消费,避免 compat 逻辑再次向业务层扩散。",
},
{
name: "@/lib/api/compat",
message:
"api/compat.ts 属于历史记忆兼容层,请不要在新代码中接入;旧记忆运行时请使用 @/lib/api/memoryRuntime,统一记忆请使用 @/lib/api/unifiedMemory。",
},
{
name: "@/lib/api/agent",
message:
"agent.ts 已删除;请直接使用 @/lib/api/agentRuntime 或 @/lib/api/agentStream。",
},
{
name: "@/hooks/useTauri",
message:
"useTauri 现在只是兼容聚合层,禁止新增依赖;请直接接入对应的 @/lib/api/* 网关。",
},
{
name: "@/hooks/useTauri",
importNames: [
"startServer",
"stopServer",
"getServerStatus",
"getServerDiagnostics",
"getLogStorageDiagnostics",
"exportSupportBundle",
"getWindowsStartupDiagnostics",
"ServerStatus",
"ServerDiagnostics",
"LogStorageDiagnostics",
"SupportBundleExportResult",
"WindowsStartupDiagnostics",
],
message:
"server/diagnostics 相关能力已迁移到 @/lib/api/serverRuntime,请不要继续从 useTauri 聚合层引入。",
},
{
name: "@/hooks/useTauri",
importNames: [
"getLogs",
"getPersistedLogsTail",
"clearLogs",
"clearDiagnosticLogHistory",
"LogEntry",
],
message:
"日志相关能力已迁移到 @/lib/api/logs,请不要继续从 useTauri 聚合层引入。",
},
{
name: "@/hooks/useTauri",
importNames: [
"checkApiCompatibility",
"ApiCheckResult",
"ApiCompatibilityResult",
],
message:
"API 兼容性检查能力已迁移到 @/lib/api/apiCompatibility,请不要继续从 useTauri 聚合层引入。",
},
{
name: "@/hooks/useTauri",
importNames: [
"getEndpointProviders",
"setEndpointProvider",
"EndpointProvidersConfig",
],
message:
"端点 Provider 配置能力已迁移到 @/lib/api/endpointProviders,请不要继续从 useTauri 聚合层引入。",
},
{
name: "@/hooks/useTauri",
importNames: [
"getMemoryStats",
"requestMemoryAnalysis",
"cleanupMemory",
"CleanupMemoryResult",
"MemoryAnalysisResult",
"MemoryStatsResponse",
],
message:
"记忆分析/清理能力已迁移到 @/lib/api/memoryRuntime,请不要继续从 useTauri 聚合层引入。",
},
{
name: "@/hooks/useTauri",
importNames: [
"testTts",
"getAvailableVoices",
"TtsTestResult",
"VoiceOption",
],
message:
"语音测试能力已迁移到 @/lib/api/voiceTools,请不要继续从 useTauri 聚合层引入。",
},
{
name: "@/hooks/useTauri",
importNames: ["uploadAvatar", "deleteAvatar", "UploadResult"],
message:
"头像上传/删除能力已迁移到 @/lib/api/profileAssets,请不要继续从 useTauri 聚合层引入。",
},
{
name: "@/hooks/useTauri",
importNames: [
"getConfig",
"saveConfig",
"getEnvironmentPreview",
"getDefaultProvider",
"setDefaultProvider",
"updateProviderEnvVars",
"Config",
"EnvironmentPreview",
],
message:
"配置/环境预览相关能力已迁移到 @/lib/api/appConfig,请不要继续从 useTauri 聚合层引入。",
},
{
name: "@/hooks/useTauri",
importNames: [
"ChannelsConfig",
"GatewayConfig",
"TelegramBotConfig",
"DiscordBotConfig",
"FeishuBotConfig",
"GatewayChannelStatusResponse",
"TelegramProbeResult",
"FeishuProbeResult",
"DiscordProbeResult",
"GatewayTunnelStatus",
"GatewayTunnelProbeResult",
"CloudflaredInstallStatus",
"CloudflaredInstallResult",
"GatewayTunnelCreateResponse",
"GatewayTunnelSyncWebhookResponse",
"gatewayChannelStart",
"gatewayChannelStop",
"gatewayChannelStatus",
"telegramChannelProbe",
"feishuChannelProbe",
"discordChannelProbe",
"gatewayTunnelProbe",
"gatewayTunnelDetectCloudflared",
"gatewayTunnelInstallCloudflared",
"gatewayTunnelCreate",
"gatewayTunnelStart",
"gatewayTunnelStop",
"gatewayTunnelRestart",
"gatewayTunnelStatus",
"gatewayTunnelSyncWebhookUrl",
],
message:
"channels/gateway 相关能力已迁移到 @/lib/api/channelsRuntime,请不要继续从 useTauri 聚合层引入。",
},
{
name: "@/hooks/useTauri",
importNames: [
"getExperimentalConfig",
"saveExperimentalConfig",
"validateShortcut",
"updateScreenshotShortcut",
"ExperimentalFeatures",
"SmartInputConfig",
],
message:
"实验室配置/截图快捷键相关能力已迁移到 @/lib/api/experimentalFeatures,请不要继续从 useTauri 聚合层引入。",
},
{
name: "@/hooks/useTauri",
importNames: [
"getMemoryOverview",
"getMemoryEffectiveSources",
"getMemoryAutoIndex",
"toggleMemoryAuto",
"updateMemoryAutoNote",
"MemoryOverviewResponse",
"EffectiveMemorySourcesResponse",
"AutoMemoryIndexResponse",
"MemoryAutoConfig",
"MemoryAutoToggleResponse",
"MemoryConfig",
"MemoryProfileConfig",
"MemoryResolveConfig",
"MemorySourcesConfig",
],
message:
"记忆运行时相关能力已迁移到 @/lib/api/memoryRuntime,请不要继续从 useTauri 聚合层引入。",
},
{
name: "@/hooks/useTauri",
importNames: ["getAvailableModels", "ModelInfo"],
message:
"模型列表查询已迁移到 @/lib/api/modelCatalog,请不要继续从 useTauri 聚合层引入。",
},
{
name: "@/hooks/useTauri",
importNames: [
"getUsageStats",
"getModelUsageRanking",
"getDailyUsageTrends",
"UsageStatsResponse",
"ModelUsage",
"DailyUsage",
],
message:
"使用统计查询已迁移到 @/lib/api/usageStats,请不要继续从 useTauri 聚合层引入。",
},
{
name: "@/hooks/useTauri",
importNames: [
"reloadCredentials",
"refreshKiroToken",
"getKiroCredentials",
"getEnvVariables",
"getTokenFileHash",
"checkAndReloadCredentials",
"getGeminiCredentials",
"reloadGeminiCredentials",
"refreshGeminiToken",
"getGeminiEnvVariables",
"getGeminiTokenFileHash",
"checkAndReloadGeminiCredentials",
"getQwenCredentials",
"reloadQwenCredentials",
"refreshQwenToken",
"getQwenEnvVariables",
"getQwenTokenFileHash",
"checkAndReloadQwenCredentials",
"getOpenAICustomStatus",
"setOpenAICustomConfig",
"getClaudeCustomStatus",
"setClaudeCustomConfig",
"KiroCredentialStatus",
"EnvVariable",
"CheckResult",
"GeminiCredentialStatus",
"QwenCredentialStatus",
"OpenAICustomStatus",
"ClaudeCustomStatus",
"CredentialEntry",
"GeminiApiKeyEntry",
"VertexApiKeyEntry",
"VertexModelAlias",
"AmpConfig",
"AmpModelMapping",
],
message:
"provider 凭证/自定义状态相关能力已迁移到 @/lib/api/providerRuntime,请不要继续从 useTauri 聚合层引入。",
},
{
name: "@/hooks/useTauri",
importNames: ["testApi", "TestResult", "getNetworkInfo", "NetworkInfo"],
message:
"API 测试/网络信息相关能力已迁移到 @/lib/api/serverTools,请不要继续从 useTauri 聚合层引入。",
},
{
name: "@/stores/agentStore",
message:
"agentStore 属于零引用遗留状态容器,请改用现役 useAgentChatUnified / useAsterAgentChat 链路。",
},
{
name: "@/stores",
importNames: [
"useAgentStore",
"useAgentMessages",
"useAgentStreaming",
"useAgentSessions",
"usePendingActions",
],
message:
"agentStore 相关导出属于零引用遗留状态容器,请改用现役 useAgentChatUnified / useAsterAgentChat 链路。",
},
{
name: "@/lib/api/agentCompat",
message:
"agentCompat 属于遗留兼容层,请仅在历史桥接或兼容测试中使用,避免继续向业务层扩散。",
},
{
name: "@/lib/api/agent",
importNames: ["sendAgentMessage", "sendAgentMessageStream"],
message:
"agent.ts 已删除;旧 Agent 发送 API 请改用 submitAgentRuntimeTurn() 或 useAsterAgentChat().sendMessage()。",
},
{
name: "@/lib/api/agentRuntime",
importNames: deprecatedAgentRuntimeHelperNames,
message:
"agentRuntime 中这些旧命名 helper 只允许留在兼容层或兼容测试;业务层请改用 agent_runtime_* 对应 API 或 useAsterAgentChat。",
},
{
name: "@/hooks/useUnifiedChat",
message:
"useUnifiedChat 已删除;Agent 工作台请改用 useAgentChatUnified / useAsterAgentChat,旧 General/Creator 路径如需恢复,必须基于 agent_runtime_* 重新设计。",
},
{
name: "@/lib/api/agent",
importNames: [
"initasterAgent",
"getasterAgentStatus",
"resetasterAgent",
"createasterSession",
"sendasterMessage",
"listasterProviders",
],
message:
"agent.ts 已删除;旧 aster 命名 API 请改用现役 Aster API 或 Provider 配置流程。",
},
];
const generalChatRestrictedPathsWithoutCompatApi =
generalChatRestrictedPaths.filter(
(entry) => entry.name !== "@/lib/api/generalChatCompat",
);
const createLegacyChatImportRule = (
paths,
{ includeAgentCompatPatterns = true } = {},
) => {
const patterns = [
{
group: legacyChatRestrictedPatterns,
message:
"components/chat 为遗留聊天模块,禁止新增依赖;请优先使用现役聊天入口。",
},
];
if (includeAgentCompatPatterns) {
patterns.push(...agentCompatRestrictedPatterns);
}
return [
"error",
{
paths,
patterns,
},
];
};
const generalChatCompatCommandSelectors = [
"general_chat_get_session",
"general_chat_list_sessions",
"general_chat_create_session",
"general_chat_delete_session",
"general_chat_rename_session",
"general_chat_get_messages",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"general_chat_* compat 命令只允许集中放在 src/lib/api/generalChatCompat.ts,禁止在业务层直接扩散。",
}));
const agentRuntimeCommandSelectors = [
...new Set([
...agentCommandCatalog.runtimeGatewayCommands,
...Object.keys(agentCommandCatalog.deprecatedCommandReplacements),
]),
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"agent runtime 命令只允许集中放在 `src/lib/api/agentRuntime` 网关目录;旧 agent_/aster_ 命令已废弃,禁止在业务模块直接扩散。",
}));
const projectGatewayCommandSelectors = [
"workspace_create",
"workspace_get_projects_root",
"workspace_resolve_project_path",
"workspace_list",
"workspace_get_default",
"workspace_ensure_default_ready",
"workspace_set_default",
"workspace_get_by_path",
"workspace_get",
"workspace_update",
"workspace_delete",
"workspace_ensure_ready",
"get_or_create_default_project",
"content_create",
"content_get",
"content_get_theme_workbench_document_state",
"content_list",
"content_update",
"content_delete",
"content_reorder",
"content_stats",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"workspace/project 相关后端命令请统一通过 `src/lib/api/project.ts` 暴露的网关函数调用,避免业务层继续拼接命令名并扩散兼容逻辑。",
}));
const materialGatewayCommandSelectors = [
"list_materials",
"get_material_count",
"upload_material",
"update_material",
"delete_material",
"get_material_content",
"import_material_from_url",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"素材相关后端命令请统一通过 `src/lib/api/materials.ts` 暴露的网关函数调用,避免在 Hook / 组件中继续直接拼接命令名。",
}));
const templateGatewayCommandSelectors = [
"list_templates",
"get_default_template",
"create_template",
"update_template",
"delete_template",
"set_default_template",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"模板相关后端命令请统一通过 `src/lib/api/templates.ts` 暴露的网关函数调用,避免在 Hook / 组件中继续直接拼接命令名。",
}));
const personaGatewayCommandSelectors = [
"list_personas",
"get_default_persona",
"create_persona",
"update_persona",
"delete_persona",
"set_default_persona",
"list_persona_templates",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"人设相关后端命令请统一通过 `src/lib/api/personas.ts` 暴露的网关函数调用,避免在 Hook / 组件中继续直接拼接命令名。",
}));
const brandPersonaGatewayCommandSelectors = [
"get_brand_persona",
"get_brand_extension",
"save_brand_extension",
"update_brand_extension",
"delete_brand_extension",
"list_brand_persona_templates",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"品牌人设相关后端命令请统一通过 `src/lib/api/brandPersona.ts` 暴露的网关函数调用,避免在 Hook / 组件中继续直接拼接命令名。",
}));
const posterMaterialGatewayCommandSelectors = [
"get_poster_material",
"create_poster_metadata",
"update_poster_metadata",
"delete_poster_metadata",
"list_by_image_category",
"list_by_layout_category",
"list_by_mood",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"海报素材相关后端命令请统一通过 `src/lib/api/posterMaterials.ts` 暴露的网关函数调用,避免在 Hook / 组件中继续直接拼接命令名。",
}));
const fileSystemCommandSelectors = [
"reveal_in_finder",
"open_with_default_app",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"文件打开/定位相关后端命令请统一通过 `src/lib/api/fileSystem.ts` 暴露的网关函数调用,避免在 Hook / 组件中继续直接拼接命令名。",
}));
const pluginGatewayCommandSelectors = [
"get_plugin_status",
"get_plugins",
"list_installed_plugins",
"list_plugin_tasks",
"get_plugin_queue_stats",
"get_plugin_task",
"enable_plugin",
"disable_plugin",
"reload_plugins",
"unload_plugin",
"uninstall_plugin",
"cancel_plugin_task",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"插件运行态/管理相关后端命令请统一通过 `src/lib/api/plugins.ts` 暴露的网关函数调用,避免在 Hook / 组件中继续直接拼接命令名。",
}));
const fileBrowserCommandSelectors = [
"list_dir",
"read_file_preview_cmd",
"create_file",
"create_directory",
"rename_file",
"delete_file",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"文件浏览/文件树相关后端命令请统一通过 `src/lib/api/fileBrowser.ts` 暴露的网关函数调用,避免在组件中继续直接拼接命令名。",
}));
const appUpdateCommandSelectors = [
"check_for_updates",
"download_update",
"close_update_window",
"dismiss_update_notification",
"record_update_notification_action",
"remind_update_later",
"skip_update_version",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"更新检查/更新提醒相关后端命令请统一通过 `src/lib/api/appUpdate.ts` 暴露的网关函数调用,避免在页面中继续直接拼接命令名。",
}));
const screenshotChatCommandSelectors = [
"send_screenshot_chat",
"close_screenshot_chat_window",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"截图聊天窗口相关后端命令请统一通过 `src/lib/api/screenshotChat.ts` 暴露的网关函数调用,避免在页面/组件中继续直接拼接命令名。",
}));
const systemSupportCommandSelectors = [
"show_notification",
"auto_fix_configuration",
"report_frontend_crash",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"系统支持类后端命令请统一通过对应 API 网关(`src/lib/api/notification.ts` / `autoFix.ts` / `frontendCrash.ts`)调用,避免在 lib / hook 中继续直接拼接命令名。",
}));
const serverRuntimeCommandSelectors = [
"start_server",
"stop_server",
"get_server_status",
"get_server_diagnostics",
"get_log_storage_diagnostics",
"export_support_bundle",
"get_windows_startup_diagnostics",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"服务控制/诊断相关后端命令请统一通过 `src/lib/api/serverRuntime.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}));
const logCommandSelectors = [
"get_logs",
"get_persisted_logs_tail",
"clear_logs",
"clear_diagnostic_log_history",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"日志相关后端命令请统一通过 `src/lib/api/logs.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}));
const appConfigCommandSelectors = [
"get_config",
"save_config",
"get_environment_preview",
"get_default_provider",
"set_default_provider",
"update_provider_env_vars",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"配置/环境预览相关后端命令请统一通过 `src/lib/api/appConfig.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}));
const channelsRuntimeCommandSelectors = [
"gateway_channel_start",
"gateway_channel_stop",
"gateway_channel_status",
"telegram_channel_probe",
"feishu_channel_probe",
"discord_channel_probe",
"gateway_tunnel_probe",
"gateway_tunnel_detect_cloudflared",
"gateway_tunnel_install_cloudflared",
"gateway_tunnel_create",
"gateway_tunnel_start",
"gateway_tunnel_stop",
"gateway_tunnel_restart",
"gateway_tunnel_status",
"gateway_tunnel_sync_webhook_url",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"channels/gateway 相关后端命令请统一通过 `src/lib/api/channelsRuntime.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}));
const experimentalFeaturesCommandSelectors = [
"get_experimental_config",
"save_experimental_config",
"validate_shortcut",
"update_screenshot_shortcut",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"实验室配置/截图快捷键相关后端命令请统一通过 `src/lib/api/experimentalFeatures.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}));
const memoryRuntimeCommandSelectors = [
"get_conversation_memory_stats",
"request_conversation_memory_analysis",
"cleanup_conversation_memory",
"get_conversation_memory_overview",
"memory_get_effective_sources",
"memory_get_auto_index",
"memory_toggle_auto",
"memory_update_auto_note",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"记忆运行时相关后端命令请统一通过 `src/lib/api/memoryRuntime.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}));
const projectMemoryCommandSelectors = [
"character_list",
"character_get",
"character_create",
"character_update",
"character_delete",
"world_building_get",
"world_building_update",
"style_guide_get",
"style_guide_update",
"outline_node_list",
"outline_node_get",
"outline_node_create",
"outline_node_update",
"outline_node_delete",
"project_memory_get",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"项目记忆 CRUD 相关后端命令请统一通过 `src/lib/api/memory.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}));
const toolHooksCommandSelectors = [
"execute_hooks",
"add_hook_rule",
"remove_hook_rule",
"toggle_hook_rule",
"get_hook_rules",
"get_hook_execution_stats",
"clear_hook_execution_stats",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"工具钩子相关命令请统一通过 `src/lib/api/toolHooks.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}));
const a2uiFormCommandSelectors = [
"create_a2ui_form",
"get_a2ui_form",
"get_a2ui_forms_by_message",
"get_a2ui_forms_by_session",
"save_a2ui_form_data",
"submit_a2ui_form",
"delete_a2ui_form",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"A2UI 表单持久化命令请统一通过 `src/lib/api/a2uiForm.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}));
const memoryFeedbackCommandSelectors = [
"unified_memory_feedback",
"get_memory_feedback_stats",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"记忆反馈相关命令请统一通过 `src/lib/api/memoryFeedback.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}));
const contextMemoryCommandSelectors = [
"save_memory_entry",
"get_session_memories",
"get_memory_context",
"record_error",
"should_avoid_operation",
"mark_error_resolved",
"get_memory_stats",
"cleanup_expired_memories",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"上下文记忆命令请统一通过 `src/lib/api/contextMemory.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}));
const asrProviderCommandSelectors = [
"list_audio_devices",
"get_asr_credentials",
"add_asr_credential",
"update_asr_credential",
"delete_asr_credential",
"set_default_asr_credential",
"test_asr_credential",
"get_voice_input_config",
"save_voice_input_config",
"get_voice_instructions",
"save_voice_instruction",
"delete_voice_instruction",
"transcribe_audio",
"polish_voice_text",
"open_voice_window",
"close_voice_window",
"output_voice_text",
"start_recording",
"stop_recording",
"cancel_recording",
"get_recording_status",
"open_input_with_text",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"语音输入/ASR 相关命令请统一通过 `src/lib/api/asrProvider.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}));
const contentWorkflowCommandSelectors = [
"content_workflow_create",
"content_workflow_get",
"content_workflow_get_by_content",
"content_workflow_advance",
"content_workflow_retry",
"content_workflow_cancel",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"内容工作流命令请统一通过 `src/lib/api/content-workflow.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}));
const novelCommandSelectors = [
"novel_create_project",
"novel_update_settings",
"novel_generate_outline",
"novel_generate_characters",
"novel_generate_chapter",
"novel_continue_chapter",
"novel_rewrite_chapter",
"novel_polish_chapter",
"novel_check_consistency",
"novel_get_project_snapshot",
"novel_list_runs",
"novel_delete_character",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"小说编排命令请统一通过 `src/lib/api/novel.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}));
const unifiedChatCommandSelectors = [
"chat_create_session",
"chat_list_sessions",
"chat_get_session",
"chat_delete_session",
"chat_rename_session",
"chat_get_messages",
"chat_send_message",
"chat_stop_generation",
"chat_configure_provider",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"`chat_*` 兼容命令已停用;不要继续直接拼接旧命令名,现役链路请统一收敛到 agent_runtime_*。",
}));
const unifiedMemoryCommandSelectors = [
"unified_memory_list",
"unified_memory_search",
"unified_memory_get",
"unified_memory_create",
"unified_memory_update",
"unified_memory_delete",
"unified_memory_stats",
"unified_memory_analyze",
"unified_memory_semantic_search",
"unified_memory_hybrid_search",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"统一记忆命令请统一通过 `src/lib/api/unifiedMemory.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}));
const apiCompatibilityCommandSelectors = ["check_api_compatibility"].map(
(command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"API 兼容性检查命令请统一通过 `src/lib/api/apiCompatibility.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}),
);
const endpointProvidersCommandSelectors = [
"get_endpoint_providers",
"set_endpoint_provider",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"端点 Provider 配置命令请统一通过 `src/lib/api/endpointProviders.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}));
const voiceToolsCommandSelectors = ["test_tts", "get_available_voices"].map(
(command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"语音测试命令请统一通过 `src/lib/api/voiceTools.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}),
);
const profileAssetsCommandSelectors = ["upload_avatar", "delete_avatar"].map(
(command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"头像资产命令请统一通过 `src/lib/api/profileAssets.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}),
);
const modelCatalogCommandSelectors = ["get_available_models"].map(
(command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"模型列表查询命令请统一通过 `src/lib/api/modelCatalog.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}),
);
const usageStatsCommandSelectors = [
"get_usage_stats",
"get_model_usage_ranking",
"get_daily_usage_trends",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"使用统计命令请统一通过 `src/lib/api/usageStats.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}));
const providerRuntimeCommandSelectors = [
"refresh_kiro_token",
"reload_credentials",
"get_kiro_credentials",
"get_env_variables",
"get_token_file_hash",
"check_and_reload_credentials",
"get_gemini_credentials",
"reload_gemini_credentials",
"refresh_gemini_token",
"get_gemini_env_variables",
"get_gemini_token_file_hash",
"check_and_reload_gemini_credentials",
"get_qwen_credentials",
"reload_qwen_credentials",
"refresh_qwen_token",
"get_qwen_env_variables",
"get_qwen_token_file_hash",
"check_and_reload_qwen_credentials",
"get_openai_custom_status",
"set_openai_custom_config",
"get_claude_custom_status",
"set_claude_custom_config",
].map((command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"provider 凭证/自定义状态相关后端命令请统一通过 `src/lib/api/providerRuntime.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}));
const serverToolsCommandSelectors = ["test_api", "get_network_info"].map(
(command) => ({
selector: `CallExpression[callee.name='safeInvoke'][arguments.0.value='${command}'], CallExpression[callee.name='invoke'][arguments.0.value='${command}']`,
message:
"API 测试/网络信息相关后端命令请统一通过 `src/lib/api/serverTools.ts` 暴露的网关函数调用,避免继续在其他模块中直接拼接命令名。",
}),
);
export default [
{ ignores: ["dist", "src-tauri", "node_modules"] },
{
files: ["**/*.{ts,tsx}"],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parser: tsparser,
parserOptions: {
ecmaFeatures: { jsx: true },
},
},
plugins: {
"@typescript-eslint": tseslint,
"react-hooks": reactHooks,
"react-refresh": reactRefresh,
},
rules: {
...js.configs.recommended.rules,
...tseslint.configs.recommended.rules,
...reactHooks.configs.recommended.rules,
"react-refresh/only-export-components": [
"warn",
{
allowConstantExport: true,
allowExportNames: [
// AddCustomProviderModal.tsx
"validateCustomProviderForm",
"isFormValid",
"hasRequiredFields",
// ApiKeyItem.tsx
"extractApiKeyDisplayInfo",
// ApiKeyList.tsx
"getApiKeyListStats",
// ApiKeyProviderSection.tsx
"verifyProviderSelectionSync",
"extractSelectionState",
// ConnectionTestButton.tsx
"getConnectionTestStatusInfo",
// DeleteProviderDialog.tsx
"canDeleteProvider",
"isSystemProvider",
// ProviderConfigForm.tsx
"getFieldsForProviderType",
"providerTypeRequiresField",
// ProviderGroup.tsx
"getGroupLabel",
"isProviderInGroup",
"getGroupOrder",
// ProviderList.tsx
"filterProviders",
"groupProviders",
"matchesSearchQuery",
// ProviderListItem.tsx
"extractListItemDisplayInfo",
"getApiKeyCount",
// ProviderSetting.tsx
"extractProviderSettingInfo",
// icons/providers/index.tsx
"iconComponents",
],
},
],
"no-restricted-imports": createLegacyChatImportRule(
generalChatRestrictedPaths,
),
"no-restricted-syntax": [
"error",
...generalChatCompatCommandSelectors,
...agentRuntimeCommandSelectors,
...projectGatewayCommandSelectors,
...materialGatewayCommandSelectors,
...templateGatewayCommandSelectors,
...personaGatewayCommandSelectors,
...brandPersonaGatewayCommandSelectors,
...posterMaterialGatewayCommandSelectors,
...fileSystemCommandSelectors,
...pluginGatewayCommandSelectors,
...fileBrowserCommandSelectors,
...appUpdateCommandSelectors,
...screenshotChatCommandSelectors,
...systemSupportCommandSelectors,
...serverRuntimeCommandSelectors,
...logCommandSelectors,
...appConfigCommandSelectors,
...channelsRuntimeCommandSelectors,
...experimentalFeaturesCommandSelectors,
...memoryRuntimeCommandSelectors,
...projectMemoryCommandSelectors,
...toolHooksCommandSelectors,
...a2uiFormCommandSelectors,
...memoryFeedbackCommandSelectors,
...contextMemoryCommandSelectors,
...asrProviderCommandSelectors,
...contentWorkflowCommandSelectors,
...novelCommandSelectors,
...unifiedChatCommandSelectors,
...unifiedMemoryCommandSelectors,
...apiCompatibilityCommandSelectors,
...endpointProvidersCommandSelectors,
...modelCatalogCommandSelectors,
...profileAssetsCommandSelectors,
...usageStatsCommandSelectors,
...providerRuntimeCommandSelectors,
...serverToolsCommandSelectors,
...voiceToolsCommandSelectors,
],
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_",
},
],
"@typescript-eslint/no-explicit-any": "off",
},
},
{
files: ["src/components/general-chat/store/useGeneralChatStore.ts"],
rules: {
"no-restricted-imports": createLegacyChatImportRule(
generalChatRestrictedPathsWithoutCompatApi,
),
},
},
{
files: ["src/lib/api/generalChatCompat.ts"],
rules: {
"no-restricted-syntax": "off",
},
},
{
files: [
"src/lib/api/agent.test.ts",
"src/components/agent/chat/hooks/useAgentChat.test.tsx",
"src/stores/agentStore.test.ts",
],
rules: {
"no-restricted-imports": createLegacyChatImportRule(
generalChatRestrictedPaths,
{ includeAgentCompatPatterns: false },
),
},
},
{
files: [
"src/lib/api/agentRuntime.ts",
"src/lib/api/agentRuntime/**/*.ts",
"src/lib/api/agentCompat.ts",
"src/lib/api/project.ts",
"src/lib/api/materials.ts",
"src/lib/api/templates.ts",
"src/lib/api/personas.ts",
"src/lib/api/brandPersona.ts",
"src/lib/api/posterMaterials.ts",
"src/lib/api/subAgentScheduler.ts",
"src/lib/api/fileSystem.ts",
"src/lib/api/memory.ts",
"src/lib/api/plugins.ts",
"src/lib/api/pluginUI.ts",
"src/lib/api/fileBrowser.ts",
"src/lib/api/a2uiForm.ts",
"src/lib/api/appUpdate.ts",
"src/lib/api/asrProvider.ts",
"src/lib/api/content-workflow.ts",
"src/lib/api/screenshotChat.ts",
"src/lib/api/notification.ts",
"src/lib/api/novel.ts",
"src/lib/api/autoFix.ts",
"src/lib/api/contextMemory.ts",
"src/lib/api/frontendCrash.ts",
"src/lib/api/memoryFeedback.ts",
"src/lib/api/toolHooks.ts",
"src/lib/api/unifiedMemory.ts",
"src/lib/api/serverRuntime.ts",
"src/lib/api/logs.ts",
"src/lib/api/apiCompatibility.ts",
"src/lib/api/appConfig.ts",
"src/lib/api/channelsRuntime.ts",
"src/lib/api/endpointProviders.ts",
"src/lib/api/experimentalFeatures.ts",
"src/lib/api/memoryRuntime.ts",
"src/lib/api/modelCatalog.ts",
"src/lib/api/profileAssets.ts",
"src/lib/api/usageStats.ts",
"src/lib/api/providerRuntime.ts",
"src/lib/api/serverTools.ts",
"src/lib/api/voiceTools.ts",
"src/lib/api/sceneapp.ts",
],
rules: {
"no-restricted-syntax": "off",
},
},
{
files: ["src/lib/api/agentRuntime/**/*.ts"],
rules: {
"no-restricted-imports": [
"error",
{
paths: [
{
name: "../agentRuntime",
message:
"agentRuntime 目录内部已收敛到 `./types` + 分域 client;禁止再回绕 compat 根入口 `../agentRuntime`。",
},
{
name: "@/lib/api/agentRuntime",
message:
"agentRuntime 目录内部已收敛到 `./types` + 分域 client;禁止再通过 alias 根入口回绕 compat barrel。",
},
],
},
],
},
},
{
files: ["src/lib/api/*.ts"],
ignores: ["src/lib/api/agentRuntime.ts", "src/lib/api/agent.test.ts"],
rules: {
"no-restricted-imports": [
"error",
{
paths: [
{
name: "./agentRuntime",
message:
"src/lib/api 根层如需复用 agent runtime,请直接依赖 `./agentRuntime/types` 或具体分域 client,不要回绕 compat barrel `./agentRuntime`。",
},
],
},
],
},
},
];