npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mellos-mapping

v0.28.0

Published

A live layered dependency map for bottom-up development — MCP server + terminal pane. Ghost the design first, then light nodes up from the bottom as they are built and verified.

Readme

Mellos Mapping · 梅勒斯地图

npm downloads MCP registry CI license LINUX DO

English | 简体中文

给 Claude Code 、ChatGPT 桌面 Codex 模式与 Codex CLI 的自下而上 开发实况地图,原生运行在终端里。

Claude 为你构建系统时,对话旁边的分屏实时显示这个系统的分层依赖地图: 最底层是原语,依赖边只允许向下指;虚线幽灵节点是已设计未实现的部分, 转圈的是此刻正在构建的模块,实心绿色代表已构建且已验证。

真实会话:左边 Claude Code,右边地图面板。L0 已验证,L1 刚点亮,上面还是幽灵节点。

为什么

大多数进度汇报是一张任务清单——那是自上而下的世界观。梅勒斯地图反过来生长: 上层节点只能站在下层节点之上,这张图让纪律变得可见:

  • 代码写出来之前,幽灵设计先出现。 Claude 先把完整的设计声明成虚线 幽灵节点;你可以在它还只是一张图的时候就否掉一个坏设计。
  • spinner 在哪,Claude 的注意力就在哪。 一眼回答"它现在在做什么、 站在什么之上?"
  • done 意味着已验证。 节点只有带着证据(一次通过的测试)才会变成 实心绿色。如果后续工作弄裂了地基,那个节点会变红——转圈的上层楼板 下面压着一块红色地基,是最诚实的状态汇报。
  • 地图是账本,不是法官。 工具只拒绝结构性破坏(向上指的边、重复的 rank)。工作流是 Claude 的纪律,写在随插件捆绑的 skill 里;违反纪律 会被看见,而不是被悄悄拦截。

安装

克隆适合自己宿主的分支,运行一个安装命令即可;无需构建。

| 分支 | 使用对象 | 在克隆目录运行 | | --- | --- | --- | | main | 共用源码/任一宿主 | node install.mjs chatgpt-app 或 node install.mjs claude | | claude | Claude Code | node install.mjs | | chatgpt-app | ChatGPT 桌面 App 的 Codex 模式 | node install.mjs |

前置要求为 Node.js 18.17 及以上的 18.x,或 20.3 及以上版本,以及对应宿主的 CLI, 并确保命令在 PATH 中。支持 Windows 10+、macOS 13.0+ 和 glibc 2.28+ 的 Linux,均支持 x64 与 arm64;系统还须满足所选 Node.js 版本的更高要求。发行包自带原生锁绑定, 无需用户本地编译。安装器检查 发行文件和八个 MCP 工具,将运行时保留到克隆目录之外,完成宿主配置。 安装后开启新对话。详见发布与分支说明。

Claude Code 也可以通过插件市场安装:

在 Claude Code 对话里输入两行:

/plugin marketplace add GuangminJu/mellos-mapping
/plugin install mellos-mapping@mellos-mapping

或者在终端里一条命令装完:

claude plugin marketplace add GuangminJu/mellos-mapping && claude plugin install mellos-mapping@mellos-mapping

需要 PATH 上有符合安装要求的 Node.js;使用原生 Claude Code 安装包时也需 单独安装 Node.js。 没有构建步骤:dist/ 是提交进仓库的,克隆即用——dist/server.mjs(MCP 服务器)、dist/watch.mjs(面板)、dist/mmap.mjs(mmap 开关)、 dist/hook-session-start.mjs(由 hooks/hooks.json 注册的 SessionStart 钩子),以及 dist/store-paths.mjs(存储的路径词汇;纯 node 的面板启动 脚本从这里导入,而不是自己抄一份文件名)。

omp(Oh My Pi) 读的是 Claude Code 版本用的同一套插件布局——同一份市场 目录、.mcp.json、技能与斜杠命令——一份发行包同时服务两个宿主:

omp plugin marketplace add GuangminJu/mellos-mapping
omp plugin install mellos-mapping@mellos-mapping

这样装跟的是 main,而发布就是它上面的版本号提升。要冻结版本,就改把某个 版本的检出目录加为市场——GitHub Release 里的 Claude Code 版本 ZIP,或按 tag 检出的克隆:

omp plugin marketplace add "<检出或解压出来的发行目录>"
omp plugin install mellos-mapping@mellos-mapping

