mellos-mapping 0.20.2 → 0.22.1

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.
Files changed (68) hide show
  1. package/README.md +125 -88
  2. package/README.zh-CN.md +122 -84
  3. package/dist/hook-session-start.mjs +25 -19
  4. package/dist/mmap.mjs +302 -170
  5. package/dist/preview.mjs +1418 -0
  6. package/dist/server.mjs +1198 -400
  7. package/dist/store-paths.mjs +40 -21
  8. package/dist/terminal-worker.mjs +3188 -0
  9. package/dist/watch.mjs +523 -280
  10. package/dist/web/TERMINAL-LICENSES.txt +70 -0
  11. package/dist/web/app.css +967 -0
  12. package/dist/web/app.js +1356 -0
  13. package/dist/web/index.html +9 -0
  14. package/dist/web/terminal.css +9 -0
  15. package/dist/web/terminal.html +7 -0
  16. package/dist/web/terminal.js +9293 -0
  17. package/dist/web/xterm.css +285 -0
  18. package/dist/web.mjs +5535 -0
  19. package/docs/codex.md +183 -0
  20. package/lib/domain/text.d.ts +9 -0
  21. package/lib/domain/text.js +43 -0
  22. package/lib/domain/types.js +10 -1
  23. package/lib/preview/index.d.ts +3 -0
  24. package/lib/preview/index.js +3 -0
  25. package/lib/preview/markdown.d.ts +8 -0
  26. package/lib/preview/markdown.js +54 -0
  27. package/lib/preview/presentation.d.ts +6 -0
  28. package/lib/preview/presentation.js +14 -0
  29. package/lib/preview/publisher.d.ts +23 -0
  30. package/lib/preview/publisher.js +143 -0
  31. package/lib/preview/svg.d.ts +3 -0
  32. package/lib/preview/svg.js +74 -0
  33. package/lib/preview/text.d.ts +4 -0
  34. package/lib/preview/text.js +13 -0
  35. package/lib/render/canvas.d.ts +1 -1
  36. package/lib/render/canvas.js +4 -2
  37. package/lib/render/draw.js +9 -6
  38. package/lib/render/render.d.ts +6 -0
  39. package/lib/render/render.js +50 -18
  40. package/lib/render/width.js +3 -1
  41. package/lib/store/atomic.d.ts +18 -0
  42. package/lib/store/atomic.js +86 -0
  43. package/lib/store/channels.d.ts +40 -0
  44. package/lib/store/channels.js +135 -0
  45. package/lib/store/format.js +3 -1
  46. package/lib/store/json-text.d.ts +9 -0
  47. package/lib/store/json-text.js +16 -0
  48. package/lib/store/maps.d.ts +12 -0
  49. package/lib/store/maps.js +42 -0
  50. package/lib/store/migration.d.ts +12 -0
  51. package/lib/store/migration.js +46 -0
  52. package/lib/store/pages.d.ts +46 -0
  53. package/lib/store/pages.js +89 -0
  54. package/lib/store/policy.d.ts +74 -0
  55. package/lib/store/policy.js +144 -0
  56. package/lib/store/store.d.ts +9 -256
  57. package/lib/store/store.js +10 -694
  58. package/lib/store/viewers.d.ts +81 -0
  59. package/lib/store/viewers.js +186 -0
  60. package/package.json +25 -6
  61. package/scripts/codex-cli.mjs +42 -0
  62. package/scripts/codex-register.mjs +27 -94
  63. package/scripts/mmap.mjs +26 -16
  64. package/scripts/open-pane.mjs +37 -18
  65. package/scripts/pane-core.mjs +57 -220
  66. package/scripts/terminal-session.mjs +137 -0
  67. package/scripts/tmux-session.mjs +90 -0
  68. package/scripts/watcher-command.mjs +16 -0
package/README.md CHANGED
@@ -1,16 +1,20 @@
1
1
  # Mellos Mapping
2
2
 
