🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

墨记 Wiki opqnext/moji-docs

DeepSeek Harness
opqnext57 天前有提交已提供中文文档扫描:高危

用 Git 管理 Markdown 笔记并全文检索

37.2/100
综合分
6
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/9/17 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

自动兼容检查有告警:未发布到 npm registry,仅可从源码安装。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add opqnext/moji-docs
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:仅索引
是什么
dsh 原生插件 · dev
装得上吗
静态安装检查有提示项,装前建议看一眼 README
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 57 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查⚠ 装前注意

未发布到 npm registry,仅可从源码安装

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✗npm 包moji-docs(未发布到 npm,仅可源码安装)
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/30 06:18:59

🔴 安全扫描发现高危能力自动 · 静态分析源码
v2.7.0
🔴 扫描:高危尚无人工评估

静态扫描发现安装期即执行代码,或命令参数由运行时变量拼接(参数来源无法静态判定,从严处理)。

安装时即执行脚本读写/删除本地文件发起外部网络请求
查看扫描证据(共 109 处,展示前 73 条)
  • 读取本地文件
    main/conflict-resolver.ts:31
    if (!existsSync(dir)) {
  • 写入本地文件
    main/conflict-resolver.ts:32
    mkdirSync(dir, { recursive: true })
  • 写入本地文件
    main/conflict-resolver.ts:35
    writeFileSync(fullPath, oursContent, 'utf-8')
  • 写入本地文件
    main/conflict-resolver.ts:55
    writeFileSync(conflictFullPath, theirsContent, 'utf-8')
  • 读取本地文件
    main/database.ts:7
    if (!existsSync(mojiDir)) {
  • 写入本地文件
    main/database.ts:8
    mkdirSync(mojiDir, { recursive: true })
  • 读取本地文件
    main/git-sync.ts:30
    const isRepo = existsSync(join(docsRoot, '.git'))
  • 读取本地文件
    main/git-sync.ts:59
    if (existsSync(gitignorePath)) {
  • 读取本地文件
    main/git-sync.ts:60
    const content = readFileSync(gitignorePath, 'utf-8')
  • 写入本地文件
    main/git-sync.ts:62
    writeFileSync(gitignorePath, content.trimEnd() + '\n' + requiredLine + '\n')
  • 写入本地文件
    main/git-sync.ts:65
    writeFileSync(gitignorePath, requiredLine + '\n')
  • 发起网络请求
    main/git-sync.ts:173
    await git.fetch('origin')
  • 读取本地文件
    main/git-sync.ts:202
    return existsSync(join(docsRoot, '.git', 'refs'))
  • 读取本地文件
    main/git-sync.ts:209
    if (!existsSync(docsRoot)) {
  • 写入本地文件
    main/git-sync.ts:210
    mkdirSync(docsRoot, { recursive: true })
  • 读取本地文件
    main/image-manager.ts:21
    if (!existsSync(monthDir)) {
  • 写入本地文件
    main/image-manager.ts:22
    mkdirSync(monthDir, { recursive: true })
  • 写入本地文件
    main/image-manager.ts:26
    writeFileSync(fullPath, buffer)
  • 读取本地文件
    main/image-manager.ts:33
    if (!existsSync(assetsDir)) return { deleted: [], total: 0 }
  • 删除本地文件
    main/image-manager.ts:57
    unlinkSync(fullPath)
  • 读取本地文件
    main/image-manager.ts:69
    if (!existsSync(dir)) return
  • 读取本地文件
    main/image-manager.ts:72
    entries = readdirSync(dir, { withFileTypes: true })
  • 读取本地文件
    main/image-manager.ts:86
    const content = readFileSync(fullPath, 'utf-8')
  • 读取本地文件
    main/image-manager.ts:96
    if (!existsSync(dir)) return
  • 读取本地文件
    main/index.ts:32
    if (!existsSync(configPath)) return null
  • 读取本地文件
    main/index.ts:34
    return JSON.parse(readFileSync(configPath, 'utf-8'))
  • 写入本地文件
    main/index.ts:41
    writeFileSync(getConfigPath(), JSON.stringify(config, null, 2))
  • 读取本地文件
    main/index.ts:93
    if (!existsSync(docsRoot)) {
  • 写入本地文件
    main/index.ts:94
    mkdirSync(docsRoot, { recursive: true })
  • 发起网络请求
    main/index.ts:122
    return net.fetch(pathToFileURL(resolved).toString())
  • 写入本地文件
    main/index.ts:164
    mkdirSync(docsRoot, { recursive: true })
  • 写入本地文件
    main/index.ts:167
    mkdirSync(docsRoot, { recursive: true })
  • 读取本地文件
    main/index.ts:183
    if (!existsSync(join(docsRoot, '.git'))) {
  • 写入本地文件
    main/index.ts:232
    writeFileSync(result.filePath, pdfData)
  • 读取本地文件
    main/indexer.ts:53
    entries = await readdir(dir, { withFileTypes: true })
  • 读取本地文件
    main/indexer.ts:69
    stat(fullPath).then(st => {
  • 读取本地文件
    main/indexer.ts:148
    readFile(join(docsRoot, fp), 'utf-8')
  • 读取本地文件
    main/indexer.ts:245
    if (!existsSync(indexFullPath)) {
  • 读取本地文件
    main/indexer.ts:248
    const dirStat = statSync(dirFullPath)
  • 写入本地文件
    main/indexer.ts:257
    writeFileSync(indexFullPath, raw, 'utf-8')
  • 读取本地文件
    main/indexer.ts:271
    if (!existsSync(dir)) return
  • 读取本地文件
    main/ipc/doc.ts:79
    if (existsSync(fullPath)) {
  • 读取本地文件
    main/ipc/doc.ts:80
    const raw = await readFile(fullPath, 'utf-8')
  • 读取本地文件
    main/ipc/doc.ts:117
    if (params.file_path && existsSync(join(docsRoot, params.file_path))) {
  • 读取本地文件
    main/ipc/doc.ts:119
    const raw = await readFile(fullPath, 'utf-8')
  • 读取本地文件
    main/ipc/doc.ts:143
    if (existsSync(newDirFull)) {
  • 写入本地文件
    main/ipc/doc.ts:148
    await writeFile(fullPath, newRaw, 'utf-8')
  • 写入本地文件
    main/ipc/doc.ts:151
    mkdirSync(dirname(newDirFull), { recursive: true })
  • 写入本地文件
    main/ipc/doc.ts:152
    renameSync(oldDirFull, newDirFull)
  • 写入本地文件
    main/ipc/doc.ts:158
    try { mkdirSync(dirname(oldDirFull), { recursive: true }); renameSync(newDirFull, oldDirFull) } catch {}
  • 写入本地文件
    main/ipc/doc.ts:158
    try { mkdirSync(dirname(oldDirFull), { recursive: true }); renameSync(newDirFull, oldDirFull) } catch {}
  • 读取本地文件
    main/ipc/doc.ts:170
    if (existsSync(newFullPath)) {
  • 写入本地文件
    main/ipc/doc.ts:175
    await writeFile(newFullPath, newRaw, 'utf-8')
  • 删除本地文件
    main/ipc/doc.ts:178
    unlinkSync(fullPath)
  • 删除本地文件
    main/ipc/doc.ts:264
    unlinkSync(fullPath)
  • 删除本地文件
    main/ipc/doc.ts:477
    unlinkSync(fullPath)
  • 删除本地文件
    main/ipc/doc.ts:480
    rmdirSync(dirPath)
  • 删除本地文件
    main/ipc/doc.ts:499
    rmdirSync(dir)
  • 发起网络请求
    main/ipc/image.ts:16
    const resp = await net.fetch(url)
  • 读取本地文件
    main/ipc/image.ts:28
    buffer = readFileSync(localPath)
  • 读取本地文件
    main/ipc/image.ts:47
    buffer = readFileSync(localPath)
  • 写入本地文件
    main/ipc/image.ts:67
    writeFileSync(result.filePath, buffer)
  • 读取本地文件
    main/ipc/settings.ts:61
    if (!existsSync(gitDir)) {
  • 读取本地文件
    main/ipc/version.ts:9
    if (!existsSync(join(docsRoot, '.git'))) return []
  • 读取本地文件
    main/ipc/version.ts:27
    if (!existsSync(join(docsRoot, '.git'))) return null
  • 读取本地文件
    main/ipc/version.ts:45
    if (!existsSync(join(docsRoot, '.git'))) throw new Error('Git 仓库未初始化')
  • 读取本地文件
    main/lfs.ts:32
    if (existsSync(attrPath)) {
  • 读取本地文件
    main/lfs.ts:33
    const content = readFileSync(attrPath, 'utf-8')
  • 写入本地文件
    main/lfs.ts:35
    writeFileSync(attrPath, content.trimEnd() + '\n' + LFS_GITATTRIBUTES)
  • 写入本地文件
    main/lfs.ts:38
    writeFileSync(attrPath, LFS_GITATTRIBUTES)
  • 读取本地文件
    main/lfs.ts:50
    const tracking = existsSync(attrPath) && readFileSync(attrPath, 'utf-8').includes('filter=lfs')
  • 读取本地文件
    main/lfs.ts:50
    const tracking = existsSync(attrPath) && readFileSync(attrPath, 'utf-8').includes('filter=lfs')
  • 发起网络请求
    main/updater.ts:77
    const request = net.request(url)
扫描于 2026/11/3(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 全文检索
  • 跨平台桌面应用

MojiDocs 是一款跨平台的 Markdown Wiki 桌面应用,基于 Electron + Vue 3 + SQLite 构建。

README

由 DeepSeek 最新模型翻译生成
MojiDocs 离线优先的 Markdown Wiki 桌面应用 Git 管文件,SQLite 管索引,数据完全属于你 功能特性 ·下载安装 ·快速开始 ·技术栈 ·开发指南 ·开源协议 简介 MojiDocs 是一款跨平台的 Markdown Wiki 桌面应用,基于 Electron + Vue 3 + SQLite 构建。 核心理念:.md 文件是唯一数据源,通过 Git 跟踪和同步;SQLite 仅作为全文搜索索引,可随时从文件重建。你的笔记以标准 Markdown 格式存储在本地文件系统中,完全兼容 Obsidian、Hugo、Hexo 等工具。 功能特性 文档管理 - 文档/目录创建、编辑、删除、移动、置顶 - 树形结构浏览(最近 / 全部 / 树形三种视图) - 拖拽导入 .md 文件 Markdown 编辑器 - 双栏实时预览 / 单栏 / 纯预览模式切换 - 工具栏:加粗、斜体、标题、引用、列表、链接、图片、代码块、表格 - 图片粘贴上传(截图 → Ctrl+V → 自动保存到 assets/) - 14 种 Markdown 渲染主题(GitHub、掘金、VuePress 等) 搜索与版本 - SQLite FTS5 全文搜索(关键字高亮 + 上下文片段) - Git 版本历史(浏览、预览、回滚) 同步与导出
展开完整文档(README 剩余 1 节)
MojiDocs

离线优先的 Markdown Wiki 桌面应用 Git 管文件,SQLite 管索引,数据完全属于你

功能特性 ·下载安装 ·快速开始 ·技术栈 ·开发指南 ·开源协议

简介

MojiDocs 是一款跨平台的 Markdown Wiki 桌面应用,基于 Electron + Vue 3 + SQLite 构建。

核心理念:.md 文件是唯一数据源,通过 Git 跟踪和同步;SQLite 仅作为全文搜索索引,可随时从文件重建。你的笔记以标准 Markdown 格式存储在本地文件系统中,完全兼容 Obsidian、Hugo、Hexo 等工具。

功能特性

文档管理
- 文档/目录创建、编辑、删除、移动、置顶
- 树形结构浏览(最近 / 全部 / 树形三种视图)
- 拖拽导入 .md 文件

Markdown 编辑器
- 双栏实时预览 / 单栏 / 纯预览模式切换
- 工具栏:加粗、斜体、标题、引用、列表、链接、图片、代码块、表格
- 图片粘贴上传(截图 → Ctrl+V → 自动保存到 assets/)
- 14 种 Markdown 渲染主题(GitHub、掘金、VuePress 等)

搜索与版本
- SQLite FTS5 全文搜索(关键字高亮 + 上下文片段)
- Git 版本历史(浏览、预览、回滚)

同步与导出
- Git 定时同步(pull + push,支持冲突检测)
- PDF 导出 / 打印
- 离线优先,所有操作本地立即完成

个性化
- 主题颜色自定义(色谱 + 十六进制输入)
- 数据大盘(文章/目录/版本统计)
- 回收站(软删除 + 级联恢复)

下载安装

前往 GitHub Releases 下载对应平台的安装包:

| 平台 | 格式 |
| macOS | .dmg |
| Windows | .exe |
| Linux | .AppImage / .deb |

macOS 安装说明

由于应用未使用 Apple 开发者证书签名,从 GitHub 下载安装后 macOS 可能提示「文件已损坏」或「无法验证开发者」。请使用以下任一方法解决:

方法一:终端执行(推荐)

xattr -cr /Applications/MojiDocs.app

方法二:右键点击应用图标 → 选择「打开」→ 在弹窗中点击「打开」

这是 macOS Gatekeeper 安全机制的限制,与应用本身无关。每次安装或更新新版本后需重新执行一次。

快速开始

环境要求

- Node.js ≥ 18
- npm ≥ 9

开发运行

git clone https://github.com/opqnext/moji-docs.git
cd moji-docs
npm install
npm run dev

构建打包

npm run build # 编译
npm run package # 打包为安装包(产物在 release/ 目录)

技术栈

| 技术 | 版本 | 用途 |
| Electron | 33 | 跨平台桌面框架 |
| Vue 3 | 3.5 | 前端 UI 框架 |
| electron-vite | 2.3 | 构建工具 |
| better-sqlite3 | 11 | SQLite 数据库(索引 + FTS5 全文搜索) |
| marked | 17 | Markdown 渲染 |
| highlight.js | 11 | 代码语法高亮 |
| simple-git | 3.27 | Git 同步 |
| chokidar | 3.6 | 文件系统监听 |
| electron-builder | 25 | 应用打包 |

项目结构

moji-docs/
├── main/ # 主进程(Node.js) │ ├── index.ts # 入口:窗口、协议、IPC │ ├── database.ts # SQLite 初始化 │ ├── indexer.ts # 文件 → 索引构建 │ ├── git-sync.ts # Git 同步调度 │ ├── file-watcher.ts # 文件系统监听 │ └── ipc/ # IPC 通道 ├── preload/ # 预加载脚本 ├── renderer/ # 渲染进程(Vue 3) │ └── src/ │ ├── views/ # 页面组件 │ └── components/ # 通用组件 ├── assets/ # 应用图标 ├── scripts/ # 工具脚本 └── doc/ # 项目文档

开发指南

热更新

| 修改内容 | 是否需要重启 |
| renderer/ 下的 Vue/CSS 文件 | 不需要(HMR 热更新) |
| main/ 下的主进程代码 | 需要重新运行 npm run dev |

调试

- 渲染进程:开发模式自动打开 DevTools,或按 Cmd+Option+I
- 主进程:console.log() 输出到终端,或使用 --inspect=9229 连接 Chrome DevTools

版本发布

1. 更新 package.json 中的 version
2. npm run build && npm run package
3. 在 GitHub Releases 创建 Release(tag: v1.x.x)
4. 上传安装包

数据存储

用户数据存储在自选的本地目录中,结构如下:

~/MojiDocs/ # 笔记根目录(= Git 仓库根) ├── .moji/ # 应用数据(不同步) │ ├── index.db # SQLite 索引(可重建) │ └── config.json # 本地设置 ├── assets/ # 图片资源(Git 跟踪) ├── Getting Started.md # 笔记文件 └── Projects/ # 目录 └── Project A.md

- 卸载或重装应用不会影响用户数据
- .moji/ 目录自动被 .gitignore 排除,不会同步到远程

Star History

开源协议

MIT License © 2018-2025 opqnext
预览分享卡片长什么样 ↓opqnext/moji-docs
分享 · DeepSeek Harness Hub
opqnext/moji-docs

用 Git 管理 Markdown 笔记并全文检索

这是你的仓库?认领条目

回到顶部