feat: 提交 task-045 至 task-058 收口产物

- 收口 rust final closure checklist,推进页面/块系统/Mindmap/CLI/AI tools 到最终 cutover 状态

- 按 ai-frontend-simplification-plan-v1 接入 Hermes bridge,合并 AI 面板并清理旧前端编排残留

- 补充 harness 任务与进度记录,加入 CLI smoke 夹具/脚本,并修正文档页 bridge SSR 自请求回退逻辑
This commit is contained in:
lix-2026
2026-04-16 15:24:37 +08:00
parent 98db79b301
commit 2ff10fa86c
47 changed files with 6494 additions and 2674 deletions
File diff suppressed because it is too large Load Diff
@@ -1110,7 +1110,7 @@ export async function POST(request: Request) {
}
const finalOutline = plan
? plan.chapters.flatMap((chapter, chapterIndex) => [
? plan.chapters.flatMap((chapter) => [
{
title: chapter.title,
level: 1,
@@ -1144,7 +1144,8 @@ export async function POST(request: Request) {
pageLinkPattern,
outline: finalOutline,
};
const result = await executeRustBridgeTool<{
// 说明:导图树构建已经交给 Rust runtime,这里只保留 PDF 提取与 transport 壳。
const rustResult = await executeRustBridgeTool<{
ok: boolean;
data?: unknown;
meta?: { title?: string | null; outlineCount?: number | null } | null;
@@ -1156,10 +1157,16 @@ export async function POST(request: Request) {
data: payload,
mode: "result",
});
const mindmapData = (result as any)?.data ?? {
data: { text: pdfTitle },
children: [],
};
const mindmapData =
rustResult.result && typeof rustResult.result === "object" && !Array.isArray(rustResult.result) && "data" in rustResult.result
? ((rustResult.result as { data?: unknown }).data ?? {
data: { text: pdfTitle },
children: [],
})
: {
data: { text: pdfTitle },
children: [],
};
return NextResponse.json({
mindmapData,
@@ -1,9 +1,15 @@
import { NextResponse } from "next/server";
import { isConvexEnabled } from "@/lib/convex/enabled";
import { getAuthedConvexClient } from "@/lib/convex/route";
import { api } from "@/lib/convex/api";
import { buildDocumentBridgeContextWithActor } from "@/lib/documents/bridge";
import { executeRustBridgeTool } from "@/lib/documents/rust-runtime";
import {
buildDocumentBridgeContextWithActor,
buildDocumentCommandEnvelope,
documentBridgeErrorResponse,
} from "@/lib/documents/bridge";
import {
executeRustBridgeMutationTransport,
resolveRustBridgeCommandPlan,
} from "@/lib/documents/rust-runtime";
export const dynamic = "force-dynamic";
@@ -13,39 +19,47 @@ interface EmptyTrashPayload {
export async function POST(request: Request) {
if (isConvexEnabled()) {
const { client } = await getAuthedConvexClient();
const { auth, client } = await getAuthedConvexClient();
const { workspaceId }: EmptyTrashPayload = await request.json().catch(() => ({}));
if (!workspaceId) {
return NextResponse.json({ error: "缺少 workspaceId" }, { status: 400 });
}
const context = buildDocumentBridgeContextWithActor({
request,
actor: {
actorType: "service",
actorId: "mindmap-trash-empty",
sessionId: null,
},
workspaceId,
source: {
channel: "mindmap-trash-route",
client: "wolai-frontend",
},
});
await executeRustBridgeTool({
context,
toolName: "mindmap_empty_trash",
invocationKind: "command",
args: { workspaceId },
data: { workspaceId, source: "mindmap-trash-empty" },
mode: "result",
});
try {
const result = await client.mutation(api.mindmaps.emptyTrashByWorkspace, { workspaceId });
const context = buildDocumentBridgeContextWithActor({
request,
actor: {
actorType: "user",
actorId: auth.userId,
sessionId: null,
},
workspaceId,
source: {
channel: "mindmap-trash-route",
client: "wolai-frontend",
},
});
const envelope = buildDocumentCommandEnvelope({
name: "mindmaps.emptyTrashByWorkspace",
payload: { workspaceId },
context,
target: {
workspaceId,
},
reason: "mindmap-trash:empty",
refs: ["task-047", "mindmap-trash"],
});
const plan = await resolveRustBridgeCommandPlan({ context, envelope });
const result = await executeRustBridgeMutationTransport<{
ok?: boolean;
deletedCount?: number;
}>({
client,
plan,
});
return NextResponse.json({ ok: true, removed: result?.deletedCount ?? 0 });
} catch (error) {
return NextResponse.json({ error: (error as Error).message }, { status: 400 });
return documentBridgeErrorResponse(error);
}
}
@@ -1,7 +1,6 @@
import { NextResponse } from "next/server";
import { isConvexEnabled } from "@/lib/convex/enabled";
import { getAuthedConvexClient } from "@/lib/convex/route";
import { api } from "@/lib/convex/api";
import { buildMindmapRouteMeta } from "@/lib/mindmap/mindmapRouteMeta";
import {
buildDocumentBridgeContextWithActor,
@@ -172,7 +171,43 @@ export async function DELETE(
if (isConvexEnabled()) {
const { auth, client } = await getAuthedConvexClient();
try {
const result = await client.mutation(api.mindmaps.softDelete, { docId, mindmapId });
const context = buildDocumentBridgeContextWithActor({
request,
actor: {
actorType: "user",
actorId: auth.userId,
sessionId: null,
},
workspaceId: null,
source: {
channel: "mindmap-route",
client: "wolai-frontend",
},
});
const envelope = buildDocumentCommandEnvelope({
name: "mindmaps.delete",
payload: {
documentId: docId,
mindmapId,
},
context,
target: {
workspaceId: null,
pageId: docId,
blockId: mindmapId,
},
reason: "mindmap-route:delete",
refs: ["task-047", "mindmap-route"],
});
const plan = await resolveRustBridgeCommandPlan({ context, envelope });
const result = await executeRustBridgeMutationTransport<{
ok?: boolean;
workspace_id?: string | null;
deleted_at?: string | null;
}>({
client,
plan,
});
return NextResponse.json({
...(result ?? { ok: true }),
meta: {
@@ -186,7 +221,7 @@ export async function DELETE(
},
});
} catch (error) {
return NextResponse.json({ error: (error as Error).message }, { status: 400 });
return documentBridgeErrorResponse(error);
}
}
@@ -207,19 +242,43 @@ export async function PATCH(
}
try {
if (action === "purge") {
const result = await client.mutation(api.mindmaps.purge, { docId, mindmapId });
return NextResponse.json({
...(result ?? { ok: true }),
meta: buildMindmapRouteMeta(request, {
workspaceId: result?.workspace_id ?? null,
documentId: docId,
mindmapId,
ownerUserId: auth.userId,
}),
});
}
const result = await client.mutation(api.mindmaps.restore, { docId, mindmapId });
const context = buildDocumentBridgeContextWithActor({
request,
actor: {
actorType: "user",
actorId: auth.userId,
sessionId: null,
},
workspaceId: null,
source: {
channel: "mindmap-route",
client: "wolai-frontend",
},
});
const envelope = buildDocumentCommandEnvelope({
name: action === "purge" ? "mindmaps.purge" : "mindmaps.restore",
payload: {
documentId: docId,
mindmapId,
},
context,
target: {
workspaceId: null,
pageId: docId,
blockId: mindmapId,
},
reason: `mindmap-route:${action}`,
refs: ["task-047", "mindmap-route"],
});
const plan = await resolveRustBridgeCommandPlan({ context, envelope });
const result = await executeRustBridgeMutationTransport<{
ok?: boolean;
workspace_id?: string | null;
updated_at?: string | null;
}>({
client,
plan,
});
return NextResponse.json({
...(result ?? { ok: true }),
meta: {
@@ -229,13 +288,11 @@ export async function PATCH(
mindmapId,
ownerUserId: auth.userId,
}),
updatedAt: result?.updated_at ?? null,
updatedAt: action === "restore" ? result?.updated_at ?? null : null,
},
});
} catch (error) {
const msg = (error as Error).message ?? "操作失败";
const status = msg.includes("未找到") ? 404 : 400;
return NextResponse.json({ error: msg }, { status });
return documentBridgeErrorResponse(error);
}
}
@@ -1,7 +1,6 @@
import { NextResponse } from "next/server";
import { isConvexEnabled } from "@/lib/convex/enabled";
import { getAuthedConvexClient } from "@/lib/convex/route";
import { api } from "@/lib/convex/api";
import {
buildDocumentBridgeContextWithActor,
buildDocumentCommandEnvelope,
@@ -179,19 +178,59 @@ export async function DELETE(
if (isConvexEnabled()) {
const { auth, client } = await getAuthedConvexClient();
const mindmapId = `legacy-${docId}`;
const result = await client.mutation(api.mindmaps.softDelete, { docId, mindmapId });
return NextResponse.json({
...(result ?? { ok: true }),
meta: {
...buildMindmapRouteMeta(request, {
workspaceId: result?.workspace_id ?? null,
try {
const context = buildDocumentBridgeContextWithActor({
request,
actor: {
actorType: "user",
actorId: auth.userId,
sessionId: null,
},
workspaceId: null,
source: {
channel: "mindmap-route",
client: "wolai-frontend",
},
});
const envelope = buildDocumentCommandEnvelope({
name: "mindmaps.delete",
payload: {
documentId: docId,
mindmapId,
ownerUserId: auth.userId,
}),
deletedAt: result?.deleted_at ?? null,
},
});
},
context,
target: {
workspaceId: null,
pageId: docId,
blockId: mindmapId,
},
reason: "mindmap-route:delete",
refs: ["task-047", "mindmap-route"],
});
const plan = await resolveRustBridgeCommandPlan({ context, envelope });
const result = await executeRustBridgeMutationTransport<{
ok?: boolean;
workspace_id?: string | null;
deleted_at?: string | null;
}>({
client,
plan,
});
return NextResponse.json({
...(result ?? { ok: true }),
meta: {
...buildMindmapRouteMeta(request, {
workspaceId: result?.workspace_id ?? null,
documentId: docId,
mindmapId,
ownerUserId: auth.userId,
}),
deletedAt: result?.deleted_at ?? null,
},
});
} catch (error) {
return documentBridgeErrorResponse(error);
}
}
return NextResponse.json({ error: "当前仅支持 Convex 模式" }, { status: 501 });