[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-94577":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":8,"htmlUrl":8,"language":9,"languages":8,"totalLinesOfCode":8,"stars":10,"forks":11,"watchers":12,"openIssues":13,"contributorsCount":13,"subscribersCount":13,"size":13,"stars1d":13,"stars7d":13,"stars30d":13,"stars90d":13,"forks30d":13,"starsTrendScore":13,"compositeScore":14,"rankGlobal":8,"rankLanguage":8,"license":8,"archived":15,"fork":15,"defaultBranch":16,"hasWiki":15,"hasPages":15,"topics":17,"createdAt":8,"pushedAt":8,"updatedAt":18,"readmeContent":19,"aiSummary":20,"trendingCount":13,"starSnapshotCount":13,"syncStatus":11,"lastSyncTime":21,"discoverSource":22},94577,"Chat-Canvas","SamuelGuan\u002FChat-Canvas","SamuelGuan",null,"TypeScript",117,2,4,0,35.43,false,"main",[],"2026-08-24 04:01:22","# Chat Canvas\n\n> 画布式 AI 对话工具 -- 把聊天变成一张可连线、可分支的有向图\n\n---\n\n## 这是什么\n\nChat Canvas 不是普通聊天页。它把每个聊天单元做成一张**卡片**，卡片之间可以**连线**，形成一张有向图。你可以在画布上自由拖拽、连线、分叉对话，像搭积木一样组织 AI 交互。\n\n每种卡片是一个独立的知识单元：\n\n| 卡片 | 能力 |\n|---|---|\n| Chat | 多轮对话、流式输出、分支追问、多模态输入 |\n| Note | Markdown 笔记，支持 GFM \u002F 数学公式 \u002F 代码高亮 |\n| PDF | 上传 PDF，`pdf.js` 渲染，哈希去重存储 |\n| Picture | 上传图片，内容哈希命名，去重引用 |\n\n---\n\n## 核心架构\n\n```mermaid\nflowchart LR\n    A[React + Zustand] --> B[React Flow 画布]\n    A --> C[卡片插件系统]\n    A --> D[三级文件持久化]\n    D --> E[index.json]\n    D --> F[project.json]\n    D --> G[session.json]\n    C --> H[Chat]\n    C --> I[Note]\n    C --> J[PDF]\n    C --> K[Picture]\n    B --> H\n    B --> I\n    B --> J\n    B --> K\n```\n\n### 三级文件持久化\n\n不是一个大 JSON blob，而是分层落盘：\n\n```\nchat-canvas-data\u002F\n  index.json          # 项目列表 + 当前激活项目\n  schema\u002F             # JSON Schema 权威格式定义\n  projects\u002F\n    \u003Cpid>\u002F\n      project.json    # Session 列表 + 资源索引\n      assets\u002F         # PDF \u002F 图片二进制 (SHA-256 命名)\n      sessions\u002F\n        \u003Csid>.json    # 完整图数据: 节点 + 边 + 视口 + 消息\n```\n\n### 卡片插件化\n\n所有卡片通过统一注册表接入，新增卡片类型无需全项目改 `if-else`。每种卡片声明自己的默认字段、渲染组件、上下文输出方式、搜索参与方式。\n\n### 上下文构建\n\n对话的上下文不是简单的\"全文复制\"，而是：\n1. 沿 `inherit` 边 BFS 收集上游\n2. 每个上游节点调用自己的结构化 `output()`\n3. 目标卡片调用自己的 `input()` 消费\n4. 注入全局 \u002F 卡片级 system prompt\n\n---\n\n## 运行模式\n\n| 模式 | 命令 | 存储后端 |\n|---|---|---|\n| 浏览器开发 | `npm run dev` | Vite dev server 中间件 |\n| Electron 开发 | `npm run dev:electron` | 主进程本地文件系统 |\n| 浏览器构建 | `npm run build` | 无文件后端 (回退空画布) |\n| Electron 打包 | `npm run package` | 本地文件系统 |\n\n启动时自动探测可用后端，优先级：远程服务 > Electron IPC > dev server > 抛错回退。\n\n---\n\n## 快速开始\n\n```bash\n# 安装依赖\nnpm install\n\n# 浏览器开发模式\nnpm run dev\n\n# Electron 桌面开发模式\nnpm run dev:electron\n\n# 类型检查\nnpm run typecheck\n\n# 数据一致性校验 (外部改文件后手动触发)\nnpm run check-data\n```\n\n### 打包\n\n```bash\n# Windows\nnpm run package:win\n\n# macOS\nnpm run package:mac\n\n# Linux\nnpm run package:linux\n```\n\n---\n\n## 技术栈\n\n| 层面 | 技术 |\n|---|---|\n| 框架 | React 18 + TypeScript |\n| 状态管理 | Zustand |\n| 画布 | @xyflow\u002Freact (React Flow) |\n| 桌面壳 | Electron 32 + electron-vite |\n| 样式 | Tailwind CSS |\n| Markdown | react-markdown + remark-gfm + rehype-mathjax |\n| PDF 渲染 | pdfjs-dist |\n| 代码高亮 | highlight.js |\n| 文件监听 | chokidar |\n\n---\n\n## 项目结构\n\n```\nsrc\u002F\n  types\u002F            # 核心数据模型 (GraphNode, GraphEdge, SessionData...)\n  store\u002F            # Zustand 状态管理 + 启动引导 + 分层层管理器\n    useCanvasStore   # 画布世界总管家: 节点\u002F边\u002FSession\u002FProject\u002F导入导出\n    useChatStore     # 流式消息状态机\n    useSettingsStore # 模型配置\u002F主题\u002FAPI Key\n    bootstrap        # 启动序列: 适配器选择 -> 迁移 -> 校验 -> 加载\n    sessionRuntime   # 激活 Session 防抖落盘\n    projectManager   # project.json 管理\n    rootManager      # index.json 管理\n  cards\u002F            # 卡片插件系统\n    builtin\u002F         # 内置插件: chat, note, pdf, picture\n    registry         # 插件注册表\n    communicateAdapter # 上下文构建适配\n  components\u002F       # UI 组件\n    Canvas\u002F          # React Flow 画布交互\n    ChatNode\u002F        # 最复杂的卡片: 流式对话\u002F分叉\u002F追问\n    NoteNode\u002F        # Markdown 编辑器\n    PdfNode\u002F         # PDF 查看器\n    PictureNode\u002F     # 图片查看器\n    Settings\u002F        # 设置对话框\n  lib\u002F              # 工具库\n    storage\u002F         # 持久化核心: 协议\u002F路径\u002F适配器\u002F一致性\u002F迁移\n    llm              # LLM 调用 + 流式解析 + 请求锁\n    contextBuilder   # 上下文构建引擎\n    resourceIndex    # 资源引用索引\n    sessionBundle    # 导入导出 Bundle\n  hooks\u002F            # React hooks\nelectron\u002F           # Electron 主进程 \u002F preload \u002F IPC \u002F 菜单\nscripts\u002F            # CLI 工具 (数据校验)\ndocs\u002F               # 设计文档\n```\n\n---\n\n## 工程亮点\n\n- **三级文件持久化**：index -> project -> session 逐层分离，按需加载，独立防抖落盘\n- **一致性自愈**：启动校验 + 文件监听 + CLI 工具三道防线，外部改文件不损坏数据\n- **资源索引去重**：SHA-256 内容哈希命名，节点自报引用 + 项目级索引，删除时精确清理\n- **卡片插件化**：注册式架构，新增卡片类型零侵入\n- **激活 Session 单实例权威**：内存唯一状态，非激活以磁盘为准，避免双副本同步\n- **并发控制**：防抖 + 串行后台队列 + Promise 请求锁\n\n---\n\n## 存储协议\n\n持久化层遵循统一的 HTTP 消息服务协议 (v2)，详见 [docs\u002Fstore-protocol.md](docs\u002Fstore-protocol.md)。核心设计：\n\n- 渲染层通过 `StorageAdapter` 接口访问持久化，不直接碰文件系统\n- `ElectronFsAdapter` 与 `DevServerAdapter` 共享同一接口\n- SSE 推送外部变更通知，多写者场景自动收敛\n- 统一错误格式 `{ error, code }`，路径防穿越\n\n---\n\n## 源码导读\n\n如果你是第一次看这个项目，建议按以下顺序阅读 (详见 [docs\u002Fsource-guide.md](docs\u002Fsource-guide.md))：\n\n1. `src\u002Ftypes\u002Findex.ts` -- 数据结构\n2. `src\u002Fmain.tsx` \u002F `src\u002FApp.tsx` -- 入口\n3. `src\u002Fstore\u002Fbootstrap.ts` -- 启动流程\n4. `src\u002Fstore\u002FuseCanvasStore.ts` -- 核心状态\n5. `src\u002Fstore\u002FsessionRuntime.ts` -- 落盘机制\n6. `src\u002Flib\u002Fstorage\u002Fconsistency.ts` -- 自愈逻辑\n7. `src\u002Fcards\u002F` -- 插件系统\n8. `electron\u002F` -- 桌面桥接\n\n---\n\n## License\n\nMIT License\n","Chat Canvas 是一款画布式 AI 对话组织工具，将多轮对话、笔记、PDF 和图片等知识单元抽象为可拖拽、可连线的节点卡片，构建有向图结构的交互工作流。核心支持卡片插件化架构、基于继承关系的结构化上下文传递、三级分层文件持久化（index\u002Fproject\u002Fsession），以及 React Flow 驱动的可视化画布。适用于需要非线性梳理思路、对比多个 AI 回应、整合多源信息（如文档+对话+标注）的研究型协作、AI 辅助写作与知识建模场景。","2026-08-12 02:30:08","CREATED_QUERY"]