3
- [![CI](https://github.com/GuangminJu/mellos-mapping/actions/workflows/ci.yml/badge.svg)](https://github.com/GuangminJu/mellos-mapping/actions/workflows/ci.yml)
3
+ [![npm](https://img.shields.io/npm/v/mellos-mapping?logo=npm&logoColor=white&label=npm&color=cb3837)](https://www.npmjs.com/package/mellos-mapping)
4
+ [![downloads](https://img.shields.io/npm/dm/mellos-mapping?label=downloads&color=cb3837)](https://www.npmjs.com/package/mellos-mapping)
5
+ [![MCP registry](https://img.shields.io/badge/MCP_registry-listed-2f6feb)](https://registry.modelcontextprotocol.io/v0/servers?search=io.github.GuangminJu/mellos-mapping)
6
+ [![CI](https://img.shields.io/github/actions/workflow/status/GuangminJu/mellos-mapping/ci.yml?branch=main&label=CI)](https://github.com/GuangminJu/mellos-mapping/actions/workflows/ci.yml)
7
+ [![license](https://img.shields.io/badge/license-MIT-444)](LICENSE)
4
8
 
5
9
  English | [简体中文](README.zh-CN.md)
6
10
 
7
11
  A live, terminal-native map of bottom-up development for
8
- [Claude Code](https://claude.com/claude-code) and Codex CLI.
12
+ [Claude Code](https://claude.com/claude-code), ChatGPT desktop Codex mode and Codex CLI.
9
13
 
10
14
  <p align="center">
11
15
  <picture>
12
16
  <source media="(prefers-color-scheme: light)" srcset="docs/demo-light.svg">
13
- <img alt="A Mellos map building itself: ghost design first, spinners climbing the layers, a cracked foundation spreading upward, honest recovery" src="docs/demo.svg" width="620">
17
+ <img alt="One declare puts the whole ghost design on screen, then the nodes light up from the bottom a foundation cracks, the damage spreads upward, and green is earned back" src="docs/demo.svg" width="620">
14
18
  </picture>
15
19
  </p>
16
20
 
@@ -20,42 +24,12 @@ dependency edges that may only point downward, ghost nodes for what is
20
24
  designed, a spinner on what is being built right now, and solid green for
21
25
  what is built *and verified*.
22
26
 
23
- ```
24
- Mellos Mapping · the plugin itself
25
-
26
- ━━━━━━━━━━━━━━━━━━━━━━━━━━ orchestration
27
-
28
- ╭╌╌╌╌╌╌╌╌╌╌╌╌╌╌╮
29
- ╎ · MCP Server ╎
30
- ╰╌╌╌╌┬╌┬╌╌┬╌╌╌╌╯
31
- │ │ │
32
- └─┼──┼─────────────┐
33
- │ └──────┐ │
34
- │ │ │
35
- ━━━━━━━━━┿━━━━━━━━━┿━━━━━━┿━━━ contracts
36
- │ │ │
37
- ┏━━━━━━┷━━━━━━━━┓│ ╭╌╌╌╌┴╌╌╌╌╌╌╮
38
- ┃ ■ State Store ┃│ ╎ · Watcher ╎
39
- ┗━━━━━┯━━━━━━━━━┛│ ╰╌╌╌╌╌┬╌╌╌╌╌╯
40
- │ │ │
41
- │ ┌────────┘ │
42
- │ │ │
43
- ━━━━━━━━┿━┿━━━━━━━━━━━━━━━━┿━ primitives
44
- │ │ │
45
- ┏━━━━━┷━┷━━━━━━┓ ╭──────┴───────────╮
46
- ┃ ■ Map Domain ┃ │ ⠋ ASCII Renderer │
47
- ┗━━━━━━━━━━━━━━┛ ╰──────────────────╯
48
-
49
- · planned ⠋ in-progress ■ done ✗ regressed
50
- ```
51
-
52
- In a real terminal the wiring and band bars render FAINT while node boxes
53
- glow in their status colors with bold labels — a dark circuit board where
54
- the components are the bright things. Skip-level edges thread through gaps
55
- between boxes (watch the line dive between State Store and Watcher above);
56
- non-overlapping wire segments share track rows to keep the bands close.
27
+ <p align="center">
28
+ <img alt="A Claude Code session with the Mellos map pane beside it: a six-layer game engine design, L0 and L1 nodes solid green, the upper layers still dashed ghost nodes" src="docs/session-claude-code.png">
29
+ </p>
57
30
 
58
- *(This is the plugin's own map, mid-development. The spinner really spins.)*
31
+ *A real session: Claude Code on the left, the map pane on the right. L0 is
32
+ verified, L1 just lit up, everything above is still a ghost.*
59
33
 
60
34
  ## Why
61
35
 
@@ -79,6 +53,21 @@ picture makes the discipline visible:
79
53
 
80
54
  ## Install
81
55
 
56
+ Clone the branch for your host, then run one command. No build is required.
57
+
58
+ | Branch | Audience | Command from the clone |
59
+ | --- | --- | --- |
60
+ | `main` | Shared source / either host | `node install.mjs chatgpt-app` or `node install.mjs claude` |
61
+ | `claude` | Claude Code | `node install.mjs` |
62
+ | `chatgpt-app` | ChatGPT desktop, Codex mode | `node install.mjs` |
63
+
64
+ Requires Node.js 18+ and the corresponding host CLI on PATH. The installer checks
65
+ release integrity and all six MCP tools, retains the runtime outside the clone,
66
+ and configures the host. Start a new conversation after installation.
67
+ See [release and branch instructions](docs/releasing.md).
68
+
69
+ Claude Code's marketplace installation is also available:
70
+
82
71
  Two lines inside any Claude Code conversation:
83
72
 
84
73
  ```
@@ -92,8 +81,7 @@ Or one line in a terminal:
92
81
  claude plugin marketplace add GuangminJu/mellos-mapping && claude plugin install mellos-mapping@mellos-mapping
93
82
  ```
94
83
 
95
- Requires Node.js 18+ on PATH (Claude Code itself requires Node, so you
96
- already have it). No build step: `dist/` is committed, so a clone runs as-is —
84
+ Requires Node.js 18+ on PATH (install Node separately when using native Claude Code). No build step: `dist/` is committed, so a clone runs as-is —
97
85
  `dist/server.mjs` (the MCP server), `dist/watch.mjs` (the pane),
98
86
  `dist/mmap.mjs` (the `mmap` toggle), `dist/hook-session-start.mjs` (the
99
87
  `SessionStart` hook that `hooks/hooks.json` registers) and
@@ -139,7 +127,7 @@ claude plugin marketplace update mellos-mapping && claude plugin update mellos-m
139
127
 
140
128
  Two steps because `plugin update` compares against the locally cached
141
129
  marketplace clone — the first command is what actually pulls this repo.
142
- Restart Claude Code to apply. Releases are version bumps on `master`.
130
+ Restart Claude Code to apply. Releases are version bumps on `main`.
143
131
  (In-app, `/plugin` opens the same management UI.)
144
132
 
145
133
  ### Upgrading from 0.19
@@ -166,31 +154,34 @@ That one move is the only time either process touches `.claude/`. Afterwards
166
154
  the tools write nowhere but `.mellos/`, and never outside the project
167
155
  directory they resolved at startup.
168
156
 
169
- ## Codex CLI
157
+ ## ChatGPT App · Codex mode
170
158
 
171
- The same repo doubles as a Codex plugin (codex-cli 0.147+). Three lines:
159
+ This is Codex mode in the ChatGPT desktop app (also called Codex App).
160
+ From the source branch run the following command; on `chatgpt-app`, omit the
161
+ host argument. It configures the desktop skill, marketplace and six MCP tools.
172
162
 
173
163
  ```
174
- codex plugin marketplace add GuangminJu/mellos-mapping
175
- codex plugin add mellos-mapping@mellos-mapping
176
- node ~/.codex/plugins/cache/mellos-mapping/mellos-mapping/<version>/scripts/codex-register.mjs
164
+ node install.mjs chatgpt-app
177
165
  ```
178
166
 
179
- The first two install the skill (the map discipline) as a Codex plugin. The
180
- third registers the MCP server at user level — needed because Codex spawns
181
- plugin-bundled MCP servers inside the plugin cache with no way to see your
182
- workspace, so a bundled server would write the map into the cache. A
183
- user-level `codex mcp add` entry (which the script writes) inherits each
184
- session's working directory instead: the state file lands in your project,
185
- same as under Claude Code. The registered path is version-specific — re-run
186
- the script after updating the plugin.
187
-
188
- To watch the live pane beside a Codex session on Windows, run
167
+ Start a new conversation. The desktop skill defaults to **web-terminal**:
168
+ `mmap_open {surface: "web-terminal", page: "<slug>"}` starts a local service,
169
+ then the AI opens its URL in the current conversation's right browser panel.
170
+ The mmap terminal starts automatically, with its own font-size selector;
171
+ no manual paste or Computer Use is needed. Graphical SVG, native terminal and
172
+ Markdown remain available. With an older MCP schema, run
173
+ `node "<plugin root>/dist/web.mjs" "<project>" --terminal --page <slug>`.
174
+ A queued panel request does not prove that the user can see it.
175
+ See [desktop installation and limitations](docs/codex.md).
176
+
177
+ For Codex CLI inside Windows Terminal (not the desktop integrated terminal), run
189
178
  `node <plugin root>/scripts/open-pane.mjs <project dir>` — it splits the
190
- terminal window hosting the session (or falls back to a dedicated
191
- "mellos-mapping" window; `--window` picks that on purpose). Add
179
+ terminal window hosting the session, keeping keyboard focus on the conversation.
180
+ If that window cannot be identified or focused, it reports failure without
181
+ opening elsewhere. `--window` explicitly chooses a separate window. Add
192
182
  `--page <slug>` to open on a particular page — and with a pane already open,
193
- rerunning with `--page` retargets it instead of opening another. The pane
183
+ rerunning with `--page` retargets the pane belonging to this console. A map
184
+ open in another session or a separate window does not count as this split. The pane
194
185
  auto-follows the page being written — the map the agent is operating on
195
186
  right now; press `f` to toggle that (a manual page switch also turns it
196
187
  off), or start with `--no-follow`. Elsewhere run
@@ -198,6 +189,32 @@ off), or start with `--no-follow`. Elsewhere run
198
189
  terminal (or any terminal split). Both take the same flags — see
199
190
  [Pane flags](#pane-flags).
200
191
 
192
+ ### Desktop Markdown map
193
+
194
+ When the user chooses the document surface, the skill uses
195
+ `mmap_open {surface: "markdown", page: "<slug>"}` and opens the returned file
196
+ beside the current conversation. The document embeds a colored SVG dependency
197
+ map plus module details, evidence, and child-page links. It needs no web server,
198
+ browser rendering process, Mermaid support, or additional runtime dependencies.
199
+
200
+ Successful MCP map writes regenerate enabled previews in `.mellos/previews/`;
201
+ JSON remains the source of truth. Image nodes are static. File visibility and
202
+ automatic viewer refresh belong to the desktop host. See the
203
+ [desktop map guide](docs/codex.md#desktop-right-side-map) for regeneration,
204
+ cache behavior, and limitations.
205
+
206
+ ### Optional interactive web viewer
207
+
208
+ An additional interactive web viewer is available with
209
+ `mmap_open {surface: "web", page: "<slug>"}` or
210
+ `node "<plugin root>/dist/web.mjs" "<project directory>" --page <slug>`.
211
+ Open its returned URL in the host's right browser panel. It provides live
212
+ updates, pan/zoom, hover and pinned details, search, dependency highlighting,
213
+ filters, group overview, submaps and themes. Stop it with
214
+ `node "<plugin root>/dist/web.mjs" "<project directory>" --stop`.
215
+ Markdown/SVG and terminal workflows remain available; all surfaces share the
216
+ same map data. See [web viewer details](docs/codex.md#optional-interactive-web-viewer).
217
+
201
218
  ## Any MCP client
202
219
 
203
220
  The server ships on npm, so any MCP client (Cursor, Windsurf, Zed,
@@ -222,7 +239,7 @@ servers), then the server process's own working directory. Set
222
239
  somewhere other than the project you are working in.
223
240
 
224
241
  The skill/discipline layer is Claude Code + Codex specific; other clients
225
- get the five `mmap_*` tools and the pane, and bring their own prompting.
242
+ get the six `mmap_*` tools and the pane, and bring their own prompting.
226
243
 
227
244
  ## Use
228
245
 
@@ -241,6 +258,25 @@ get the five `mmap_*` tools and the pane, and bring their own prompting.
241
258
  3. Watch nodes light up from the bottom. Interrupt when the picture worries
242
259
  you — that is what it is for.
243
260
 
261
+ On Linux and macOS, `mmap_open` and `mmap` automatically use tmux. The launcher
262
+ targets the inherited `TMUX`/`TMUX_PANE`; if the tool process lost those variables,
263
+ it discovers the single attached session on the default tmux server. The default
264
+ is a right split that preserves input focus; `--window` creates a new tmux window.
265
+ Repeated opens reuse the watcher bound to that source pane or session window.
266
+
267
+ For multiple attached sessions or a custom tmux socket, set these variables in
268
+ the environment of the MCP server (restart it after changing them):
269
+
270
+ | Variable | Meaning |
271
+ | --- | --- |
272
+ | `MELLOS_MAPPING_TMUX_TARGET` | Explicit tmux session or pane, such as `work:2.1` or `%7` |
273
+ | `MELLOS_MAPPING_TMUX_SOCKET` | Absolute socket path, for example `/tmp/my-tmux/socket` |
274
+
275
+ Ambiguous sessions, detached sessions and missing tmux produce a concrete error
276
+ and a fully quoted watcher command, including the project and requested page,
277
+ to paste into any visible terminal. Map writes remain available; after an open
278
+ failure the assistant retries only when the environment changes or you ask.
279
+
244
280
  The pane is mouse-aware (xterm SGR any-event tracking — the same protocol
245
281
  htop and tmux speak):
246
282
 
@@ -323,7 +359,7 @@ them verbatim and rejects anything it does not know rather than dropping it.
323
359
 
324
360
  | Flag | Effect |
325
361
  | --- | --- |
326
- | `--page <slug>` | open on this page; with a pane already running, retarget that pane instead of opening another |
362
+ | `--page <slug>` | open on this page; with this console’s pane already running, retarget it instead of opening another |
327
363
  | `--ascii` | pure-ASCII repertoire, for fonts without box-drawing glyphs |
328
364
  | `--no-color` | no ANSI color |
329
365
  | `--no-mouse` | no mouse reporting, if your terminal multiplexer wants the mouse for itself |
@@ -336,6 +372,13 @@ though one is already running for this project. Watcher-only: `--file <path>`
336
372
  names the default page's state file (the launcher derives it from the project
337
373
  directory).
338
374
 
375
+ Pane ownership is carried by the internal watcher flag `--owner <token>` and
376
+ the optional `owner` field in viewer reports. Launchers derive the token from
377
+ the source console process and its creation time; manual watchers can omit it.
378
+ Focus and quit requests to a bound viewer use its PID, so another window of
379
+ the same project cannot consume them. Bare `mmap` toggles only the pane bound
380
+ to the current console; `mmap --window` toggles the separate project window.
381
+
339
382
  ### The mmap command
340
383
 
341
384
  `mmap`, typed in any terminal, is a **toggle**: it opens the map pane for the
@@ -472,7 +515,10 @@ mean:
472
515
  - **control characters** in text fields — an ESC sequence stored in a label
473
516
  would let a map repaint the terminal of everyone who opens it. `detail` is
474
517
  the exception: newlines and tabs are how a note is written, everything else
475
- (ESC, BEL, lone CR) is still refused;
518
+ (ESC, BEL, lone CR) is still refused. File loading and library saves apply
519
+ the same control-character rules, retaining multiline evidence in older
520
+ files. Terminal rendering also neutralizes controls in maps constructed
521
+ directly by library callers;
476
522
  - **an empty string** where a field is optional — `null` is how a field is
477
523
  cleared, never a blank that renders as a box nobody can tell from a real
478
524
  one;
@@ -500,7 +546,7 @@ ends with what those reports say:
500
546
  | The line | What it means |
501
547
  | --- | --- |
502
548
  | `pane: CLOSED` | nobody is seeing this map; the assistant opens one with `mmap_open` instead of asking you to |
503
- | `pane: open on this page` | you are watching this land |
549
+ | `pane: running on this page` | a live process reports this page; its terminal may be hidden |
504
550
  | `pane: open on <other>, auto-follow on` | the pane follows the page last written, so it arrives here by itself |
505
551
  | `pane: open on <other>, auto-follow OFF` | you pinned that page by hand: the change is real and NOT on your screen. The assistant is told to say so rather than move your view |
506
552
 
@@ -510,6 +556,11 @@ not say which page was on screen. A report whose pane stopped refreshing it is
510
556
  ignored after five seconds and deleted after a minute, so a killed pane cannot
511
557
  go on claiming an audience.
512
558
 
559
+ A heartbeat does not establish screen visibility. An explicit tmux open also
560
+ selects the existing watcher's window, reveals it if another pane was zoomed,
561
+ and verifies the attached session's active window before reporting visibility.
562
+ Focusing that watcher in a shell without `TMUX` reuses its original owner.
563
+
513
564
  ### Setup: choose when maps open
514
565
 
515
566
  How eager mapping should be is a habit, not a property of a repository — so it
@@ -551,17 +602,18 @@ render as boxes and one id must mean one box.
551
602
 
552
603
  ## Development
553
604
 
605
+ See [contributing](CONTRIBUTING.md) and the
606
+ [project structure, branch and recovery guide](docs/project-maintenance.md).
607
+
554
608
  ```
555
- npm install
609
+ npm ci
556
610
  npm run verify
557
611
  ```
558
612
 
559
- `verify` is five steps, in this order: `typecheck` (the repo's own sources),
560
- `typecheck:packages` (the dsh plugin packages' framework-free modules, with
561
- `mellos-mapping/*` pointed at these sources), `test`, `build` (bundles
562
- `dist/`, emits `lib/` with declarations, cleaning both first), and
563
- `check:package` — which packs the tarball through the real `prepack`
564
- lifecycle and fails if any `exports` or `bin` target is missing from it.
613
+ Use Node.js 22.12+ for development. `verify` runs `typecheck`, `test`, `build`
614
+ (bundles `dist/` and emits `lib/` with declarations), `check:package`,
615
+ `check:codex`, and `check:release`. These check npm entrypoints, the Codex
616
+ package and both installable editions, including their MCP handshake.
565
617
 
566
618
  The repo is itself layered bottom-up, and each layer has its spec:
567
619
 
@@ -572,31 +624,16 @@ The repo is itself layered bottom-up, and each layer has its spec:
572
624
  | 1 store | `src/store/store.ts` | `store.test.ts`, `atomic-save.test.ts` | atomic state-file persistence on Node |
573
625
  | 1 semantics | `src/semantics/` | `semantics.test.ts` | medium-neutral view semantics: zoom ladder, group aggregation, page-set rules, sequence flip, the shared glyph vocabulary |
574
626
  | 2 apply | `src/server/apply.ts` | `apply.test.ts` | tool inputs → transactional op sequences |
575
- | 3 server | `src/server/server.ts` | `server.test.ts`, `save-failure.test.ts` | the five MCP tools over stdio |
627
+ | 3 server | `src/server/server.ts` | `server.test.ts`, `save-failure.test.ts` | the six MCP tools over stdio |
576
628
  | 4 render | `src/render/` | `render.test.ts`, `routing.test.ts` | the ASCII renderer and its wire routing |
577
629
  | 4 pane | `src/watch/` | `watch.test.ts`, `pane-state.test.ts`, `input.test.ts` | the polling pane: page set, input parsing, panel and chrome |
578
630
  | — launchers | `scripts/` | `open-pane.test.mjs`, `codex-register.test.mjs` | plain-node entry points |
579
- | — packaging | `package.json`, `packages/` | `tests/lockfile.test.ts`, `tests/packages.test.ts`, `browser-safe.test.ts` | what ships, and to whom |
631
+ | — packaging | `package.json` | `tests/lockfile.test.ts`, `browser-safe.test.ts` | what ships, and to whom |
580
632
 
581
633
  `dist/` is committed deliberately: plugin installation clones this repo and
582
634
  runs nothing, so entry points ship bundled. CI diffs the committed `dist/`
583
635
  against a fresh build, so a source change that forgets the rebuild fails.
584
636
 
585
- ### The dsh packages
586
-
587
- `packages/dsh` and `packages/dsh-client` are the DeepSeek Harness surface: a
588
- host plugin that reads and watches a workspace's `.mellos/` store, and the
589
- browser map panel that draws it with these same semantics. They are
590
- *developed* inside a dsh workspace checkout (its toolchain builds them) and
591
- *published* from here — sources, specs and `lib/` committed, refreshed by
592
- `node scripts/sync-dsh-plugin.mjs <path-to-deepseek-harness>`, which rewrites
593
- the dsh-internal package names to the published ones. This repo cannot build
594
- them, so it proves what it can: `typecheck:packages` and the framework-free
595
- specs run in CI, and `tests/packages.test.ts` guards the src↔lib structure,
596
- the shared version line, and the MCP row's spawn form. Specs that need the
597
- `@deepseek-ai` framework or a DOM are named, with their reason, in
598
- `vitest.config.ts`. See [`packages/dsh/README.md`](packages/dsh/README.md).
599
-
600
637
  ### Library
601
638
 
602
639
  The lower layers are also a library (`npm run build` emits `lib/` with type
@@ -615,7 +652,7 @@ declarations; npm packs it). Subpath exports mirror the source:
615
652
  **Browser-safe** means no Node builtins anywhere in the import closure, gated
616
653
  by a test, so a graphical client (a web panel, an editor view) can parse state
617
654
  files and reuse the exact aggregation, zoom and glyph semantics the terminal
618
- pane draws with. `packages/dsh-client` is that client.
655
+ pane draws with.
619
656
 
620
657
  ## License
621
658