omp 不读 hooks/hooks.json,所以那段会话说明由插件的 omp 宿主适配器送达 (dist/omp-extension.mjs,在 package.json#omp.extensions 里声明):同一个 存储、同一段策略文字,Windows 上的 mmap shim 也由它安装。面板仍旧是会话 旁边的终端分屏。请把它当插件安装——omp plugin link 与 npm 包都不是插 件,用它们装会只剩适配器、没有工具。见 omp 安装与限制。

pi 则完全不读那套目录:它加载的是扩展,而且出于设计考虑自己没有 MCP。 所以这个插件自己跟自己讲 MCP——在 package.json#pi.extensions 里声明的扩 展(dist/pi-extension.mjs)会在会话所在目录启动同一个 dist/server.mjs, 八个 mmap_* 工具因此就是同样的八个、同名可用,会话说明也来自同一个存储、 同一段策略文字,与 Claude 钩子打印的一样:

pi install npm:mellos-mapping

加 -l 只装到当前项目而不是所有项目,之后开一个新会话:pi 在会话开始时才 发现包。包里的 skills/ 与 commands/ 随之一并生效——同一套建图纪律, /mmap 也还是同一个斜杠命令。见 pi 安装与行为。

装完之后的第一个会话只会问你一个问题——建图要多积极——并把答案记成 你以后打开的每一个项目的默认。此后钩子会自己把它带进每个新会话;再也没有 "每个项目设置一遍"这回事。见 Setup:选择什么时候建图。

mmap 终端命令(面板的开关切换)在 Windows 上会自己装好:还是这个钩子, 在会话启动时发现 shim 缺失或者还指向旧版本安装,就把 mmap.cmd(cmd、 PowerShell)和 mmap(git-bash)写进 %LOCALAPPDATA%\mellos-mapping\bin, 把这一个目录追加进你的用户 PATH,并通过助手告诉你这件事。PATH 改动 只对新进程生效——而且运行中的 Windows Terminal 连新标签页都继承旧环境, 所以第一次敲 mmap 之前要把终端应用整个关掉重开。PATH 的编辑保持安装器 原有的承诺:条目已经在里面 就什么都不做;遇到 setx 会损坏的 PATH(%VARIABLE% 被展平、超长被截 断),它干脆拒绝。

PATH 被拒绝不等于没命令可用:同样两个 shim 会再写一份到 %LOCALAPPDATA%\Microsoft\WindowsApps(或 ~/.local/bin)——一个你的 PATH 本来就有名字的目录——于是新终端里直接敲 mmap 就能用,完全不用改 PATH。 PATH 很长的机器正是这种情况,也最需要它。命令可以带要打开的页名 (mmap omp-host-support);面板已经开着时再敲一次就是关掉它。

它背后的那一步仍然是个独立命令,留给钩子管不到的情形——--uninstall, 或者 shim 还在、PATH 条目却被你删掉之后重新加回去:

node "<插件目录>/scripts/install-mmap-command.mjs" [--uninstall]

(--json 把安装结果打成一行 JSON 而不是散文——钩子自己调用它时用的就是 这个模式。)npm i -g mellos-mapping 通过 bin 提供同一个 mmap,不涉及 shim。

更新

claude plugin marketplace update mellos-mapping && claude plugin update mellos-mapping@mellos-mapping

要两步是因为 plugin update 只对比本地缓存的 marketplace 克隆——真正 拉取本仓库的是第一条命令。重启 Claude Code 生效。发布即 main 分支 上的版本号提升。(在对话里输入 /plugin 也能打开同一个管理界面。)

omp 也有自己的两步:

omp plugin marketplace update mellos-mapping && omp plugin upgrade mellos-mapping@mellos-mapping

先关面板(面板里按 q):watcher 跑的就是插件副本里的文件,而 Windows 不 允许改名一个正被打开的文件——开着面板升级会以 EPERM 失败并把插件缓存清空 (旧副本已删、新副本未就位),用 omp plugin install mellos-mapping@mellos-mapping --force 修回来。然后:第一条刷新市场目录,第二条按目录重装。omp 还会在启动时尽力刷新超过一天没更新过 的目录条目——除非 marketplace.autoUpdate 设为 off;默认的 notify 模式只把 "有可用更新"写进 debug 日志,所以让更新看得见的是 marketplace update 这一 步。upgrade 不比较版本:它按目录里现在指的内容强制重装,同版本号也会重下—— 因此版本号提升是给发行贴标签,而不是送达的门槛。之后重启 omp,并把仍显示旧 运行文件的面板关掉重开(面板里按 q,再 mmap_open)。

pi 更新的则是它装下的那个包,中间没有市场目录:

pi update npm:mellos-mapping

这是 npm 来源;git 来源由 pi 自己的更新流程校准到你 settings 里写的 ref,带版本的 写法(npm:[email protected])会被跳过。之后重启会话:每个会话各自拥有它启动 的地图服务器进程,仍在运行的会话会一直用开始时的那份副本,直到会话结束。

从 0.19 升级

0.20 把地图存储从 .claude/ 挪到了 .mellos/——地图属于这个工具,不属于 某一个客户端。服务器和 watcher 都会在启动时做一次搬迁,并在 stderr 打一行 提示(mellos-mapping: moved the legacy .claude map store to .mellos/ — commit the move.):

| 0.19 及更早 | 0.20 及之后 | | --- | --- | | .claude/mellos-mapping.json | .mellos/map.json | | .claude/mellos-mapping.pages/ | .mellos/pages/ | | .claude/mellos-mapping.config.json | .mellos/config.json |

搬迁不合并、也不覆盖:.mellos/ 里已经有东西(地图、页目录或配置)的项目 原样不动,无论旧目录里还剩什么。如果地图跟着 git 走,记得把这次搬迁提交 上去——git add -A .claude .mellos 会把它记成重命名,而不是一堆删除加一堆 未跟踪文件。

这一次搬迁是两个进程唯一会碰 .claude/ 的时刻。此后工具只往 .mellos/ 里写,也绝不会写到启动时解析出的项目目录之外。

ChatGPT App · Codex 模式

本版用于 ChatGPT 桌面 App 的 Codex 模式(也称 Codex App)。在源码分支运行 以下命令;在 chatgpt-app 分支运行时省略宿主参数。它会一次配置桌面专用技能、 插件市场与八个 MCP 工具。

node install.mjs chatgpt-app

安装完成后开启新对话。技能默认使用 web-terminal 网页终端: mmap_open {surface: "web-terminal", page: "<slug>"} 启动本地服务后, AI 自动把 URL 打开到当前对话右侧浏览器,直接显示 mmap 终端地图。 不需要粘贴命令或 Computer Use;网页有独立字号调节。 图形 SVG 网页、原生终端和 Markdown 仍然保留。旧 MCP 对话可使用 node "<插件根>/dist/web.mjs" "<项目>" --terminal --page <slug>。 面板排队打开不等于地图已经可见。 详见桌面安装与限制。

在 Windows Terminal 使用 Codex CLI 时(不指桌面 App 内置终端),运行 node <插件根>/scripts/open-pane.mjs <项目目录>——它会在承载本会话的 终端窗口右侧分屏,并保留左侧对话的键盘焦点。识别或聚焦失败时会明确报错, 不会改开其他窗口;--window 用于明确选择独立窗口。加 --page <slug> 指定打开哪一页; 当前会话的面板已经开着时,带 --page 重跑会让它切到那一页。其他会话 或独立窗口中的面板不算当前会话已分屏。面板默认自动跟随正在被写入的页——AI 此刻操作哪张图, 就看哪张图;按 f 开关(手动切页也会关掉),或用 --no-follow 启动。 其他环境在项目目录下的第二个终端(或任意分屏)运行 node <插件根>/dist/watch.mjs。两者接受同一套参数,见 面板参数。

桌面对话右侧:Markdown 地图

用户选择文档方式时,技能会使用 mmap_open 的 surface: "markdown",生成地图文档后交给宿主在当前对话右侧打开。 文档包含彩色 SVG 分层依赖图、模块状态、设计说明、验证记录和子图链接。 不需要网页服务或 Mermaid 支持,图像放大仍保持清晰。

首次打开后,本项目中成功的地图工具写入会自动重新生成预览。JSON 仍是 唯一数据源,.mellos/previews/ 是可重新生成的输出。图片里的节点没有 拖拽、悬停、双击下潜和动画;用文档链接打开子图。侧栏是否自动刷新由 桌面应用决定,生成成功不代表已显示。手动刷新或旧会话可以运行:

node "<插件根>/dist/preview.mjs" "<项目目录>" --page <页名>

完整说明见 Codex 桌面地图。

可选:交互网页版

现有 Markdown/SVG 用法继续保留。需要缩放拖动、悬停/固定节点详情、依赖 高亮、搜索、状态筛选、分组概览、页面和子地图切换时,使用新增的 mmap_open {surface: "web", page: "<页名>"},将返回的网址交给宿主在右侧 浏览器打开。网页直接读取项目地图并自动更新,也支持明暗主题和确认后删页。

node "<插件根>/dist/web.mjs" "<项目目录>" --page <页名>
# 关闭该项目的网页服务:
node "<插件根>/dist/web.mjs" "<项目目录>" --stop

服务仅在本机运行,不需要部署或下载网页依赖。Markdown 和网页共用原来的 JSON 数据,能够同时使用;手动切页会固定当前页面。详见 网页版功能与运行方式。

任意 MCP 客户端

服务器已发布到 npm,任何 MCP 客户端(Cursor、Windsurf、Zed、Gemini CLI……)都能用标准 stdio 条目接入:

npx -y mellos-mapping

地图文件落在客户端会话的工作目录(.mellos/map.json)。在同 一项目里打开实况面板:

npx -y -p mellos-mapping mellos-mapping-watch

服务器按这个顺序确定项目目录:MELLOS_MAPPING_CWD(显式覆盖,给那些会 在固定目录里拉起服务器的客户端用)、CLAUDE_PROJECT_DIR(Claude Code 为 插件 MCP 服务器设置的约定),最后才是服务器进程自己的工作目录。如果你的 客户端会在你实际工作的项目之外启动服务器,就设 MELLOS_MAPPING_CWD。

技能/纪律层是 Claude Code 与 Codex 专属的;其他客户端获得八个 mmap_* 工具和面板,提示词自备。

使用

  1. 让 Claude 构建一个非平凡的东西。捆绑的 skill 会让 Claude 先声明幽灵 设计,并在工作过程中保持地图与现实一致。
  2. 面板会自己打开。每一次写入都会告诉 Claude 到底有没有人在看 (见谁在看);没人看的时候,Claude 用 mmap_open 自己 把面板开出来或切到该看的那一页——你不需要记着去开它。想自己开关, 在任意终端敲 mmap,或者在对话里用 /mellos-mapping:mmap (Windows 上是 Windows Terminal 分屏,tmux 里是 tmux 分屏,Pebrel 里 是 Pebrel 分屏,其他环境会打印一条命令让你在第二个终端里运行)。Windows 上即使开着多个 终端窗口,分屏也会落在你的会话所在的窗口;想让地图独占一个窗口 就加 --window。字体缺少制表符字形时用 --ascii。
  3. 看着节点从底部一路亮起。图让你不安的时候就打断它——这正是它存在的 意义。

在 Linux 和 macOS 上,mmap_open 与 mmap 会自动使用 tmux。启动器优先 定位继承的 TMUX/TMUX_PANE;工具进程丢失这些变量时,会自动发现默认 tmux 服务中唯一已连接的会话。默认在右侧分屏并保留输入焦点;--window 创建一个新的 tmux 窗口。再次打开会复用属于该源面板或会话窗口的 watcher。

如果有多个已连接的会话,或使用自定义 tmux socket,在 MCP 服务进程的 环境中设置以下变量(修改后重启该进程):

| 环境变量 | 含义 | | --- | --- | | MELLOS_MAPPING_TMUX_TARGET | 指定 tmux 会话或面板,例如 work:2.1 或 %7 | | MELLOS_MAPPING_TMUX_SOCKET | socket 的绝对路径,例如 /tmp/my-tmux/socket |

在 Pebrel 里,mmap_open 与 mmap 通过 Pebrel 运行时 CLI (PEBREL_CLI)分屏承载本会话的面板。启动器用进程树确认该面板所在的窗口, 把输入焦点还给对话,再把 watcher 命令输入新面板的 shell(PowerShell、cmd 或 POSIX shell);shell 随 watcher 一起退出,地图关闭时面板也随之关闭。 --window 会新开一个 Pebrel 窗口。在 tmux 里则由 tmux 负责分屏。

目标不明确、会话未连接或没有安装 tmux 时,启动器会返回具体原因,以及 包含项目、页面和正确引号的一条完整 watcher 命令,可以粘贴到可见终端。 地图仍可正常写入;打开失败后,助手只在环境变化或你要求重试时再次打开。

分屏支持鼠标(xterm SGR any-event 协议——htop 和 tmux 说的同一种话):

| 输入 | 动作 | | --- | --- | | 悬停节点 | 高亮它的关系线;在地图下方预览节点详情 | | 点击节点 | 钉住——鼠标移开后详情仍然常驻 | | 点击空白 / Esc | 取消钉住;无钉住时 Esc 从下潜返回 | | 滚轮 / + - | 缩放,以焦点节点为锚(阶梯见下) | | 按住左键拖动 | 地图超出面板时抓取平移 | | shift+滚轮 | 垂直滚动 | | 滚轮横向拨动 | 左右平移 | | hjkl / 方向键 | 微移视口 | | Tab / Shift+Tab / 1-9 / 点击标签 | 切换页(并行的多张地图) | | 在标签行上滚轮 / 点击 ‹ › | 浏览放不下的标签栏,但不切页 | | f | 开关自动跟随(见页) | | x,或点击当前标签上的 × | 请求删除屏幕上这一页;在确认窗口内再按一次,它的文件就被删掉(见页) | | 双击带 ⊞ 的节点 | 下潜进它的子图(一个子页面) | | Backspace / Esc | 从上一次下潜爬回父图 | | 拖动 ⋯ 分隔线 | 调整详情面板高度——向上拉,完整阅读长设计笔记 | | 0 | 重置平移和缩放 | | q / Ctrl+C | 退出面板 |

其他按键一律无效,这是有意的:面板不认识的转义序列(F 键、Home/End、 PgUp/PgDn、Insert/Delete、带修饰的方向键)会被整段吞掉、什么都不做, 而不是让它的载荷字节被当成热键读进来。

缩放先做几何缩小,只在阶梯两端才切换显示模式——每一级都能看到有意义的 数据:

细读+ ← 细读 ← 100% ← 85% ← 70% ← 55% ← 概览
  • 放大过 100%——detail 在盒子里展开验证证据和设计笔记的前三行; detail+ 把盒子撑成一张阅读卡(最多十二行笔记);
  • 85–55%——留白收紧、标签按比例截断,盒子还是盒子;
  • 低于 55%——标签已短到无意义,此时地图聚合:每个已声明的分组 (层内的具名子系统)变成一个盒子,如 地基子系统 1/2,状态由成员推导, 边收拢到分组上,未分组节点保持原样。就像真地图缩小后显示省名,而不是 把城市变成无名光点。(没有声明分组的地图退化为纯字形星座 + 每层计数。) 页脚始终显示当前级别。

地图下方、提示行之上,是一块固定高度的详情面板:一条可拖动的分隔线、 一行按状态着色的表头、焦点节点的验证证据、两个方向的连线(uses → … · used by ← …,每个邻居各带自己的状态字形),以及自动折行的设计笔记。没有 焦点时显示整图的仪表盘。高度固定——详情不会悬浮遮挡地图,版面也不会跳。

字形

一个状态一个字形,画地图的地方都一样——面板里的盒子、标签栏、详情面板, 以及任何读同一份存储的客户端:

| Unicode | ASCII | 含义 | | --- | --- | --- | | · | . | planned——已声明,未开工 | | ⠿ | * | in-progress 的静止形态——能做动画的盒子转的是盲文帧 ⠋⠙⠹…,ASCII 下是四帧的转杠 | | ■ | # | done,且有证据 | | □ | o | done,但没有记录证据——同一个断言,背后空无一物 | | ✗ | X | regressed:曾经 done,现在坏了 | | ⊞ | + | 徽标:这个节点链着子图,双击下潜 |

图下方的图例列出四个状态;□ done, no evidence 只在这张图里真的出现了 这种节点时才加入——四个状态是词汇表,那一个是此时此地正在被违反的规则。 文档型图种用节点 kind 的字形取代状态图例。

面板参数

面板启动脚本(scripts/open-pane.mjs <项目目录>)和 watcher (dist/watch.mjs)接受同一套 watcher 参数;启动脚本原样转发它们,遇到 不认识的参数会报错,而不是悄悄丢掉。

| 参数 | 作用 | | --- | --- | | --page <slug> | 打开时定位到这一页;已经有面板在跑时,改为让那个面板切过去,而不是再开一个 | | --ascii | 纯 ASCII 字形,给缺制表符字形的字体用 | | --no-color | 不输出 ANSI 颜色 | | --no-mouse | 关闭鼠标上报,把鼠标留给你的终端复用器 | | --no-follow | 启动时就关掉自动跟随 | | --interval <ms> | 轮询间隔,缺省 250,下限 50 |

只属于启动脚本的:--window 直接开到专属的 "mellos-mapping" 窗口而不是 在会话窗口里分屏,--force 即使本项目已有面板在跑也再开一个。只属于 watcher 的:--file <path> 指定默认页的状态文件(启动脚本会从项目目录 自己推导出来)。

内部 watcher 参数 --owner <token> 和面板报告的可选 owner 字段承载会话绑定。 启动器用源控制台进程及创建时间生成身份;手动运行 watcher 可省略。切页和关闭 请求按面板 PID 定向投递,同项目其他窗口不会抢走请求。普通 mmap 只切换当前 会话的面板;mmap --window 切换本项目的独立窗口。

mmap 命令

在终端里敲 mmap,它是当前会话地图的开关:本会话还没有面板就开一个, 已经有面板就把它关掉。

| 你敲的 | 发生什么 | | --- | --- | | mmap | 当前会话没有面板在跑 → 开一个;有 → 关掉它 | | mmap <页 slug> | 打开时定位到这一页,或者让已开的面板切过去——永远不关 | | mmap --window | 开到专属的 "mellos-mapping" 窗口,而不是把当前窗口分屏 | | mmap --force | 即使已经有面板在跑也再开一个 |

项目是像 git 找仓库根那样找出来的:从当前目录往上走,找最近一个含 .mellos/ 存储的目录。站在一个还没有地图的项目里也没问题——面板会开在 待机画面上,等第一次 mmap_declare。

关闭走的是存储,不是信号:mmap 在地图旁边写一份一次性请求,面板在下一次 轮询(缺省 250 毫秒)时消费掉它并退出,并把终端原样还回去——关掉鼠标上报、 恢复光标。还停在待机画面上的面板也一样关得掉。请求读到即删;上一个面板死掉 留下的残留会在下一个面板启动时被清扫,所以过期的请求永远关不掉新面板。

上面每一个 watcher 参数在这里同样有效,原样转发;不认识的参数会报用法错误, 绝不悄悄丢掉。除非你装的是 npm 包,否则 mmap 需要 装一次。在 Claude Code 对话里,/mellos-mapping:mmap 打开的是 同一个面板。

页

一个项目可以并排保有多张地图——一个工作努力 = 一页。Claude 在任何 mmap_* 工具里传 page 参数即可定向到某页;出现第二页时面板顶部自动长出 标签栏。当前页加粗、按整图状态着色。每页记住自己的平移/缩放/钉住状态。

面板默认自动跟随正在被写入的那一页——AI 此刻在操作哪张图,就看哪张图, 于是 declare 和 update 自己就把观众带过去了。按 f 开关,手动切页也会关掉 它,--no-follow 则是一开始就关着;跟随关掉之后,后台页有变化时它的标签会 亮起状态色提示你,而不是抢走你的视线。显式的 --page 优先级高于跟随;请求 一个还不存在的页会一直挂着,等它出现的那一刻显示出来。

删除一页。 一件事做完了,它那一页不必留着。在面板里按 x——或者点击 当前标签上的 ×(开着鼠标时才画)——只是发问:页脚出现 press x again to delete <页>,三秒内再按一次,这一页的文件就被删掉。切页、 Esc、或者干脆等它过期,请求就收回了。× 只长在当前标签上,所以点一个 非当前标签是先切过去,下一帧它才带上自己的 ×。工具那边是 mmap_remove {pages: ["slug", …]},在这次调用的地图修改之后执行。两条 路都一样:文件是真的没了——地图是纯 JSON,提交进 git 是唯一的后悔药。

地图状态存在项目根目录下、属于本工具的 .mellos/ 目录里:

| 路径 | 是什么 | | --- | --- | | .mellos/map.json | 默认页——可选;工作全在命名页上的项目根本没有这个文件 | | .mellos/pages/<slug>.json | 一个命名页一个文件 | | .mellos/config.json | 本项目的建图策略(见 Setup) | | .mellos/focus | 启动脚本发给运行中面板的一次性"切到这一页"请求;面板在一个轮询周期内消费并删除它 | | .mellos/quit | mmap 开关发出的一次性"自己关掉"请求,以同样的方式被消费和删除 | | .mellos/viewers/<pid>.json | 每个活着的面板一份报告——它正显示哪一页、自动跟随是否打开——运行期间每秒刷新一次(见谁在看) | | <上面任一文件>.<pid>.<随机>.tmp | 正在落盘的一次写入;它要么被改名覆盖目标,要么被删掉。留下来说明那次写入失败(并已被报告),连清理都没能跑成 | | .mellos/.write-lock | 操作系统项目锁使用的永久普通文件;不纳入 Git,正常运行时不得删除、改名或替换 |

地图文件是纯 JSON,想在 git 里留下地图的历史就把它们提交进去。focus、quit、 viewers/ 和 .write-lock 应加入 gitignore。前三者传递运行期消息;锁文件即使 没有进程持锁也应保留,不要当作临时文件清理。

并发模型,直说。 每次保存都是原子的——先写进一个私有的同级临时文件, 再改名覆盖目标——所以轮询存储的读者要么看到上一张完整的地图,要么看到新的 那张,绝不会读到写了一半的。所有写图入口(MCP、HTTP 查看器、watcher)都使用 同一把项目级、非阻塞的操作系统排他锁。锁使用独立的固定文件,与被原子替换的 地图文件分开;操作结束或进程退出后,操作系统释放锁,锁文件仍保留。锁被占用时 返回可重试的 BUSY。

这把锁串行执行每次操作的读取、修改和保存。基于先前读取计算的改动还应传入 expectedRevision:它在锁内比较,版本过旧返回 CONFLICT。省略它时,后续写入 仍可能覆盖同一字段或 context 这样的完整值。不同页面用于分开互不相关的工作; 共用一页时仍需带版本检查。底层 saveMapFile、手工编辑和仍在运行的旧进程不参与 这份约定。升级前须停掉该项目所有旧 MCP、查看器和 watcher 进程;残留的旧锁目录 需一次性迁移。完整边界和升级步骤见持久化地图 API 指南与 项目锁说明。

图种

缺省图种 dev 就是上文那本活的进度账本。同一套分层 DAG 机器也能画文档型 图:在 mmap_declare 里传 kind,该页即以中性方式渲染——素色实线盒子, 没有幽灵、没有 spinner、不数进度。

| 图种 | 读法 | 专属能力 | | --- | --- | --- | | architecture | 分层组件(也适合模块依赖、调用图) | 边标签标协议 | | dataflow | 管线阶段即层,源头在最底 | 边标签标数据 | | behavior-tree | 叶子(动作)在最底,根在顶(也适合思维导图、WBS) | 节点 kind selector sequence parallel decorator condition action 渲染为字形 | | sequence | 经典的调用/返回时序:时间自上而下流,参与者是顶部泳道表头;每次进入和每次返回都是"当事参与者泳道里"的一个事件 | lanes 即参与者泳道;边标签即消息 |

节点 kind 和边标签在 dev 图上同样可用。状态机是有意不支持的:状态迁移 成环,而这里的边只许向下。

子图

节点可以用 submap: <页名> 链接一个子页面——面板给它戴上 ⊞ 徽标;双击 下潜进子图,Backspace 爬回父图。图中图,完全由页组合而成:没有新存储、 没有新不变量。一个节点值不值得配子图,由 AI 自行判断——大多数不需要。

子图是节点的内部细节,不是兄弟页:被别的页潜进去的页不占标签栏。 有两条修正保证标签栏不会把自己抹掉——节点指向自己所在页的,谁也不藏; 链接成环的一组页保留各自的标签,除非环外有页潜进来,因为环本身没有"外面" 可以爬回去。下潜 之后标签行变成面包屑——⌫ 父图 ▸ 节点——点击它(或按 Backspace)爬 回去。隐藏的子图在后台有变化时,底栏会提示。

MCP 工具

先用 mmap_read 查找并恢复已有页面;新对话不等于新任务。通过稳定 ID、过滤查询 和版本检查做增量修改。持久化地图接口说明包含完整增删改查、 混合事务、恢复摘要、源码哈希和 worktree 边界。

| 工具 | 用途 | | --- | --- | | mmap_declare | 生长地图:标题(传 null 删掉)、图种、层级横条、泳道、分组(子系统)、节点(可带 status、evidence、detail、kind、group、lane、submap)、边(可带标签);批量,全有或全无 | | mmap_update | 记录进度并修订:状态(planned → in-progress → done 附证据、regressed)、改节点标签、把节点搬到另一层(layer)、加入/退出分组或泳道、设节点 kind 或 submap;给层改名和改 rank(layers)、给分组改标签(groups)、给泳道改标签(lanes);任何可清空的字段传 null 即清空 | | mmap_remove | 修订:删除边、节点、分组、泳道、空层——以及用 pages 删掉整页,连文件一起(永久;在本次调用的地图修改之后执行) | | mmap_view | 把当前地图渲染成文本,直接在对话里看(可选 zoom,-4…2);每次响应结尾都有一行 pages:,列出本项目有哪些页、以及你正在看哪一页 | | mmap_read | 结构化页面发现、稳定 ID、过滤分页查询、恢复摘要与源码变化检查 | | mmap_batch | 单页增删改混合事务与版本冲突检查 | | mmap_setup | 查/设本项目的建图策略——什么时候开地图 | | mmap_open | 把地图放到你屏幕上:开面板,或把已开的面板切到某一 page(window: true 用独立窗口)。它回答的是"事后有没有面板真的报到",而不只是"命令跑过了"——而且它永远关不掉面板 |

一个批次的施加顺序是 层 → 分组 → 泳道 → 节点更新;同一条节点更新里 layer 先于其他字段生效,所以一个节点可以在一条更新里搬层并加入新层上的 分组。

边界会拒绝下面这些,好让账本不会记下它并不想记的东西:

  • 不认识的键,并把键名说出来——拼错的 evidance 是错误,不是被悄悄 丢掉的字段;任何嵌套深度都一样;
  • 文本字段里的控制字符——藏在标签里的 ESC 序列,会让这张图重绘每一个 打开它的人的终端。detail 是例外:换行和制表符本来就是写笔记的方式, 其余(ESC、BEL、单独的 CR)照样拒绝。文件加载和公共库保存也校验控制字符, 同时兼容旧文件中的多行证据。直接通过公共库构造地图时,终端渲染仍会消除 控制字符的执行效果;
  • 可选字段上的空字符串——清空字段用 null,而不是一个渲染出来跟真盒子 分不清的空白;
  • submap 指向本次调用所针对的那一页的节点——那是个没有底的环,不是 指向父图的链接;
  • 删页请求指向本次调用自己所针对的那一页,或者指向本项目根本没有的 slug——一次调用不能一边改一张图一边删掉它;而对不上任何一页的名字, 是拼错的概率远大于"刚被别人删了",拒绝时会把真实存在的页列出来。

没有落盘的写入回答 save failed, nothing changed (retry):之前的文件完好 无损,重试一次就是全部的恢复手段。

谁在看

没人开在屏幕上的地图不是地图,是文件——而系统以前根本分不出这两者。 助手声明幽灵设计、一个个把节点点亮,然后把这一切写进一个你从来没打开过 面板的仓库里。

现在每个面板在运行期间都会发布一份小小的报告——.mellos/viewers/, 一个面板一个文件,每秒刷新一次——而每一次写入、每一次查看的结尾,都会 把这些报告说出来:

| 这一行 | 意思 | | --- | --- | | pane: CLOSED | 没人在看这张图;助手会用 mmap_open 自己开,而不是回过头来要求你开 | | pane: running on this page | 活跃进程报告正在显示这一页,但终端可能被隐藏 | | pane: open on <其他页>, auto-follow on | 面板跟随最后被写入的那一页,它自己会过来 | | pane: open on <其他页>, auto-follow OFF | 那一页是你亲手钉住的:这次改动是真的,但不在你屏幕上。助手被要求把这件事说出来,而不是把你的视图搬走 |

同一批报告也回答了 mmap 和启动脚本要问的"面板是不是已经开着"——这个 问题以前得靠一次只有 Windows 才有的进程扫描,而且答不出屏幕上是哪一页。 超过五秒没被刷新的报告不再算数,超过一分钟就被读到它的人删掉,所以被强杀 的面板不会一直冒领观众。

心跳不等于屏幕可见。显式调用 tmux 打开操作时,启动器还会切回已有地图所在的 窗口,解除遮挡地图的面板缩放,并检查已连接会话的活动窗口后再报告可见。 缺少 TMUX 环境变量、焦点又落在地图面板上时,会沿用原来的归属,避免重复打开。

Setup:选择什么时候建图

建图要多积极,是一个人的工作习惯,不是某个仓库的属性——所以它只为你选 一次,就在你装完之后的第一个会话里:

  • always —— 任何有结构的任务都建图:流程、设计、架构、技术依赖。AI 会 主动开面板;你记下的这个答案就是它的长期授权,它不会再问。
  • complex —— 同样的做法,但只用在中等或复杂任务上:牵涉多个模块、一个 新子系统,大约一小时以上的活。
  • on-request —— 只在你明确要求时建图。在还没有地图的项目里,插件对此 一个字都不说——零噪音就是目的。

答案落在 <你的用户目录>/.mellos/config.json,并通过插件的 SessionStart 钩子进入每一个会话:钩子把它读出来,在你敲下第一个字之前就把对应的指令交给 AI。从此再也不需要按项目设置什么。

单个项目仍然可以不一样:mmap_setup {policy, scope: "project"} 把策略写进 那个项目的 .mellos/config.json,项目策略压过用户策略。想改主意时, /mmap setup 会把这个问题按任一作用域重新问一遍。策略只是引导 AI;它从不 阻止工具本身——无论什么策略,明确要求建图永远有效。

没有钩子的宿主(Codex CLI、裸 MCP 客户端)用另一条路拿到这个问题:只要两个 作用域里都还没有策略,每一次 mmap_declare 的响应都会带一条提示,让 AI 来 问你。你在任何一个作用域答完之后,这条提示就永远闭嘴了——在每一个项目里。

工具强制的结构不变量:层按 rank 构成全序(rank 是 0..99 的整数,0 在最底, 一张图里不许重复);每个节点恰好属于一层;边严格向下——因此图从构造上 就是无环的;节点不能依赖同层兄弟(如果 A 需要兄弟 B,要么 B 其实是更低层的 概念,要么 A 和 B 本来就是一个节点);分组只在一层之内聚拢节点;节点 id 和 分组 id 共用同一个命名空间——一个 id 要么命名节点、要么命名分组,绝不 两者兼有,因为它们都渲染成盒子,一个 id 必须只意味着一个盒子。

开发

先阅读贡献说明和项目结构、分支与恢复指南。

npm ci
npm run verify

开发环境使用 Node.js 22.12+。verify 依次运行 typecheck、test、build (打包 dist/、产出带声明的 lib/)、check:package、check:codex 和 check:release,检查 npm 入口、Codex 包和两个可安装发行包,包括 MCP 握手。

这个仓库本身就是自下而上分层的,每一层都有自己的规格测试:

| 层 | 代码 | 规格 | 职责 | | --- | --- | --- | --- | | 0 domain | src/domain/ | ops.test.ts | 地图值、结构不变量、纯操作 | | 1 format | src/store/format.ts | store.test.ts | 状态文件格式:重放校验的解析与序列化,零 I/O | | 1 store | src/store/store.ts | store.test.ts、atomic-save.test.ts | Node 上的原子化状态文件持久化 | | 1 semantics | src/semantics/ | semantics.test.ts | 媒介无关的视图语义:缩放阶梯、分组聚合、页集规则、时序翻转、共享字形词汇表 | | 2 apply | src/server/apply.ts | apply.test.ts | 工具输入 → 事务性操作序列 | | 3 server | src/server/server.ts | server.test.ts、save-failure.test.ts | stdio 上的八个 MCP 工具 | | 4 render | src/render/ | render.test.ts、routing.test.ts | ASCII 渲染器与它的走线 | | 4 pane | src/watch/ | watch.test.ts、pane-state.test.ts、input.test.ts | 轮询面板:页集、输入解析、详情面板与外框 | | — 启动脚本 | scripts/ | open-pane.test.mjs、codex-register.test.mjs | 纯 node 的入口 | | — 打包 | package.json | tests/lockfile.test.ts、browser-safe.test.ts | 发出去的是什么、发给谁 |

dist/ 是刻意提交的:插件安装就是克隆本仓库、不运行任何东西,所以入口 文件以打包形式随仓库分发。CI 会把提交的 dist/ 和一次全新构建做 diff, 所以改了源码却忘了重新构建会直接失败。

库

底部各层同时是一个库(npm run build 产出带类型声明的 lib/,npm 打包 收录)。子路径导出与源码结构一一对应:

| 子路径 | 内容 | 浏览器安全 | | --- | --- | --- | | mellos-mapping/domain/types | 地图值、id、rank、状态、错误 | 是 | | mellos-mapping/domain/ops | 地图上的纯操作 | 是 | | mellos-mapping/format | 状态文件的解析/序列化、页 id | 是 | | mellos-mapping/semantics | 缩放阶梯、分组聚合、焦点与页集规则、共享字形词汇表 | 是 | | mellos-mapping/render | 终端渲染器 | 同样受门禁守护(它是纯的),但产出是字符格——给终端宿主 | | mellos-mapping/store | 文件系统持久化、原子保存、focus 文件、策略 | 仅 Node | | mellos-mapping/server | 打包好的 MCP 服务器入口——用来拉起的进程,不是拿来 import 的模块 | 仅 Node |

浏览器安全的意思是 import 闭包里没有任何 Node 内建模块,由测试门禁 守护——图形客户端(web 面板、编辑器视图)可以直接解析状态文件,并复用与 终端面板完全一致的聚合、缩放与字形语义。

可选的 GitHub Star 提醒

仅 npm/npx 安装会在首次成功查看地图满 7 天、且已在至少 3 个不同 UTC 日期 成功查看地图后,显示一次轻提示。网页中是一行可关闭的文字,不抢焦点; 原生交互终端只在正常退出地图后提示。MCP 返回、AI 提示词、安装日志、CI 及管道输出中都不会加入提醒,插件版和源码运行也不触发。

Star 按钮会调用系统默认浏览器打开 GitHub,方便沿用已有登录状态。 若未能打开,会保留提示并提供复制地址按钮。 提醒按用户跨项目、版本及安装去重,一生效就记为已提醒。关闭、点击 Star 或直接离开后,都不会再次出现。想提前关闭,可在启动地图或 MCP 的环境中 设置 MELLOS_MAPPING_NO_STAR=1。 仅在 ~/.mellos/support/star-reminder.json 本地记录首次使用时间、最后一个 UTC 日期、最多 3 天的计数和已提醒标记,不上传数据,不查询是否点过 Star; 只有用户主动点击链接时才访问 GitHub。设置损坏、不可写或锁忙时静默跳过。

社区

本项目积极参与并认可 LINUX DO 社区。

许可证

MIT