新增源码绑定、代码面板、流程分组可视化与分组模式切换

- Web: 点击节点在底部代码面板展示源码(语法高亮、可折叠)
- Web: 画布按目录/文件聚类为背景框,头部新增分组模式切换(目录/文件/无)
- Web: 流程横幅、流程/分组列表与节点详情展示 summary
- CLI: 新增 overview 推导与运行器
- scripts: 手动标注 self-report summary

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
朱葛
2026-07-22 18:22:45 +08:00
parent cb23f814c7
commit 35958b408c
23 changed files with 5313 additions and 1168 deletions
+52 -2
View File
@@ -1,8 +1,58 @@
import { defineConfig } from "vite";
import { defineConfig, type Plugin } from "vite";
import react from "@vitejs/plugin-react";
import { readFileSync } from "node:fs";
import { resolve, sep } from "node:path";
/**
* 开发期源码服务:GET /__source?root=&file=&start=&end=
* 按报告里的 location 从磁盘读取真实源码片段,实现「报告 → 代码库」绑定。
* 仅用于本地开发;做了基本的路径穿越防护(结果路径必须落在 root 内)。
*/
function sourceServer(): Plugin {
return {
name: "code-visualize-source-server",
configureServer(server) {
server.middlewares.use("/__source", (req, res) => {
try {
const url = new URL(req.url ?? "", "http://localhost");
const root = url.searchParams.get("root") ?? "";
const file = url.searchParams.get("file") ?? "";
const start = Number(url.searchParams.get("start") ?? "1");
const end = Number(url.searchParams.get("end") ?? String(start));
if (!root || !file) {
res.statusCode = 400;
res.end("missing root/file");
return;
}
const rootResolved = resolve(root);
const target = resolve(rootResolved, file);
if (target !== rootResolved && !target.startsWith(rootResolved + sep)) {
res.statusCode = 403;
res.end("path escapes root");
return;
}
const content = readFileSync(target, "utf-8");
const allLines = content.split(/\r?\n/);
const from = Math.max(1, start);
const to = Math.min(allLines.length, Math.max(from, end));
const code = allLines.slice(from - 1, to).join("\n");
res.setHeader("Content-Type", "application/json; charset=utf-8");
res.end(JSON.stringify({ file, startLine: from, endLine: to, code }));
} catch (e) {
res.statusCode = 404;
res.end(e instanceof Error ? e.message : "read error");
}
});
},
};
}
export default defineConfig({
plugins: [react()],
plugins: [react(), sourceServer()],
server: {
port: 5300,
open: true,