# AGENTS.md > Agent 工作指南 / Agent Working Guide > 本文件原为**新项目创建蓝图**,现已记录 VizTyp 的完整实现(全部功能已完成)。 > This file was a **greenfield blueprint**, now documents VizTyp's full implementation (all 5 phases complete). --- ## 项目概述 / Project Overview VizTyp 是一个基于 Typst 的**个人与团队知识管理系统**,融合语雀的结构化知识管理与 MrDoc 的私有化部署理念,采用**思源笔记**风格 IDE 布局,面向 Web 和 Tauri 桌面双平台。 VizTyp is a **personal and team knowledge management system** based on Typst, combining Yuque's structured knowledge management with MrDoc's self-hosted philosophy, with a **SiYuan-note** style IDE layout, targeting both Web and Tauri desktop platforms. ### 核心定位 / Core Positioning > **"可本地优先的语雀" + "实时可视化的 MrDoc"** > "Local-first Yuque + real-time visual MrDoc" | 特性 / Feature | 说明 / Description | |---|---| | **本地优先 / Local-first** | Typst 文件存储在本地磁盘,支持 Git 版本控制,不依赖云端 (vs 语雀/MrDoc 的云端存储) | | **实时编译 / Real-time compilation** | Typst 源码通过 typst.ts WASM 在浏览器/webview 中实时编译,生成 SVG 预览 (语雀/MrDoc 均无此能力) | | **Typst 作为规范格式 / Typst as canonical format** | 开放、可编译、可版本控制,非私有格式 (vs 语雀的 Lake 私有格式 / MrDoc 的 Markdown 字符串) | | **可视化知识图谱 / Visual knowledge graph** | 基于 `#include`/`#import` 的依赖图可视化,超越语雀和 MrDoc 的隐式引用 | | **思源风格 IDE / SiYuan-style IDE** | ActivityBar + LeftDock + Center(Tabs + Editor/Preview Split) + RightDock + StatusBar | | **双平台共享 / Dual-platform sharing** | Web 和桌面使用同一套 Svelte 5 前端,零重复代码 | ### 竞品对比 / Competitive Analysis | 维度 / Dimension | 语雀 / Yuque | MrDoc (觅思文档) | **VizTyp** | |---|---|---|---| | **层级结构 / Hierarchy** | Team → Book → Doc (严格三层) | Project → Doc (`parent_doc` 自引用) | Workspace → KB → Doc (Typst `#include` 树) | | **内容/结构 / Content/Structure** | **解耦**: 文档扁平存储, TOC 独立树 | **双重**: `parent_doc` + `ProjectToc` JSON | `refs.ts` 解析 `#include` 树 (已实现) | | **文档格式 / Doc format** | Lake (私有 block/card 格式) | Markdown 字符串 (无 AST) | **Typst** (开放, 可编译, 可 Git) | | **草稿/发布 / Draft/Publish** | `body_draft` vs `body`, `status` 0/1 | `pre_content` vs `content` | `.typ.draft` sidecar + publish (已实现) | | **权限 / Permissions** | Team: Admin/Member/ReadOnly; KB: reader/writer | 4 级: 公开/私密/指定用户/访问码 | 4 级 + JWT 认证 + 协作者角色 (已实现) | | **实时协作 / Real-time collab** | 实时协同 → 降级为锁模式 | 无 (异步编辑 + 版本快照) | typst.ts 实时 SVG 预览 + presence 轮询 | | **知识图谱 / Knowledge graph** | 隐式 (文档嵌入), 无可视化 | 无 | **DependencyGraph.svelte** 手写 SVG (已实现) | | **搜索 / Search** | 分层 scope (user→team→book) | 权限感知 (预过滤 project IDs), Whoosh+jieba | 权限感知全文搜索 (预过滤可见 KB, 已实现) | | **部署模式 / Deployment** | SaaS 云端 | 私有化部署 (Django 单体) | **本地优先** (文件 + 可选同步) | | **技术栈 / Tech stack** | Java 后端 + React 前端 | Django SSR + jQuery/LayUI | **Svelte 5 SPA + Tauri** | #### 借鉴语雀的模式 / Patterns Adopted from Yuque 1. **解耦内容/结构 / Decoupled content/structure** — 文档扁平存储, TOC 独立树, 支持重组不触碰内容 2. **草稿/发布分离 / Draft/publish separation** — `body_draft` vs `body`, `status` 0/1 3. **卡片/块扩展 / Card/block extensibility** — Typst 的 CeTZ/Fletcher 块已天然支持 4. **分层搜索 scope / Hierarchical search scope** — user → team → team/book 5. **文档嵌入与引用 / Document embedding** — `#include` 实现内容嵌入 #### 借鉴 MrDoc 的模式 / Patterns Adopted from MrDoc 1. **4 级可见性 / 4-tier visibility** — 公开/私密/指定用户/访问码 2. **协作者角色 / Collaborator roles** — 0=仅自身文档, 1=所有文档 3. **双重表示 / Dual representation** — `parent_doc` + 序列化 TOC JSON, 支持拖拽排序 4. **权限感知搜索 / Permission-aware search** — 预过滤可见 ID 列表 5. **文档分享令牌 / DocShare token** — 独立于项目权限的单文档分享 6. **软删除 / Soft delete** — `status` 枚举 + 回收站 #### VizTyp 的差异化优势 / VizTyp's Differentiators 1. **实时 SVG 渲染 / Real-time SVG rendering** — typst.ts WASM 编译,语雀和 MrDoc 均无 2. **Typst 规范格式 / Typst canonical format** — 开放、可编译、可 Git,非 Lake 私有 3. **可视化知识图谱 / Visual knowledge graph** — `DependencyGraph.svelte` 超越两者 4. **本地优先 / Local-first** — 文件存储在磁盘,天然 Git 兼容 --- ## 知识管理架构 / Knowledge Management Architecture ### 三层结构 / Three-Layer Structure 借鉴语雀和 MrDoc 的核心模式,VizTyp 采用三层知识管理结构: Drawing from Yuque and MrDoc's core patterns, VizTyp adopts a three-layer knowledge management structure: ``` ┌─────────────────────────────────────────────────────────────────┐ │ Workspace (工作空间) │ │ ├── KnowledgeBase (知识库) ← 一个 .typ 项目文件夹 / Typst project folder │ │ ├── Document (文档) ← 单个 .typ 文件 / single Typst file │ │ │ ├── Sub-document ← #include 的子文件 / included child │ │ │ └── (无限嵌套) ← 基于 #include 的自然树 │ │ ├── Document ... │ │ └── TOC (目录树) ← 解耦的独立结构树 / Decoupled structure tree │ ├── KnowledgeBase ... │ └── (知识库集合) / KB collection └─────────────────────────────────────────────────────────────────┘ ``` ### 核心数据模型设计 / Core Data Model Design > ✅ **以下类型已在 `types.ts` + 后端 `models.rs` 完整实现。前端与后端通过 `api/` 客户端交互。** > ✅ **These types are fully implemented in `types.ts` + backend `models.rs`. Frontend↔backend via `api/` client.** #### 类型定义 / Type Definitions (planned for `types.ts`) ```typescript // 工作空间 / Workspace — 顶层容器 / Top-level container interface Workspace { id: string; name: string; knowledgeBases: KnowledgeBase[]; members?: WorkspaceMember[]; // 团队成员 / Team members (future) createdAt: number; } // 知识库 / KnowledgeBase — 类似语雀的 Book 或 MrDoc 的 Project interface KnowledgeBase { id: string; name: string; icon?: string; description: string; rootPath: string; // 本地文件夹路径 / Local folder path visibility: KBVisibility; // 可见性 / Visibility level collaborators?: Collaborator[]; // 协作者 / Collaborators (future) toc: TOCNode[]; // 解耦的目录树 / Decoupled TOC tree tags: Tag[]; // 标签 / Tags createdAt: number; updatedAt: number; } // 可见性 / Visibility — 借鉴 MrDoc 4 级权限 type KBVisibility = | 'public' // 公开 — 任何人可读 / Anyone can read (role=0) | 'private' // 私密 — 仅所有者 + 协作者 / Owner + collaborators only (role=1) | 'specified' // 指定用户可见 / Specified users (role=2) | 'access_code'; // 访问码可见 / Access code required (role=3) // 目录树节点 / TOC Node — 借鉴语雀的 TOC 解耦模式 interface TOCNode { uuid: string; type: 'DOC' | 'TITLE' | 'LINK'; // 文档引用 / 纯分组 / 外部链接 title: string; docId?: string; // type=DOC 时的文档 ID parentId?: string; // 父节点 UUID (构建树) level: number; // 深度, 0=root sortOrder: number; // 同级排序 / Ordering among siblings openByDefault?: boolean; // 默认展开 / Expand by default } // 文档 / Document — 单个 Typst 文件 interface Document { id: string; kbId: string; // 所属知识库 / Parent KB title: string; filePath: string; // 本地文件路径 / Local file path content: string; // 发布内容 / Published content draftContent?: string; // 草稿内容 / Draft content (借鉴 MrDoc pre_content) status: 'draft' | 'published' | 'deleted'; // 软删除 / Soft delete editorMode: 'typst'; // 编辑器模式 (未来可扩展) tags: string[]; // 标签 / Tags wordCount: number; createdAt: number; updatedAt: number; publishedAt?: number; } // 协作者 / Collaborator (future) interface Collaborator { userId: string; kbId: string; role: 'reader' | 'writer' | 'admin'; } // 标签 / Tag interface Tag { id: string; name: string; color?: string; } // 文档分享 / Document Share — 借鉴 MrDoc DocShare interface DocShare { token: string; docId: string; shareType: 'public' | 'private'; // private 需访问码 shareCode?: string; // 私密分享的访问码 isEnabled: boolean; createdAt: number; } // 版本历史 / Version History interface DocVersion { id: string; docId: string; content: string; // 完整快照 / Full snapshot (MrDoc 模式) creator: string; createdAt: number; } ``` ### 权限系统设计 / Permission System Design #### 知识库可见性 (借鉴 MrDoc) / KB Visibility (from MrDoc) | 可见性 / Visibility | 说明 / Description | 访问控制 / Access Control | |---|---|---| | `public` | 公开 / Public | 任何人可读 / Anyone can read | | `private` | 私密 / Private | 仅所有者 + 协作者 / Owner + collaborators only | | `specified` | 指定用户 / Specified users | 白名单用户 / Whitelisted user IDs | | `access_code` | 访问码 / Access code | 需输入访问码 (存储于 cookie/localStorage) | #### 协作者角色 (借鉴 MrDoc + 语雀) / Collaborator Roles (from MrDoc + Yuque) | 角色 / Role | 能力 / Capabilities | |---|---| | `reader` | 只读 / Read only | | `writer` | 创建文档, 编辑/删除自身文档 / Create docs, edit/delete own docs | | `admin` | 创建文档, 编辑所有文档, 管理知识库 / Create docs, edit all docs, manage KB | #### 权限感知搜索 (借鉴 MrDoc) / Permission-Aware Search (from MrDoc) ``` 搜索流程 / Search flow: 1. 获取用户可见的知识库 ID 列表 / Get visible KB ID list for user 2. 在可见范围内执行全文搜索 / Execute full-text search within visible scope 3. 返回结果带知识库上下文 / Return results with KB context ``` --- ## 技术栈 / Tech Stack | 层 / Layer | 选型 / Choice | 版本 / Version | |---|---|---| | 前端框架 / Frontend | Svelte 5 (runes 模式) + Vite | Svelte `^5.55`, Vite `^8.0` | | 语言 / Language | TypeScript | `~6.0` | | 代码编辑器 / Code editor | CodeMirror 6 (basicSetup + 自定义思源主题) | `^6.0` | | Typst 集成 / Typst | typst.ts 运行时编译 (Mode B) | `@myriaddreamin/*` 锁定 `0.7.0` | | 桌面外壳 / Desktop | Tauri v2 | `@tauri-apps/cli ^2` | | 包管理器 / Package manager | Yarn (classic) | — | | Typst 可视化 / Typst viz | CeTZ + Fletcher (消费) + 自研库 | — | | 全文搜索 / Full-text search | (规划中 / planned) flexsearch 或 lunr | — | --- ## 布局架构 / Layout Architecture ``` ┌─ ActivityBar (40px) ─┬─ LeftDock (220px) ─┬─ Center Area ─────────────┬─ RightDock (260px) ─┐ │ │ │ TabBar (32px) │ DockPanel │ │ 📁 知识库树 │ DocTree │ ┌─────────┬─────────┐ │ (Outline/Diag/Mark) │ │ 🔍 搜索 │ (文件导航 + │ │ Editor │ Preview │ │ │ │ 🔖 书签 │ 右键菜单 + │ │ (CM6) │ (SVG) │ │ · 大纲 Outline │ │ 🕸 依赖图 │ #include 树) │ │ │ │ │ · 诊断 Diagnostics │ │ 📤 分享 (规划中) │ │ │ │ │ │ · 书签 Bookmarks │ │ │ │ └─────────┴─────────┘ │ │ │ ➕ 新建 │ │ │ │ │ 📂 打开 │ │ (拖拽分隔条调整比例) │ │ │ 💾 保存 │ │ │ │ │ ⚙️ 设置 │ │ │ │ │ 🌙 主题 │ │ │ │ ├──────────────────────┴─────────────────────┴───────────────────────────┴─────────────────────┤ │ StatusBar (26px): 子块统计 | 字符/词/行 | 光标 Ln/Col | 选区计数 | 同步状态 │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ ``` ### 布局演进计划 / Layout Evolution Plan | 版本 / Version | LeftDock 内容 / Content | 说明 | |---|---|---| | ~~早期 / Early~~ | ~~DocTree (已打开 Tab 列表)~~ | 多 Tab 编辑, 每个 Tab 一个 .typ 文件 | | **当前 / Current** | **KBTree + DocTree (顶部 tab 切换)** | 类似语雀: 左侧显示所有知识库, 点击展开文档树; 顶部切换"知识库/已打开" | | **未来 / Future** | KBTree + 搜索 + 收藏 + 标签 | 类似语雀工作台 | --- ## 目录结构 / Directory Structure ``` viztyp/ ├── packages/ │ └── frontend/ # Svelte 前端 (Web + Tauri 共享) │ ├── package.json # 前端依赖 │ ├── vite.config.ts # Vite 配置 (COOP/COEP headers, WASM exclude) │ ├── tsconfig.json / tsconfig.app.json / tsconfig.node.json │ ├── index.html │ └── src/ │ ├── main.ts # Svelte 5 mount 入口 │ ├── App.svelte # 主编排器 (布局 + 状态 + 全局快捷键) │ ├── app.css # CSS 变量系统 (--viztyp-*) │ ├── lib/ │ │ ├── types.ts # Tab + Document/KB/Workspace 接口 (已实现全部) │ │ ├── typst-init.ts # typst.ts WASM 初始化 (手动 compiler+renderer) │ │ ├── Editor.svelte # CodeMirror 6 编辑器 (+ view 逃逸口 + search 扩展) │ │ ├── Preview.svelte # SVG 实时预览 (debounced, 错误状态) │ │ ├── cm-theme.ts # CodeMirror 思源风格主题 (安全 tags) │ │ ├── ActivityBar.svelte # 最左侧垂直图标栏 (12 图标 + dock 切换) │ │ ├── TabBar.svelte # 多标签栏 (center 区域内) │ │ ├── DocTree.svelte # 已打开 Tab 文档树 │ │ ├── kb-tree.svelte # 左侧知识库树 (KB → Doc 两级展开) ✅ │ │ ├── DockPanel.svelte # 右侧 Dock (大纲/诊断/依赖图/历史/书签 5 tab) │ │ ├── OutlinePanel.svelte # Typst #heading 大纲 │ │ ├── DiagnosticsPanel.svelte # 编译诊断 (typst.ts) │ │ ├── DependencyGraph.svelte # SVG 依赖图 (知识图谱核心, 手写 SVG) │ │ ├── HistoryPanel.svelte # 版本历史 (快照 + 恢复) │ │ ├── StatusBar.svelte # 底部状态栏 (统计 + 在线协作者) │ │ ├── CommandPalette.svelte # Ctrl+K 命令面板 (模糊搜索) │ │ ├── SearchPanel.svelte # 全局搜索 (KB 权限感知 + Tabs 双模式) │ │ ├── FindReplace.svelte # 查找替换 (CM6 内置面板) │ │ ├── PluginManager.svelte # 插件管理 (Alt+P, 开关切换) │ │ ├── TagEditor.svelte # 文档标签编辑 modal │ │ ├── CollaboratorManager.svelte # KB 协作者管理 modal ✅ │ │ ├── SnippetSettings.svelte # CSS/JS 片段编辑器 │ │ ├── Login.svelte # 登录/注册全屏覆盖 ✅ │ │ ├── Settings.svelte # 设置面板 (Ctrl+,) │ │ ├── command-registry.ts # 命令注册系统 (去重 + 模糊搜索) │ │ ├── theme.svelte.ts # 主题状态 (light/dark/system) │ │ ├── settings.svelte.ts # 设置状态 (localStorage 持久化) │ │ ├── auth.svelte.ts # 认证状态 (JWT, login/register/logout) ✅ │ │ ├── kb-store.svelte.ts # 知识库状态 (Workspace/KB/Doc, 接后端) ✅ │ │ ├── collab.svelte.ts # 协作状态 (presence 轮询) ✅ │ │ ├── snippets.svelte.ts # CSS/JS 片段管理 (CSS 动态注入) │ │ ├── plugin-loader.svelte.ts # 插件加载器 + 钩子体系 (onCompile/onSave/...) ✅ │ │ ├── outline.ts # parseOutline() — 解析 #heading │ │ ├── refs.ts # parseReferences() + buildDependencyGraph() │ │ ├── stats.ts # parseStats() — 文档统计 + CursorInfo │ │ ├── history.ts # 版本快照 (接后端 API) │ │ ├── share-manager.ts # 文档分享令牌 (接后端 API) ✅ │ │ ├── search-engine.ts # 权限感知全文搜索 (接后端 API) ✅ │ │ ├── workspace.ts # 导出/导入工作区 JSON (接后端 API) ✅ │ │ ├── find-replace.ts # CM6 搜索面板辅助 │ │ ├── file-ops.ts # openTypstFile/saveTypstFile/exportPdf/exportSvg │ │ ├── typst-snippets.ts # 30+ Typst slash 命令片段 │ │ ├── api/ # ── Rust 后端 HTTP 客户端 ── │ │ │ ├── client.ts # fetch 封装 (JWT Bearer + access_code) │ │ │ ├── kb-api.ts # KB/文档/版本/标签/搜索/分享 API │ │ │ ├── auth-api.ts # 注册/登录/me API ✅ │ │ │ └── types.ts # 后端对应 TS 类型 │ │ └── plugins/ # ── 内置插件 ── │ │ ├── word-count-pro.ts # 字数统计 Pro (onCompile 钩子) │ │ └── auto-outline.ts # 自动大纲 (onSave 钩子) │ └── typst/ │ └── main.typ.ts # 默认欢迎文档 (TS 导出, 注入虚拟 FS /main.typ) ├── server/ # Rust HTTP 后端 (tokio + hyper, Web/Tauri 共用) │ ├── Cargo.toml # tokio + hyper + serde + jsonwebtoken + sha2 │ ├── README.md # 后端文档 + API 表 + 打包流程 │ └── src/ │ ├── main.rs # tokio main + hyper server (端口 7480) │ ├── handlers.rs # 手写路由 + 所有 API 端点 │ ├── store.rs # JSON 文件存储 (workspace/users/versions/...) │ ├── auth.rs # JWT 签发/验证 + 权限校验 (4 级可见性 + 角色) │ └── models.rs # Rust struct 镜像前端类型 ├── typst-pkg/ # 自研 Typst 库 (有独立 typst.toml) │ ├── typst.toml # 包清单: name="viztyp" version="0.1.0" compiler="0.14.0" │ └── src/lib.typ # 库入口 (version + get-version) ├── src-tauri/ # Tauri v2 桌面外壳 (sidecar 自动启动后端) │ ├── Cargo.toml # tauri + dialog/fs/shell/log 插件 │ ├── tauri.conf.json # CSP + externalBin (sidecar) + COOP/COEP notes │ ├── capabilities/default.json # core/dialog/fs/shell 权限 │ ├── COOP_COEP_NOTES.md # 跨源隔离处理说明 │ └── src/{lib.rs, main.rs} # Tauri 入口 (sidecar 启动 + RunEvent::Exit 清理) ├── scripts/ │ └── build-sidecar.sh # 构建 server + 带 target-triple 后缀复制 ├── package.json # 根级 (Tauri CLI + server/frontend 脚本) ├── README.md / README.zh.md # 双语文档对 └── AGENTS.md # 本文件 ``` --- ## 数据流 / Data Flow ### 编辑器数据流 (核心) / Editor data flow (core) ``` .typ 源码 → CodeMirror 编辑器 → (onInput 回调) → Tab 状态更新 → typst.ts 编译器 (WASM) → Uint8Array artifact → 渲染器 (WASM) → SVG ``` 源码被添加到**虚拟文件系统** (`/main.typ`),不是真实磁盘路径。 Source is added to a **virtual filesystem** (`/main.typ`), not the real disk. ### 知识库数据流 (目标) / KB data flow (target) ``` Workspace → KnowledgeBase → Document (.typ 文件) │ ┌──────────┼──────────┐ ▼ ▼ ▼ CodeMirror typst.ts refs.ts (编辑) (编译→SVG) (依赖树→TOC) │ │ │ └──────────┼──────────┘ ▼ DocTree (TOC) + Outline + DependencyGraph │ ┌──────────┼──────────┐ ▼ ▼ ▼ Preview(SVG) Search Version History ``` --- ## 状态管理 / State Management 项目使用 **Svelte 5 runes** 模式,不使用 stores。 ### 全局状态文件 / Global state files | 文件 / File | 用途 / Purpose | 存储 / Storage | |---|---|---| | `theme.svelte.ts` | 主题模式 (light/dark/system) | localStorage `viztyp:theme` | | `settings.svelte.ts` | 编辑器/预览设置 | localStorage `viztyp:settings` | | `snippets.svelte.ts` | CSS/JS 片段管理 (CSS 动态注入) | localStorage `viztyp:snippets` | | `kb-store.svelte.ts` | 知识库状态 (Workspace/KB/Doc, 接后端) | 后端 API (server/) | | `auth.svelte.ts` | 认证状态 (JWT, login/register/logout) | localStorage `viztyp:token` | | `collab.svelte.ts` | 协作状态 (presence 10s 轮询) | 后端 API | | `plugin-loader.svelte.ts` | 插件启用状态 | localStorage `viztyp:plugins-enabled` | ### App.svelte 核心状态 / Core state ```ts tabs: Tab[] // 所有打开的标签页 activeId: string // 当前活跃标签 ID showLeftDock: boolean // 左 dock 可见性 showRightDock: boolean // 右 dock 可见性 dockTab: DockTab // 右 dock 活跃 tab (outline/diagnostics/deps/history/bookmarks) cursor: CursorInfo // 光标位置 {line, col, selectionLength} bookmarks: number[] // 书签行号列表 splitPercent: number // 编辑器/预览分栏比例 (15-85) leftDockView: 'tabs'|'kb' // 左 dock 视图切换 (已打开 Tab | 知识库 KB 树) diagnostics: string[] // typst.ts 编译诊断 // 模态可见性 / Modal visibility: showCommandPalette, showSettings, showGlobalSearch, showTagEditor, showPluginManager, showCollaborators, showSnippets: boolean // 通过 kb-store/auth/collab 模块管理: // workspace, activeKbId, versions, docTags, currentUser, onlineCount ``` ### 编辑器回调注册模式 / Editor callback registration pattern Editor.svelte 使用**注册回调**模式与父组件通信: - `onInput(value)` — 文档变更 - `onCursorChange(info)` — 光标移动 - `registerScroll(fn)` — 父组件注册跳转函数 - `registerFold(fn)` — 父组件注册折叠函数 ```svelte cursor = info} {registerScroll} {registerFold} /> ``` --- ## 项目初始化 / Project Initialization > 从零创建项目的脚手架步骤 / Scaffolding steps to create the project from scratch ### 1. 创建 Monorepo 结构 / Create Monorepo Structure ```bash mkdir viztyp && cd viztyp git init # 根级 package.json — 仅 Tauri CLI / Root package.json — Tauri CLI only yarn init -y yarn add -D @tauri-apps/cli@^2 ``` ### 2. 创建前端 / Create Frontend (Svelte 5 + Vite) ```bash mkdir -p packages/frontend cd packages/frontend # Vite + Svelte 5 + TypeScript / Scaffold with Vite yarn create vite . --template svelte-ts # 安装核心依赖 / Install core dependencies yarn add @myriaddreamin/typst.ts@0.7.0 \ @myriaddreamin/typst.svelte@0.7.0 \ @myriaddreamin/typst-ts-renderer@0.7.0 \ @myriaddreamin/typst-ts-web-compiler@0.7.0 yarn add @codemirror/view @codemirror/state @codemirror/commands \ @codemirror/language @codemirror/autocomplete @codemirror/search \ @codemirror/language-data @codemirror/basic-setup @lezer/highlight yarn add -D @tsconfig/svelte svelte-check ``` ### 3. 初始化 Tauri / Initialize Tauri ```bash cd ../.. # 回到根目录 / Back to root yarn tauri init # 配置 / Configure: # - frontend dev path: packages/frontend # - frontend build path: packages/frontend/dist # - dev server URL: http://localhost:5173 ``` ### 4. 关键配置文件 / Key Configuration Files #### `packages/frontend/vite.config.ts` ```typescript import { defineConfig } from 'vite'; import { svelte } from '@sveltejs/vite-plugin-svelte'; export default defineConfig({ plugins: [svelte()], server: { port: 5173, strictPort: true, // 与 Tauri 约定一致 / Match Tauri convention headers: { 'Cross-Origin-Opener-Policy': 'same-origin', 'Cross-Origin-Embedder-Policy': 'require-corp', }, }, optimizeDeps: { exclude: ['@myriaddreamin/typst-ts-web-compiler', '@myriaddreamin/typst-ts-renderer'], }, worker: { format: 'es', }, }); ``` #### `src-tauri/tauri.conf.json` (关键片段 / Key excerpts) ```json { "build": { "frontendDist": "../packages/frontend/dist", "devUrl": "http://localhost:5173" }, "app": { "security": { "csp": "script-src 'self' 'wasm-unsafe-eval'", "headers": { "Cross-Origin-Opener-Policy": "same-origin", "Cross-Origin-Embedder-Policy": "require-corp" } } } } ``` #### `typst-pkg/typst.toml` ```toml name = "viztyp" version = "0.1.0" compiler = "0.14.0" entrypoint = "src/lib.typ" ``` --- ## 功能清单 / Feature Checklist ### 📝 文档编辑 - [x] 项目脚手架 (Vite + Svelte 5 + Tauri) - [x] typst.ts WASM 初始化 + 字体加载 - [x] CodeMirror 6 编辑器 + 思源主题 - [x] 实时 SVG 预览 (debounced) - [x] 多 Tab 编辑 - [x] 文件 I/O (打开/保存/导出 PDF/SVG) - [x] 查找替换 (Ctrl+H) - [x] 可拖拽编辑器/预览分栏 ### 📚 知识库管理 - [x] Workspace/KB/Document/TOCNode 类型定义 - [x] 知识库状态管理 (接 Rust 后端) - [x] 知识库树 (KB 列表 → 文档树两级展开) - [x] Typst `#include` 树解析 → TOC 构建 (借鉴语雀解耦模式) - [x] 草稿/发布分离 (`.typ.draft` sidecar) - [x] 版本历史 (快照 + 恢复, MrDoc 式完整快照) - [x] 标签系统 (文档级标签) - [ ] 文档模板 *(未实现, 优先级低)* ### 🔍 搜索与发现 - [x] 大纲解析 (#heading) + 跳转 - [x] 依赖图可视化 (DependencyGraph.svelte, 手写 SVG) - [x] 编译诊断 (typst.ts) - [x] 权限感知全文搜索 (预过滤可见 KB) - [x] 全局搜索 (Ctrl+Shift+F, KB/Tabs 双模式) - [x] 文档分享令牌 (DocShare) ### 👥 协作与权限 - [x] 用户认证 (JWT + SHA-256 密码哈希) - [x] 权限系统 (4 级可见性 + 协作者角色) - [x] KB 协作者管理 (reader/writer/admin) - [x] 协作状态 (presence 轮询) ### 🔌 系统扩展 - [x] IDE 布局 (ActivityBar/LeftDock/RightDock/StatusBar) - [x] 命令面板 (Ctrl+K) - [x] 插件系统 (内置 TS 插件 + 钩子体系: onCompile/onSave/onPublish/onRender) - [x] CSS/JS 片段管理 - [x] 工作区导出/导入 (JSON 含文档内容) - [x] 主题与设置 (light/dark/system + 编辑器设置) - [x] Tauri sidecar 自动启动/清理 > ✅ **实现状态**: 除"文档模板"外全部功能已实现并通过验证 (`svelte-check` 0/0 + `cargo build` 0 warnings + `vite build` 通过)。 --- ## CSS 变量系统 / CSS Variable System 所有颜色/尺寸/字体通过 `--viztyp-*` CSS 变量管理,定义在 `app.css`。 All colors/sizes/fonts managed via `--viztyp-*` CSS variables, defined in `app.css`. ### 思源色板 (目标值, 从思源源码提取) / SiYuan Palette (target values from SiYuan source) ```css /* 暗色 / Dark */ --viztyp-bg-primary: #1e1e1e; /* 编辑器背景 / Editor background */ --viztyp-bg-secondary: #262626; /* 面板/工具栏 / Panels/toolbars */ --viztyp-bg-activity: #1e1e1e; /* ActivityBar */ --viztyp-border-primary: #363636; /* 边框, 0.5px 发丝线 / Borders, 0.5px hairline */ --viztyp-accent: #3573f0; /* 强调蓝 / Accent blue */ --viztyp-text-primary: #dadada; /* 主文字 / Primary text */ --viztyp-text-secondary: #9aa0a6; /* 次文字 / Secondary text */ /* 尺寸 / Sizing */ --viztyp-radius: 6px; /* 标准圆角 / Standard radius */ --viztyp-radius-large: 12px; /* 大圆角 / Large radius */ --viztyp-activitybar-width: 42px; --viztyp-tab-height: 42px; --viztyp-toolbar-height: 32px; --viztyp-statusbar-height: 32px; /* 动画 / Animation */ --viztyp-transition: 0.2s cubic-bezier(0, 0, 0.2, 1); ``` ### 思源交互设计规范 / SiYuan Interaction Design Specs ``` Dock 活跃态: 实心蓝药丸 (#3573f0 背景 + 白色图标), 非左边竖条 Tab 活跃态: 3px 蓝色下划线 背景分层: background #1e1e1e vs surface #262626 (两色分层) 边框: #363636, 0.5px 发丝线 (不是 1px) ``` --- ## Typst.ts 集成关键约定 / typst.ts Integration Rules ### ⚠️ 版本锁定 / Version Pinning 所有 `@myriaddreamin/*` 包**必须锁定 `0.7.0`**。混用版本会导致静默失败。 All `@myriaddreamin/*` packages **MUST be pinned to `0.7.0`**. Mixing causes silent failures. ```json "@myriaddreamin/typst-ts-renderer": "0.7.0", "@myriaddreamin/typst-ts-web-compiler": "0.7.0", "@myriaddreamin/typst.svelte": "0.7.0", "@myriaddreamin/typst.ts": "0.7.0" ``` ### WASM 资源加载 (必须用 Vite `?url`) / WASM loading (MUST use Vite `?url`) ```ts import compilerWasm from '@myriaddreamin/typst-ts-web-compiler/pkg/typst_ts_web_compiler_bg.wasm?url'; import rendererWasm from '@myriaddreamin/typst-ts-renderer/pkg/typst_ts_renderer_bg.wasm?url'; ``` ❌ 硬编码路径在 Tauri 生产构建中会失效 / Hardcoded paths break in Tauri production builds. ### 初始化守卫 / Init Guard `setCompilerInitOptions` / `setRendererInitOptions` **必须只调用一次**,用模块级布尔标志防止 HMR 重复初始化。 Must be called exactly once. Guard with module-level boolean flag. ### ⚠️ 字体不内置 / Fonts Not Bundled typst.ts **不包含字体**。必须通过 `loadFonts([], { assets: ['text', 'cjk'] })` 显式加载 CJK 字体。 typst.ts does **NOT** bundle fonts. Load CJK explicitly via `loadFonts([], { assets: ['text', 'cjk'] })`. --- ## Tauri 桌面关键约定 / Tauri Desktop Rules ### ⚠️ COOP/COEP Headers (线程化 WASM 必须) ```json { "app": { "security": { "headers": { "Cross-Origin-Opener-Policy": "same-origin", "Cross-Origin-Embedder-Policy": "require-corp" } } } } ``` Vite dev server 也需镜像这两个 header (已在 `vite.config.ts` 配置)。 Vite dev server must mirror these headers too (already configured in `vite.config.ts`). ### CSP 必须允许 WASM / CSP Must Allow WASM ``` script-src 'self' 'wasm-unsafe-eval' ``` --- ## CodeMirror 6 约定 / CodeMirror 6 Conventions ### 自定义主题 / Custom Theme 编辑器使用 `cm-theme.ts` 中定义的 `siyuanFullTheme`,不使用 `@codemirror/theme-one-dark`。 Editor uses `siyuanFullTheme` from `cm-theme.ts`, does NOT use `@codemirror/theme-one-dark`. ### ⚠️ HighlightStyle 标签陷阱 / HighlightStyle Tag Pitfall `@lezer/highlight` 的 `tags` 对象中,**`t.functionName` 不存在**(不是直接属性)。会导致 `TypeError: Cannot read properties of undefined (reading 'id')`。 The `tags` object from `@lezer/highlight` does **NOT** have `t.functionName` (not a direct property). Causes `TypeError: Cannot read properties of undefined (reading 'id')`. 安全的标签 / Safe tags: `t.comment`, `t.keyword`, `t.string`, `t.number`, `t.variableName`, `t.typeName`, `t.operator`, `t.meta`, `t.invalid`. ❌ 嵌套标签修饰器也不安全: `t.function(t.variableName)` 在当前版本可能未定义。 ❌ Nested tag modifiers also unsafe: `t.function(t.variableName)` may be undefined in current version. --- ## 键盘快捷键 / Keyboard Shortcuts | 快捷键 / Shortcut | 动作 / Action | |---|---| | `Ctrl+K` | 命令面板 / Command palette | | `Ctrl+S` | 保存 / Save | | `Ctrl+N` | 新建标签 / New tab | | `Ctrl+O` | 打开文件 / Open file | | `Ctrl+W` | 关闭标签 / Close tab | | `Ctrl+J` | 切换主题 / Toggle theme | | `Ctrl+H` | 查找替换 / Find & replace | | `Ctrl+B` | 切换左 dock / Toggle left dock | | `Ctrl+,` | 设置 / Settings | | `Ctrl+Shift+F` | 全局搜索 / Global search | | `Ctrl+Shift+D` | 切换右 dock 到诊断 / Dock → diagnostics | | `Ctrl+Shift+B` | 切换书签 / Toggle bookmark | | `Alt+1` | 切换右 dock / Toggle right dock | | `Alt+G` | 依赖图 / Dependency graph | | `Alt+H` | 版本历史 / Version history | | `Alt+P` | 插件管理 / Plugin manager | --- ## 开发命令 / Development Commands ```bash # 根级 / Root yarn install # 安装 Tauri CLI # 前端 / Frontend cd packages/frontend && yarn install # 安装前端依赖 cd packages/frontend && yarn dev # Web 开发服务器 (Vite, port 5173) cd packages/frontend && yarn build # Web 生产构建 cd packages/frontend && npx svelte-check --tsconfig ./tsconfig.json # 类型检查 # 桌面 / Desktop yarn tauri dev # 桌面开发 (Tauri + Vite) yarn tauri build # 桌面生产构建 (安装包) ``` --- ## 文档约定 / Documentation Convention ⚠️ 强制 / Mandatory - **双语并行**:所有文档维护中英文两个版本,文件名成对出现。 All documentation is maintained in bilingual EN/ZH pairs. - `README.md` + `README.zh.md` - `AGENTS.md` (单文件双语 / single file bilingual) - **代码注释双语**:源码中的注释使用中英文双语,格式为: Code comments are bilingual, formatted as: ```ts // 初始化 typst.ts 编译器 / Initialize typst.ts compiler ``` - **同步更新规则**:修改代码时,**必须同步更新对应的文档**(EN + ZH)。 When modifying code, you **MUST update the corresponding docs** (both EN and ZH). --- ## 常见陷阱 / Common Pitfalls 1. **Svelte 5 runes `.svelte.ts` 文件**:状态管理文件必须用 `.svelte.ts` 后缀才能使用 `$state`/`$derived` 等 runes。 State management files MUST use `.svelte.ts` suffix to use `$state`/`$derived` runes. 2. **`ViewUpdate` 导入**:必须从 `@codemirror/view` 导入,umbrella 包 `codemirror` 不重新导出它。 Must import from `@codemirror/view`, NOT from umbrella `codemirror`. 3. **Uint8Array → Blob**:TypeScript 6 严格类型下需用 `pdfData.buffer as ArrayBuffer`。 Under TS6 strict mode, use `pdfData.buffer as ArrayBuffer`. 4. **Vite 端口锁定**:Vite dev server 锁定 port 5173 (`strictPort: true`),与 Tauri 约定一致。 Vite dev server is locked to port 5173 (`strictPort: true`), matching Tauri convention. 5. **Vite dev server 后台运行**:用 `nohup ... &` 或 `setsid bash -c '...'