39 KiB
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
- 解耦内容/结构 / Decoupled content/structure — 文档扁平存储, TOC 独立树, 支持重组不触碰内容
- 草稿/发布分离 / Draft/publish separation —
body_draftvsbody,status0/1 - 卡片/块扩展 / Card/block extensibility — Typst 的 CeTZ/Fletcher 块已天然支持
- 分层搜索 scope / Hierarchical search scope — user → team → team/book
- 文档嵌入与引用 / Document embedding —
#include实现内容嵌入
借鉴 MrDoc 的模式 / Patterns Adopted from MrDoc
- 4 级可见性 / 4-tier visibility — 公开/私密/指定用户/访问码
- 协作者角色 / Collaborator roles — 0=仅自身文档, 1=所有文档
- 双重表示 / Dual representation —
parent_doc+ 序列化 TOC JSON, 支持拖拽排序 - 权限感知搜索 / Permission-aware search — 预过滤可见 ID 列表
- 文档分享令牌 / DocShare token — 独立于项目权限的单文档分享
- 软删除 / Soft delete —
status枚举 + 回收站
VizTyp 的差异化优势 / VizTyp's Differentiators
- 实时 SVG 渲染 / Real-time SVG rendering — typst.ts WASM 编译,语雀和 MrDoc 均无
- Typst 规范格式 / Typst canonical format — 开放、可编译、可 Git,非 Lake 私有
- 可视化知识图谱 / Visual knowledge graph —
DependencyGraph.svelte超越两者 - 本地优先 / 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 intypes.ts+ backendmodels.rs. Frontend↔backend viaapi/client.
类型定义 / Type Definitions (planned for types.ts)
// 工作空间 / 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 | 说明 |
|---|---|---|
| 多 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
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)— 父组件注册折叠函数
<Editor
content={activeTab.content}
onInput={handleContentChange}
onCursorChange={(info) => cursor = info}
{registerScroll}
{registerFold}
/>
项目初始化 / Project Initialization
从零创建项目的脚手架步骤 / Scaffolding steps to create the project from scratch
1. 创建 Monorepo 结构 / Create Monorepo Structure
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)
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
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
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)
{
"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
name = "viztyp"
version = "0.1.0"
compiler = "0.14.0"
entrypoint = "src/lib.typ"
功能清单 / Feature Checklist
📝 文档编辑
- 项目脚手架 (Vite + Svelte 5 + Tauri)
- typst.ts WASM 初始化 + 字体加载
- CodeMirror 6 编辑器 + 思源主题
- 实时 SVG 预览 (debounced)
- 多 Tab 编辑
- 文件 I/O (打开/保存/导出 PDF/SVG)
- 查找替换 (Ctrl+H)
- 可拖拽编辑器/预览分栏
📚 知识库管理
- Workspace/KB/Document/TOCNode 类型定义
- 知识库状态管理 (接 Rust 后端)
- 知识库树 (KB 列表 → 文档树两级展开)
- Typst
#include树解析 → TOC 构建 (借鉴语雀解耦模式) - 草稿/发布分离 (
.typ.draftsidecar) - 版本历史 (快照 + 恢复, MrDoc 式完整快照)
- 标签系统 (文档级标签)
- 文档模板 (未实现, 优先级低)
🔍 搜索与发现
- 大纲解析 (#heading) + 跳转
- 依赖图可视化 (DependencyGraph.svelte, 手写 SVG)
- 编译诊断 (typst.ts)
- 权限感知全文搜索 (预过滤可见 KB)
- 全局搜索 (Ctrl+Shift+F, KB/Tabs 双模式)
- 文档分享令牌 (DocShare)
👥 协作与权限
- 用户认证 (JWT + SHA-256 密码哈希)
- 权限系统 (4 级可见性 + 协作者角色)
- KB 协作者管理 (reader/writer/admin)
- 协作状态 (presence 轮询)
🔌 系统扩展
- IDE 布局 (ActivityBar/LeftDock/RightDock/StatusBar)
- 命令面板 (Ctrl+K)
- 插件系统 (内置 TS 插件 + 钩子体系: onCompile/onSave/onPublish/onRender)
- CSS/JS 片段管理
- 工作区导出/导入 (JSON 含文档内容)
- 主题与设置 (light/dark/system + 编辑器设置)
- Tauri sidecar 自动启动/清理
✅ 实现状态: 除"文档模板"外全部功能已实现并通过验证 (
svelte-check0/0 +cargo build0 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)
/* 暗色 / 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.
"@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)
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 必须)
{
"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
# 根级 / 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.mdAGENTS.md(单文件双语 / single file bilingual)
- 代码注释双语:源码中的注释使用中英文双语,格式为:
Code comments are bilingual, formatted as:
// 初始化 typst.ts 编译器 / Initialize typst.ts compiler - 同步更新规则:修改代码时,必须同步更新对应的文档(EN + ZH)。 When modifying code, you MUST update the corresponding docs (both EN and ZH).
常见陷阱 / Common Pitfalls
-
Svelte 5 runes
.svelte.ts文件:状态管理文件必须用.svelte.ts后缀才能使用$state/$derived等 runes。 State management files MUST use.svelte.tssuffix to use$state/$derivedrunes. -
ViewUpdate导入:必须从@codemirror/view导入,umbrella 包codemirror不重新导出它。 Must import from@codemirror/view, NOT from umbrellacodemirror. -
Uint8Array → Blob:TypeScript 6 严格类型下需用
pdfData.buffer as ArrayBuffer。 Under TS6 strict mode, usepdfData.buffer as ArrayBuffer. -
Vite 端口锁定:Vite dev server 锁定 port 5173 (
strictPort: true),与 Tauri 约定一致。 Vite dev server is locked to port 5173 (strictPort: true), matching Tauri convention. -
Vite dev server 后台运行:用
nohup ... &或setsid bash -c '...' </dev/null确保进程不被 shell 超时杀死。 Usenohuporsetsidwith</dev/nullto keep dev server alive after shell timeout. -
TOC 与内容解耦 (借鉴语雀):不要在文档内容中硬编码目录结构,应维护独立的 TOC 树。 Following Yuque: don't hardcode TOC structure in document content; maintain a separate TOC tree.
-
权限感知搜索 (借鉴 MrDoc):搜索前必须预过滤用户可见的知识库 ID 列表。 Following MrDoc: always pre-filter visible KB IDs before executing search queries.
Agent 工作检查清单 / Agent Checklist
修改代码时必须 / When modifying code, you MUST:
- 同步更新
README.md和README.zh.md/ Sync both READMEs - 双语注释保持一致 / Keep bilingual comments consistent
- 如果改了 typst.ts 相关代码,检查
@myriaddreamin/*版本是否一致 (0.7.0) / Check version sync - 如果改了 WASM/渲染逻辑,验证 Web 和 Tauri 两个目标都正常 / Verify both targets
- 如果新增 Typst 库 API,更新
typst.toml版本号 / Bump typst.toml version - 如果改了 CodeMirror 主题/高亮,验证
@lezer/highlighttags 是否存在 / Validate tag existence - 如果改了布局/CSS,验证
--viztyp-*变量在 light + dark 都正常 / Verify both themes - 如果新增知识管理模块,确保 TOC 与内容解耦 (语雀模式) / Keep TOC decoupled from content
- 如果新增权限/搜索功能,确保权限预过滤 / Ensure permission pre-filtering
- 运行
svelte-check确保 0 errors / Run svelte-check for 0 errors