mellos-mapping 0.24.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +82 -12
- package/README.zh-CN.md +69 -10
- package/dist/hook-session-start.mjs +69 -13
- package/dist/native/LICENSES.txt +443 -0
- package/dist/native/darwin-arm64/fs-native-extensions.node +0 -0
- package/dist/native/darwin-x64/fs-native-extensions.node +0 -0
- package/dist/native/linux-arm64/fs-native-extensions.node +0 -0
- package/dist/native/linux-x64/fs-native-extensions.node +0 -0
- package/dist/native/win32-arm64/fs-native-extensions.node +0 -0
- package/dist/native/win32-x64/fs-native-extensions.node +0 -0
- package/dist/native-lock.cjs +346 -0
- package/dist/omp-extension.mjs +359 -0
- package/dist/server.mjs +199 -139
- package/dist/terminal-worker.mjs +116 -74
- package/dist/watch.mjs +125 -83
- package/dist/web.mjs +170 -113
- package/docs/codex.md +4 -1
- package/docs/locking.md +115 -0
- package/docs/map-api.md +29 -13
- package/lib/store/migration.js +19 -12
- package/lib/store/native-lock.d.ts +5 -0
- package/lib/store/native-lock.js +27 -0
- package/lib/store/transaction.d.ts +9 -2
- package/lib/store/transaction.js +79 -50
- package/package.json +11 -3
- package/scripts/install-mmap-command.mjs +179 -13
package/README.md
CHANGED
|
@@ -61,7 +61,11 @@ Clone the branch for your host, then run one command. No build is required.
|
|
|
61
61
|
| `claude` | Claude Code | `node install.mjs` |
|
|
62
62
|
| `chatgpt-app` | ChatGPT desktop, Codex mode | `node install.mjs` |
|
|
63
63
|
|
|
64
|
-
Requires Node.js 18+
|
|
64
|
+
Requires Node.js 18.17+ on the 18.x line, or 20.3+, and the corresponding host CLI
|
|
65
|
+
on PATH. Supported platforms are Windows 10+, macOS 13.0+ and Linux with glibc
|
|
66
|
+
2.28+, each on x64 or arm64. The OS must also meet the selected Node.js version's
|
|
67
|
+
requirements. Native lock bindings ship with the release; no local compilation
|
|
68
|
+
is needed. The installer checks
|
|
65
69
|
release integrity and all eight MCP tools, retains the runtime outside the clone,
|
|
66
70
|
and configures the host. Start a new conversation after installation.
|
|
67
71
|
See [release and branch instructions](docs/releasing.md).
|
|
@@ -81,13 +85,41 @@ Or one line in a terminal:
|
|
|
81
85
|
claude plugin marketplace add GuangminJu/mellos-mapping && claude plugin install mellos-mapping@mellos-mapping
|
|
82
86
|
```
|
|
83
87
|
|
|
84
|
-
Requires Node.js
|
|
88
|
+
Requires the same [Node.js and platform versions](#install) on PATH (install
|
|
89
|
+
Node separately when using native Claude Code). No build step: `dist/` is
|
|
90
|
+
committed, so a clone runs as-is —
|
|
85
91
|
`dist/server.mjs` (the MCP server), `dist/watch.mjs` (the pane),
|
|
86
92
|
`dist/mmap.mjs` (the `mmap` toggle), `dist/hook-session-start.mjs` (the
|
|
87
93
|
`SessionStart` hook that `hooks/hooks.json` registers) and
|
|
88
94
|
`dist/store-paths.mjs` (the store's path vocabulary, which the plain-node pane
|
|
89
95
|
launcher imports instead of restating filenames).
|
|
90
96
|
|
|
97
|
+
**omp (Oh My Pi)** reads the same plugin layout the Claude Code edition ships —
|
|
98
|
+
the same marketplace catalog, `.mcp.json`, skill and slash command — so one
|
|
99
|
+
release serves both hosts:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
omp plugin marketplace add GuangminJu/mellos-mapping
|
|
103
|
+
omp plugin install mellos-mapping@mellos-mapping
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
That install follows `main`, where a release is a version bump. To freeze a
|
|
107
|
+
version instead, add a checkout of one — the Claude Code edition ZIP from the
|
|
108
|
+
GitHub Release, or a clone at the release tag:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
omp plugin marketplace add "<checkout or extracted release directory>"
|
|
112
|
+
omp plugin install mellos-mapping@mellos-mapping
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
omp never reads `hooks/hooks.json`, so the session paragraph arrives through the
|
|
116
|
+
plugin's omp host adapter (`dist/omp-extension.mjs`, declared in
|
|
117
|
+
`package.json#omp.extensions`): the same store, the same policy text, and the
|
|
118
|
+
same `mmap` shim install as the Claude hook. The pane is the same terminal
|
|
119
|
+
split beside the session. Install it *as a plugin*: neither `omp plugin link`
|
|
120
|
+
nor the npm package is a plugin, and both would leave the tools behind. See
|
|
121
|
+
[omp installation and limitations](docs/distributions/omp.md).
|
|
122
|
+
|
|
91
123
|
The first session after installing asks you **one** question — how eager
|
|
92
124
|
mapping should be — and records the answer for every project you will ever
|
|
93
125
|
open. From then on the hook carries it into each new session by itself; there
|
|
@@ -104,8 +136,14 @@ Terminal inherits the old environment, so close the terminal app entirely and
|
|
|
104
136
|
reopen it before the first `mmap`. The PATH edit keeps the
|
|
105
137
|
installer's guarantees: nothing happens when the entry is already there, and
|
|
106
138
|
a PATH that `setx` would damage (flattened `%VARIABLE%` references, truncation
|
|
107
|
-
past its limit) is refused outright
|
|
108
|
-
|
|
139
|
+
past its limit) is refused outright.
|
|
140
|
+
|
|
141
|
+
A refused PATH is not a dead end: the same two shims are then written into
|
|
142
|
+
`%LOCALAPPDATA%\Microsoft\WindowsApps` (or `~/.local/bin`) — a directory your
|
|
143
|
+
PATH already names — so `mmap` is runnable in a new terminal with no PATH
|
|
144
|
+
change at all. Machines with a long PATH are exactly where that happens, and
|
|
145
|
+
where it matters most. The command takes the page to open as an argument
|
|
146
|
+
(`mmap omp-host-support`), and closes the pane when it is already open.
|
|
109
147
|
|
|
110
148
|
The step behind it is still a command of its own, for the cases the hook does
|
|
111
149
|
not cover — `--uninstall`, or re-adding a PATH entry you removed while the
|
|
@@ -130,6 +168,26 @@ marketplace clone — the first command is what actually pulls this repo.
|
|
|
130
168
|
Restart Claude Code to apply. Releases are version bumps on `main`.
|
|
131
169
|
(In-app, `/plugin` opens the same management UI.)
|
|
132
170
|
|
|
171
|
+
omp updates with its own two steps:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
omp plugin marketplace update mellos-mapping && omp plugin upgrade mellos-mapping@mellos-mapping
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Close the pane first (`q` in it): the watcher runs from the plugin copy, and on
|
|
178
|
+
Windows an open file cannot be renamed away, so an upgrade attempted while a
|
|
179
|
+
pane is open can fail with `EPERM` and leave the plugin cache empty — repaired
|
|
180
|
+
by `omp plugin install mellos-mapping@mellos-mapping --force`. Then: the first
|
|
181
|
+
command refreshes the catalog, the second reinstalls from it. omp also
|
|
182
|
+
refreshes a catalog entry it has not updated for a day at startup, unless
|
|
183
|
+
`marketplace.autoUpdate` is `off` — in the default `notify` mode that check
|
|
184
|
+
writes its finding to the debug log only, so `marketplace update` is the step
|
|
185
|
+
that makes an update visible. `upgrade` does not compare versions: it
|
|
186
|
+
force-reinstalls whatever the catalog names, which is why a release is
|
|
187
|
+
identified by its version bump rather than gated by it. Restart omp afterwards,
|
|
188
|
+
and reopen a pane still showing the old bundle (`q` in it, then `mmap_open`
|
|
189
|
+
again).
|
|
190
|
+
|
|
133
191
|
### Upgrading from 0.19
|
|
134
192
|
|
|
135
193
|
0.20 moved the store out of `.claude/` — the map belongs to this tool, not to
|
|
@@ -446,19 +504,31 @@ State lives in the tool-owned `.mellos/` directory at the project root:
|
|
|
446
504
|
| `.mellos/quit` | one-shot "close yourself" request from the `mmap` toggle, consumed and deleted the same way |
|
|
447
505
|
| `.mellos/viewers/<pid>.json` | one report per live pane — the page it is showing, whether auto-follow is on — refreshed every second while it runs (see [Who is watching](#who-is-watching)) |
|
|
448
506
|
| `<any of the above>.<pid>.<random>.tmp` | a save in flight; it is renamed over its target or removed. A leftover means a write failed (and was reported) and even its cleanup could not run |
|
|
507
|
+
| `.mellos/.write-lock` | permanent regular file for the OS project lock; keep it untracked and never remove, rename or replace it during normal operation |
|
|
449
508
|
|
|
450
509
|
The map files are plain JSON, safe to commit if you want the maps' history in
|
|
451
|
-
git.
|
|
452
|
-
|
|
510
|
+
git. Keep `focus`, `quit`, `viewers/` and `.write-lock` out of Git. The first
|
|
511
|
+
three carry runtime messages; the lock file must remain in place, including
|
|
512
|
+
when no process holds its lock.
|
|
453
513
|
|
|
454
514
|
**Concurrency, stated plainly.** Every save is atomic — written to a private
|
|
455
515
|
sibling temp file and renamed over the target — so a reader polling the store
|
|
456
|
-
sees the previous complete map or the new one, never a torn write.
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
516
|
+
sees the previous complete map or the new one, never a torn write. Every graph
|
|
517
|
+
writer (MCP, the HTTP viewer, the watcher) uses the same non-blocking OS
|
|
518
|
+
exclusive lock for the project. The lock has its own fixed file, separate from
|
|
519
|
+
the map files being replaced; it stays in place after the OS releases the lock
|
|
520
|
+
on completion or process exit. Contention returns a retryable `BUSY`.
|
|
521
|
+
|
|
522
|
+
The lock serializes each operation's read, change and save. To protect an edit
|
|
523
|
+
computed from an earlier read, pass `expectedRevision`: it is compared inside
|
|
524
|
+
the lock, and a stale revision returns `CONFLICT`. Without it, a later write
|
|
525
|
+
can still overwrite the same field or a whole value such as `context`. Pages
|
|
526
|
+
separate unrelated efforts; sharing a page still requires revision-checked
|
|
527
|
+
edits. Low-level `saveMapFile`, hand edits and older running processes do not
|
|
528
|
+
participate in this contract. Stop all old MCP, viewer and watcher processes
|
|
529
|
+
for the project before upgrading; an old lock directory needs a one-time
|
|
530
|
+
migration. See the [persistent-map API guide](docs/map-api.md) and
|
|
531
|
+
[project locking](docs/locking.md) for the boundary and upgrade steps.
|
|
462
532
|
|
|
463
533
|
### Diagram kinds
|
|
464
534
|
|
package/README.zh-CN.md
CHANGED
|
@@ -54,7 +54,10 @@ Claude 为你构建系统时,对话旁边的分屏实时显示这个系统的*
|
|
|
54
54
|
| `claude` | Claude Code | `node install.mjs` |
|
|
55
55
|
| `chatgpt-app` | ChatGPT 桌面 App 的 Codex 模式 | `node install.mjs` |
|
|
56
56
|
|
|
57
|
-
前置要求为 Node.js 18
|
|
57
|
+
前置要求为 Node.js 18.17 及以上的 18.x,或 20.3 及以上版本,以及对应宿主的 CLI,
|
|
58
|
+
并确保命令在 PATH 中。支持 Windows 10+、macOS 13.0+ 和 glibc 2.28+ 的 Linux,均支持
|
|
59
|
+
x64 与 arm64;系统还须满足所选 Node.js 版本的更高要求。发行包自带原生锁绑定,
|
|
60
|
+
无需用户本地编译。安装器检查
|
|
58
61
|
发行文件和八个 MCP 工具,将运行时保留到克隆目录之外,完成宿主配置。
|
|
59
62
|
安装后开启新对话。详见[发布与分支说明](docs/releasing.md)。
|
|
60
63
|
|
|
@@ -73,13 +76,38 @@ Claude Code 也可以通过插件市场安装:
|
|
|
73
76
|
claude plugin marketplace add GuangminJu/mellos-mapping && claude plugin install mellos-mapping@mellos-mapping
|
|
74
77
|
```
|
|
75
78
|
|
|
76
|
-
需要 PATH
|
|
79
|
+
需要 PATH 上有符合[安装要求](#安装)的 Node.js;使用原生 Claude Code 安装包时也需
|
|
80
|
+
单独安装 Node.js。
|
|
77
81
|
没有构建步骤:`dist/` 是提交进仓库的,克隆即用——`dist/server.mjs`(MCP
|
|
78
82
|
服务器)、`dist/watch.mjs`(面板)、`dist/mmap.mjs`(`mmap` 开关)、
|
|
79
83
|
`dist/hook-session-start.mjs`(由 `hooks/hooks.json` 注册的 `SessionStart`
|
|
80
84
|
钩子),以及 `dist/store-paths.mjs`(存储的路径词汇;纯 node 的面板启动
|
|
81
85
|
脚本从这里导入,而不是自己抄一份文件名)。
|
|
82
86
|
|
|
87
|
+
**omp(Oh My Pi)** 读的是 Claude Code 版本用的同一套插件布局——同一份市场
|
|
88
|
+
目录、`.mcp.json`、技能与斜杠命令——一份发行包同时服务两个宿主:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
omp plugin marketplace add GuangminJu/mellos-mapping
|
|
92
|
+
omp plugin install mellos-mapping@mellos-mapping
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
这样装跟的是 `main`,而发布就是它上面的版本号提升。要冻结版本,就改把某个
|
|
96
|
+
版本的检出目录加为市场——GitHub Release 里的 Claude Code 版本 ZIP,或按
|
|
97
|
+
tag 检出的克隆:
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
omp plugin marketplace add "<检出或解压出来的发行目录>"
|
|
101
|
+
omp plugin install mellos-mapping@mellos-mapping
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
omp 不读 `hooks/hooks.json`,所以那段会话说明由插件的 omp 宿主适配器送达
|
|
105
|
+
(`dist/omp-extension.mjs`,在 `package.json#omp.extensions` 里声明):同一个
|
|
106
|
+
存储、同一段策略文字,Windows 上的 `mmap` shim 也由它安装。面板仍旧是会话
|
|
107
|
+
旁边的终端分屏。请把它**当插件**安装——`omp plugin link` 与 npm 包都不是插
|
|
108
|
+
件,用它们装会只剩适配器、没有工具。见
|
|
109
|
+
[omp 安装与限制](docs/distributions/omp.md)。
|
|
110
|
+
|
|
83
111
|
装完之后的第一个会话只会问你**一个**问题——建图要多积极——并把答案记成
|
|
84
112
|
你以后打开的每一个项目的默认。此后钩子会自己把它带进每个新会话;再也没有
|
|
85
113
|
"每个项目设置一遍"这回事。见
|
|
@@ -93,7 +121,13 @@ PowerShell)和 `mmap`(git-bash)写进 `%LOCALAPPDATA%\mellos-mapping\bin`
|
|
|
93
121
|
所以第一次敲 `mmap` 之前要把终端应用整个关掉重开。PATH 的编辑保持安装器
|
|
94
122
|
原有的承诺:条目已经在里面
|
|
95
123
|
就什么都不做;遇到 `setx` 会损坏的 PATH(`%VARIABLE%` 被展平、超长被截
|
|
96
|
-
|
|
124
|
+
断),它干脆拒绝。
|
|
125
|
+
|
|
126
|
+
PATH 被拒绝不等于没命令可用:同样两个 shim 会再写一份到
|
|
127
|
+
`%LOCALAPPDATA%\Microsoft\WindowsApps`(或 `~/.local/bin`)——一个你的 PATH
|
|
128
|
+
本来就有名字的目录——于是**新终端里直接敲 `mmap` 就能用,完全不用改 PATH**。
|
|
129
|
+
PATH 很长的机器正是这种情况,也最需要它。命令可以带要打开的页名
|
|
130
|
+
(`mmap omp-host-support`);面板已经开着时再敲一次就是关掉它。
|
|
97
131
|
|
|
98
132
|
它背后的那一步仍然是个独立命令,留给钩子管不到的情形——`--uninstall`,
|
|
99
133
|
或者 shim 还在、PATH 条目却被你删掉之后重新加回去:
|
|
@@ -116,6 +150,22 @@ claude plugin marketplace update mellos-mapping && claude plugin update mellos-m
|
|
|
116
150
|
拉取本仓库的是第一条命令。重启 Claude Code 生效。发布即 `main` 分支
|
|
117
151
|
上的版本号提升。(在对话里输入 `/plugin` 也能打开同一个管理界面。)
|
|
118
152
|
|
|
153
|
+
omp 也有自己的两步:
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
omp plugin marketplace update mellos-mapping && omp plugin upgrade mellos-mapping@mellos-mapping
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**先关面板**(面板里按 `q`):watcher 跑的就是插件副本里的文件,而 Windows 不
|
|
160
|
+
允许改名一个正被打开的文件——开着面板升级会以 `EPERM` 失败并把插件缓存清空
|
|
161
|
+
(旧副本已删、新副本未就位),用 `omp plugin install mellos-mapping@mellos-mapping
|
|
162
|
+
--force` 修回来。然后:第一条刷新市场目录,第二条按目录重装。omp 还会在启动时尽力刷新超过一天没更新过
|
|
163
|
+
的目录条目——除非 `marketplace.autoUpdate` 设为 `off`;默认的 `notify` 模式只把
|
|
164
|
+
"有可用更新"写进 debug 日志,所以让更新**看得见**的是 `marketplace update` 这一
|
|
165
|
+
步。`upgrade` 不比较版本:它按目录里现在指的内容强制重装,同版本号也会重下——
|
|
166
|
+
因此版本号提升是给发行**贴标签**,而不是送达的门槛。之后重启 omp,并把仍显示旧
|
|
167
|
+
运行文件的面板关掉重开(面板里按 `q`,再 `mmap_open`)。
|
|
168
|
+
|
|
119
169
|
### 从 0.19 升级
|
|
120
170
|
|
|
121
171
|
0.20 把地图存储从 `.claude/` 挪到了 `.mellos/`——地图属于这个工具,不属于
|
|
@@ -405,17 +455,26 @@ watcher 的:`--file <path>` 指定默认页的状态文件(启动脚本会
|
|
|
405
455
|
| `.mellos/quit` | `mmap` 开关发出的一次性"自己关掉"请求,以同样的方式被消费和删除 |
|
|
406
456
|
| `.mellos/viewers/<pid>.json` | 每个活着的面板一份报告——它正显示哪一页、自动跟随是否打开——运行期间每秒刷新一次(见[谁在看](#谁在看)) |
|
|
407
457
|
| `<上面任一文件>.<pid>.<随机>.tmp` | 正在落盘的一次写入;它要么被改名覆盖目标,要么被删掉。留下来说明那次写入失败(并已被报告),连清理都没能跑成 |
|
|
458
|
+
| `.mellos/.write-lock` | 操作系统项目锁使用的永久普通文件;不纳入 Git,正常运行时不得删除、改名或替换 |
|
|
408
459
|
|
|
409
|
-
地图文件是纯 JSON,想在 git
|
|
410
|
-
|
|
411
|
-
|
|
460
|
+
地图文件是纯 JSON,想在 git 里留下地图的历史就把它们提交进去。`focus`、`quit`、
|
|
461
|
+
`viewers/` 和 `.write-lock` 应加入 gitignore。前三者传递运行期消息;锁文件即使
|
|
462
|
+
没有进程持锁也应保留,不要当作临时文件清理。
|
|
412
463
|
|
|
413
464
|
**并发模型,直说。** 每次保存都是原子的——先写进一个私有的同级临时文件,
|
|
414
465
|
再改名覆盖目标——所以轮询存储的读者要么看到上一张完整的地图,要么看到新的
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
466
|
+
那张,绝不会读到写了一半的。所有写图入口(MCP、HTTP 查看器、watcher)都使用
|
|
467
|
+
同一把项目级、非阻塞的操作系统排他锁。锁使用独立的固定文件,与被原子替换的
|
|
468
|
+
地图文件分开;操作结束或进程退出后,操作系统释放锁,锁文件仍保留。锁被占用时
|
|
469
|
+
返回可重试的 `BUSY`。
|
|
470
|
+
|
|
471
|
+
这把锁串行执行每次操作的读取、修改和保存。基于先前读取计算的改动还应传入
|
|
472
|
+
`expectedRevision`:它在锁内比较,版本过旧返回 `CONFLICT`。省略它时,后续写入
|
|
473
|
+
仍可能覆盖同一字段或 `context` 这样的完整值。不同页面用于分开互不相关的工作;
|
|
474
|
+
共用一页时仍需带版本检查。底层 `saveMapFile`、手工编辑和仍在运行的旧进程不参与
|
|
475
|
+
这份约定。升级前须停掉该项目所有旧 MCP、查看器和 watcher 进程;残留的旧锁目录
|
|
476
|
+
需一次性迁移。完整边界和升级步骤见[持久化地图 API 指南](docs/map-api.md)与
|
|
477
|
+
[项目锁说明](docs/locking.md)。
|
|
419
478
|
|
|
420
479
|
### 图种
|
|
421
480
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { createRequire } from 'node:module'; const require =
|
|
2
|
+
import { createRequire as __mellosCreateRequire } from 'node:module'; const require = __mellosCreateRequire(import.meta.url);
|
|
3
3
|
|
|
4
4
|
// src/hook/session-start.ts
|
|
5
5
|
import { spawnSync } from "node:child_process";
|
|
@@ -129,11 +129,47 @@ function sessionStartContext(input) {
|
|
|
129
129
|
function hasMap(stateFile) {
|
|
130
130
|
return existsSync(stateFile) || existsSync(join4(dirname4(stateFile), PAGES_DIR_NAME));
|
|
131
131
|
}
|
|
132
|
+
function mmapBinDir(localAppData) {
|
|
133
|
+
return join4(localAppData, "mellos-mapping", "bin");
|
|
134
|
+
}
|
|
132
135
|
function mmapShimFilePath(localAppData) {
|
|
133
|
-
return join4(localAppData, "
|
|
136
|
+
return join4(mmapBinDir(localAppData), "mmap.cmd");
|
|
137
|
+
}
|
|
138
|
+
function mmapFallbackDirs(localAppData, home) {
|
|
139
|
+
return [join4(localAppData, "Microsoft", "WindowsApps"), join4(home, ".local", "bin")];
|
|
140
|
+
}
|
|
141
|
+
function pathNames(rawPath, dir) {
|
|
142
|
+
const norm = (s) => s.trim().replace(/^"|"$/g, "").replace(/[\\/]+$/, "").toLowerCase();
|
|
143
|
+
return rawPath.split(";").some((entry) => entry.trim() !== "" && norm(entry) === norm(dir));
|
|
144
|
+
}
|
|
145
|
+
function readIfPresent(path) {
|
|
146
|
+
try {
|
|
147
|
+
return readFileSync2(path, "utf8");
|
|
148
|
+
} catch {
|
|
149
|
+
return void 0;
|
|
150
|
+
}
|
|
134
151
|
}
|
|
135
152
|
function mmapShimCurrent(shimContent, mmapPath) {
|
|
136
|
-
|
|
153
|
+
if (shimContent === void 0) return false;
|
|
154
|
+
return shimContent.includes(`"${mmapPath}"`) || shimContent.includes(`"${mmapPath.replaceAll("\\", "/")}"`);
|
|
155
|
+
}
|
|
156
|
+
function shimIsOurs(content) {
|
|
157
|
+
if (content.includes("mellos-mapping mmap shim")) return true;
|
|
158
|
+
const quoted = /"([^"]*mmap\.mjs)"/.exec(content)?.[1];
|
|
159
|
+
return quoted !== void 0 && /mellos-mapping/i.test(quoted);
|
|
160
|
+
}
|
|
161
|
+
function mmapCommandResolves(localAppData, mmapPath, environment, read, exists) {
|
|
162
|
+
if (pathNames(environment.path, mmapBinDir(localAppData))) return true;
|
|
163
|
+
if (environment.home === void 0 || environment.home === "") return false;
|
|
164
|
+
for (const dir of mmapFallbackDirs(localAppData, environment.home)) {
|
|
165
|
+
if (!exists(dir) || !pathNames(environment.path, dir)) continue;
|
|
166
|
+
const files = ["mmap.cmd", "mmap"].map((name) => read(join4(dir, name))).filter((content) => content !== void 0);
|
|
167
|
+
if (files.length === 0) continue;
|
|
168
|
+
const ours = files.filter((content) => shimIsOurs(content));
|
|
169
|
+
if (ours.length === 0) return true;
|
|
170
|
+
return ours.every((content) => mmapShimCurrent(content, mmapPath));
|
|
171
|
+
}
|
|
172
|
+
return false;
|
|
137
173
|
}
|
|
138
174
|
function installContextLine(outcome) {
|
|
139
175
|
if (typeof outcome !== "object" || outcome === null) return void 0;
|
|
@@ -150,11 +186,22 @@ function installContextLine(outcome) {
|
|
|
150
186
|
}
|
|
151
187
|
if (o.path === "refused" || o.path === "error") {
|
|
152
188
|
const reason = typeof o.reason === "string" ? o.reason : "the PATH edit failed";
|
|
189
|
+
const aliasDir = typeof o.alias === "object" && o.alias !== null && "dir" in o.alias && typeof o.alias.dir === "string" ? o.alias.dir : void 0;
|
|
190
|
+
if (aliasDir !== void 0) {
|
|
191
|
+
return [
|
|
192
|
+
`mellos-mapping: the \`mmap\` terminal command should work: its shims live in`,
|
|
193
|
+
`${o.binDir}, and \u2014 because the user PATH could not be changed (${reason}) \u2014 a second copy`,
|
|
194
|
+
`was written to ${aliasDir}, a directory PATH already names (so \`mmap\` resolves there unless`,
|
|
195
|
+
"something earlier in PATH claims the name first).",
|
|
196
|
+
"The user can therefore type `mmap` in a new terminal right now; the command opens the map",
|
|
197
|
+
"pane for the project it is typed in, or closes the open one."
|
|
198
|
+
].join("\n");
|
|
199
|
+
}
|
|
153
200
|
return [
|
|
154
201
|
`mellos-mapping: the \`mmap\` command's launcher was written to ${o.binDir},`,
|
|
155
202
|
`but the user PATH was NOT changed: ${reason}.`,
|
|
156
203
|
"If the user wants the `mmap` pane-toggle command, tell them to add that directory to",
|
|
157
|
-
'their user PATH (Settings > "Edit environment variables for
|
|
204
|
+
'their user PATH (Settings > "Edit environment variables for their account").'
|
|
158
205
|
].join("\n");
|
|
159
206
|
}
|
|
160
207
|
return void 0;
|
|
@@ -164,15 +211,18 @@ function ensureMmapCommand(pluginRoot) {
|
|
|
164
211
|
const localAppData = process.env["LOCALAPPDATA"];
|
|
165
212
|
if (localAppData === void 0 || localAppData === "") return void 0;
|
|
166
213
|
const mmapPath = join4(pluginRoot, "dist", "mmap.mjs");
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
214
|
+
const shim = readIfPresent(mmapShimFilePath(localAppData));
|
|
215
|
+
const resolves = mmapShimCurrent(shim, mmapPath) && mmapCommandResolves(
|
|
216
|
+
localAppData,
|
|
217
|
+
mmapPath,
|
|
218
|
+
{ path: process.env["PATH"] ?? "", home: process.env["USERPROFILE"] ?? process.env["HOME"] },
|
|
219
|
+
readIfPresent,
|
|
220
|
+
existsSync
|
|
221
|
+
);
|
|
222
|
+
if (resolves) return void 0;
|
|
223
|
+
const runtime = "bun" in process.versions ? "node" : process.execPath;
|
|
174
224
|
const run = spawnSync(
|
|
175
|
-
|
|
225
|
+
runtime,
|
|
176
226
|
[join4(pluginRoot, "scripts", "install-mmap-command.mjs"), "--json"],
|
|
177
227
|
{ encoding: "utf8", windowsHide: true, timeout: 15e3 }
|
|
178
228
|
);
|
|
@@ -236,12 +286,18 @@ if (launchedAsEntry(process.argv[1], import.meta.url)) {
|
|
|
236
286
|
main().catch(() => process.exit(0));
|
|
237
287
|
}
|
|
238
288
|
export {
|
|
289
|
+
ensureMmapCommand,
|
|
239
290
|
hasMap,
|
|
240
291
|
hookOutput,
|
|
241
292
|
installContextLine,
|
|
242
293
|
launchedAsEntry,
|
|
294
|
+
mmapBinDir,
|
|
295
|
+
mmapCommandResolves,
|
|
296
|
+
mmapFallbackDirs,
|
|
243
297
|
mmapShimCurrent,
|
|
244
298
|
mmapShimFilePath,
|
|
245
299
|
parseHookInput,
|
|
246
|
-
|
|
300
|
+
pathNames,
|
|
301
|
+
sessionStartContext,
|
|
302
|
+
shimIsOurs
|
|
247
303
|
};
|