feat: v0.8.2 安全纵深补全 · 协议保真 · 断链修复 — 图片SSRF/根MEMORY.md保护根治 · Anthropic thinking回传+pause_turn续传 · 2523 用例全量回归 + E2E 扩充
CI / 类型检查 + Lint + 单元测试 (push) Failing after 9m45s
CI / 全量测试 (Electron ABI) (push) Failing after 6m28s
CI / 产物编译验证 (push) Successful in 11m18s

This commit is contained in:
2026-09-08 14:30:27 +08:00
parent 69776e447f
commit 4cd6e997b5
86 changed files with 4303 additions and 956 deletions
+24 -1
View File
@@ -47,6 +47,9 @@ const ONBOARDING_PROGRESS_KEY = 'onboarding_progress';
export function OnboardingWizard(): React.JSX.Element | null {
const onboardingCompleted = useUIStore((s) => s.onboardingCompleted);
const setOnboardingCompleted = useUIStore((s) => s.setOnboardingCompleted);
// v0.8.2 P3-4: 配置就绪门禁 —— onboarding.completed 异步读取期间不渲染向导,
// 消除老用户每次启动的向导首帧闪烁
const onboardingGateReady = useUIStore((s) => s.onboardingGateReady);
const [step, setStep] = useState(0);
const [provider, setProvider] = useState('');
// v0.5.4: 多模态总开关(保存到 llm.multimodalEnabled,控制图片上传入口)
@@ -110,7 +113,7 @@ export function OnboardingWizard(): React.JSX.Element | null {
}
}, [step, provider, baseURL, model, workspacePath, contextWindow]);
if (onboardingCompleted) return null;
if (onboardingCompleted || !onboardingGateReady) return null;
// v0.8.1 硬性契约: 上下文长度是全局单一配置(llm.contextWindow),不再存在
// 分 Provider 默认值 —— 删除了旧的 DEFAULT_CTX 写死表(1M/128K/200K/4096)。
@@ -119,7 +122,27 @@ export function OnboardingWizard(): React.JSX.Element | null {
const ctxError =
contextWindow != null && (!Number.isFinite(contextWindow) || contextWindow < ctxMin);
// v0.8.2 P3-4: 步骤字段校验门禁 —— 此前"下一步"无任何校验,可以全空走完,
// 完成后 provider/model 缺失 → 首次发送必然 adapter 加载失败。LLM 配置步
// 强制 provider + model+ apiKeyollama 除外)+ 合法上下文长度。
const validateStep = (s: number): string | null => {
if (s === 1) {
if (!provider.trim()) return t('onboarding.validate.provider');
if (!model.trim()) return t('onboarding.validate.model');
if (provider !== 'ollama' && !apiKey.trim()) return t('onboarding.validate.apiKey');
if (ctxError) return t('onboarding.llm.ctx.minError', { min: ctxMin });
}
return null;
};
const handleNext = async () => {
const validationError = validateStep(step);
if (validationError) {
import('@metona-team/metona-toast')
.then((mod) => mod.default.warning(validationError))
.catch(() => {});
return;
}
if (step < STEPS.length - 1) {
setStep(step + 1);
return;