{"_id":"@alotop/dsh-matlab-bridge","_rev":"5-87136ecc730f2ddabfed3593402650e0","name":"@alotop/dsh-matlab-bridge","dist-tags":{"latest":"0.2.0"},"versions":{"0.1.1":{"name":"@alotop/dsh-matlab-bridge","version":"0.1.1","keywords":["dsh","dsh-plugin","cordis","matlab","debugger","matlab-engine"],"author":{"name":"alotop"},"license":"MIT","_id":"@alotop/dsh-matlab-bridge@0.1.1","maintainers":[{"name":"alotop","email":"oem0032011@hotmail.com"}],"homepage":"https://github.com/alotop/dsh-matlab-bridge#readme","bugs":{"url":"https://github.com/alotop/dsh-matlab-bridge/issues"},"bin":{"dsh-matlab-bridge-setup":"scripts/setup-engine.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"}},"dist":{"shasum":"0720d3f623613c84291952fc2649887180ee9af6","tarball":"https://registry.npmjs.org/@alotop/dsh-matlab-bridge/-/dsh-matlab-bridge-0.1.1.tgz","fileCount":13,"integrity":"sha512-8R/l/9M6ayxscC4H90PFoDenxdhYepMh1TKhY8n7z3wP2k7cjX2XFI7ksAkW8b9t1XxnKOysEfXdgSiBsUMYVQ==","signatures":[{"sig":"MEUCIDlukTxumbLmzoAX9mNYPdT+ri3MaVtujt66aJlDIE3SAiEAzhbrxy0CTK0rykIgYaaoAtC8s5FxJ+BewsuZIiAgdO4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":83578},"type":"module","engines":{"node":">=20"},"exports":{".":"./src/plugin.mjs"},"gitHead":"7f326486c2ede4acc07e0950553dddacf8086b90","scripts":{"check":"node --check src/plugin.mjs && node --check scripts/setup-engine.mjs","setup":"node scripts/setup-engine.mjs","selftest":"node scripts/run-selftest.mjs"},"_npmUser":{"name":"alotop","email":"oem0032011@hotmail.com"},"deprecated":"wrong repository metadata; use >= 0.1.6","repository":{"url":"git+https://github.com/alotop/dsh-matlab-bridge.git","type":"git"},"_npmVersion":"11.5.2","description":"Run and interactively debug MATLAB code from a DSH session, through a persistent MATLAB Engine session.","directories":{},"_nodeVersion":"22.19.0","publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/dsh-matlab-bridge_0.1.1_1789233604012_0.29352856280560724","host":"s3://npm-registry-packages-npm-production"}},"0.1.5":{"name":"@alotop/dsh-matlab-bridge","version":"0.1.5","keywords":["dsh","dsh-plugin","cordis","matlab","debugger","matlab-engine"],"author":{"name":"alotop"},"license":"MIT","_id":"@alotop/dsh-matlab-bridge@0.1.5","maintainers":[{"name":"alotop","email":"oem0032011@hotmail.com"}],"homepage":"https://github.com/alotop/dsh-matlab#readme","bugs":{"url":"https://github.com/alotop/dsh-matlab/issues"},"bin":{"dsh-matlab-bridge-setup":"scripts/setup-engine.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"}},"dist":{"shasum":"40eac228d6af884980b1f49a6f058470425ba634","tarball":"https://registry.npmjs.org/@alotop/dsh-matlab-bridge/-/dsh-matlab-bridge-0.1.5.tgz","fileCount":14,"integrity":"sha512-7vxwbJv/5P1Qmad9It9SLVfMJDHGC/GX47cSyffJNxav0eRDsUskWPmCb2x0tRSx/0LsABorBXS70pfkJjBhKw==","signatures":[{"sig":"MEYCIQC58fou2P+SYfUxnlmucqXCpj75/v4jr1GJrGiyfAst1gIhAJwEvS0C6gbVAd2L0nJGyKrgPlBQUORoyyr+LlkO2TNf","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":90144},"type":"module","engines":{"node":">=20"},"exports":{".":"./src/plugin.mjs"},"gitHead":"2b3fcd2e88583083d2ba548079e237de6164f015","scripts":{"check":"node --check src/plugin.mjs && node --check scripts/setup-engine.mjs && node --check scripts/run-selftest.mjs && node --check scripts/inspect-tarball.mjs","setup":"node scripts/setup-engine.mjs","selftest":"node scripts/run-selftest.mjs","pack:check":"npm pack --dry-run --json > pack.json && node scripts/inspect-tarball.mjs"},"_npmUser":{"name":"alotop","email":"oem0032011@hotmail.com"},"repository":{"url":"git+https://github.com/alotop/dsh-matlab.git","type":"git"},"_npmVersion":"11.5.2","description":"Run and interactively debug MATLAB code from a DSH session, through a persistent MATLAB Engine session.","directories":{},"_nodeVersion":"22.19.0","publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/dsh-matlab-bridge_0.1.5_1789237561492_0.903859572241803","host":"s3://npm-registry-packages-npm-production"}},"0.1.6":{"name":"@alotop/dsh-matlab-bridge","version":"0.1.6","keywords":["dsh","dsh-plugin","cordis","matlab","debugger","matlab-engine"],"author":{"name":"alotop"},"license":"MIT","_id":"@alotop/dsh-matlab-bridge@0.1.6","maintainers":[{"name":"alotop","email":"oem0032011@hotmail.com"}],"homepage":"https://github.com/alotop/dsh-matlab#readme","bugs":{"url":"https://github.com/alotop/dsh-matlab/issues"},"bin":{"dsh-matlab-bridge-setup":"scripts/setup-engine.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"}},"dist":{"shasum":"475274900f2630914eafad858d2385d298b53295","tarball":"https://registry.npmjs.org/@alotop/dsh-matlab-bridge/-/dsh-matlab-bridge-0.1.6.tgz","fileCount":14,"integrity":"sha512-+sOWcdqN9nIoKTcjyAKhbazsJ3EhaGrxqbgCH7xR0aenqpJV/cjXdO1pnq9doSAsKozJaUBjG0tQwU34u/XVOw==","signatures":[{"sig":"MEUCIQCIkOWIZpeDOt9eJw/4c7BUTd8sB/J3kl0Jc+w7vpNG7wIgJzdXAFj6db6gO+E861VKIWR0AxnbgN80kknlDv4vQ0E=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alotop%2fdsh-matlab-bridge@0.1.6","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":90144},"type":"module","engines":{"node":">=20"},"exports":{".":"./src/plugin.mjs"},"gitHead":"12ee5d0e59212d9f1048d940a81222e59bbd1805","scripts":{"check":"node --check src/plugin.mjs && node --check scripts/setup-engine.mjs && node --check scripts/run-selftest.mjs && node --check scripts/inspect-tarball.mjs","setup":"node scripts/setup-engine.mjs","selftest":"node scripts/run-selftest.mjs","pack:check":"npm pack --dry-run --json > pack.json && node scripts/inspect-tarball.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:82d34373-6cb9-4285-b633-7d5cb5a72082"}},"repository":{"url":"git+https://github.com/alotop/dsh-matlab.git","type":"git"},"_npmVersion":"12.0.2","description":"Run and interactively debug MATLAB code from a DSH session, through a persistent MATLAB Engine session.","directories":{},"_nodeVersion":"22.23.2","publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/dsh-matlab-bridge_0.1.6_1789238300205_0.7549825862829127","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"_id":"@alotop/dsh-matlab-bridge@0.2.0","bin":{"dsh-matlab-bridge-setup":"scripts/setup-engine.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"}},"bugs":{"url":"https://github.com/alotop/dsh-matlab/issues"},"dist":{"shasum":"bb4a10e14b9f04a8ac7904373fc223d40644e8e8","tarball":"https://registry.npmjs.org/@alotop/dsh-matlab-bridge/-/dsh-matlab-bridge-0.2.0.tgz","fileCount":14,"integrity":"sha512-049VYoWa709jkbQFCaUXKqJknuDlGla/sK2xS3I//xj9N/qCpQGeXRFHNLntCH9y408RkiYCFG3z7xota0kcRQ==","signatures":[{"sig":"MEUCIFX5MA9b9TGgaeJVHpEOvAybZjmWwoIn2B+mbLHhIELaAiEA/2oeDkLNmBaKS1UTSaeQYoWYmtYUS6KWzE791O65Dbc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCICS26+w1nt9cEbHXe32Lsy1oct9As4/pw/3lnPpXw+VHAiEA38H6ZaKRnN7MigKqxQ5aYCyi0oX8mEOrU/Usc/bsoB8="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alotop%2fdsh-matlab-bridge@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":100233},"name":"@alotop/dsh-matlab-bridge","type":"module","author":{"name":"alotop"},"engines":{"node":">=20"},"exports":{".":"./src/plugin.mjs"},"gitHead":"208973e6b528ea1e6cad36ca4219f91f09317ad5","license":"MIT","scripts":{"check":"node --check src/plugin.mjs && node --check scripts/setup-engine.mjs && node --check scripts/run-selftest.mjs && node --check scripts/inspect-tarball.mjs","setup":"node scripts/setup-engine.mjs","selftest":"node scripts/run-selftest.mjs","pack:check":"npm pack --dry-run --json > pack.json && node scripts/inspect-tarball.mjs"},"version":"0.2.0","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:82d34373-6cb9-4285-b633-7d5cb5a72082"}},"homepage":"https://github.com/alotop/dsh-matlab#readme","keywords":["dsh","dsh-plugin","cordis","matlab","debugger","matlab-engine"],"repository":{"url":"git+https://github.com/alotop/dsh-matlab.git","type":"git"},"_npmVersion":"12.0.2","description":"Run and interactively debug MATLAB code from a DSH session, through a persistent MATLAB Engine session.","directories":{},"maintainers":[{"name":"alotop","email":"157029761+alotop@users.noreply.github.com"}],"_nodeVersion":"22.23.2","publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dsh-matlab-bridge_0.2.0_1789832847287_0.927184900083805"}}},"time":{"created":"2026-09-12T17:20:03.906Z","modified":"2026-09-19T15:47:27.748Z","0.1.1":"2026-09-12T17:20:04.148Z","0.1.5":"2026-09-12T18:26:01.627Z","0.1.6":"2026-09-12T18:38:20.341Z","0.2.0":"2026-09-19T15:47:27.362Z"},"bugs":{"url":"https://github.com/alotop/dsh-matlab/issues"},"author":{"name":"alotop"},"license":"MIT","homepage":"https://github.com/alotop/dsh-matlab#readme","keywords":["dsh","dsh-plugin","cordis","matlab","debugger","matlab-engine"],"repository":{"url":"git+https://github.com/alotop/dsh-matlab.git","type":"git"},"description":"Run and interactively debug MATLAB code from a DSH session, through a persistent MATLAB Engine session.","maintainers":[{"name":"alotop","email":"157029761+alotop@users.noreply.github.com"}],"readme":"# @alotop/dsh-matlab-bridge\n\n在 [DSH](https://github.com/deepseek-ai) 会话里**运行和交互式单步调试** MATLAB 代码，底层是一个常驻的 MATLAB Engine 会话。\n\n[![npm](https://img.shields.io/npm/v/@alotop/dsh-matlab-bridge.svg)](https://www.npmjs.com/package/@alotop/dsh-matlab-bridge)\n[![license](https://img.shields.io/npm/l/@alotop/dsh-matlab-bridge.svg)](LICENSE)\n\n[English](README.md)\n\n---\n\n## 为什么需要它\n\nMATLAB 在 DSH 默认的 `workspace-write` 文件沙箱下**根本无法启动**。它在启动时会写工作区之外的位置（偏好设置、许可缓存），然后直接崩掉：\n\n```\nFatal Startup Error: System error: File system inconsistency\n```\n\n把偏好目录重定向到可写位置**也没用**。所以用 shell 去驱动 `matlab -batch`，代价是**每一次调用都要一次沙箱提权**。\n\n本插件改为通过非受限的 `ctx.subprocess` 通道启动驱动进程，这笔代价只需付一次——而且它保持一个 MATLAB Engine 会话存活，这正是一切调试能力的前提。\n\n### 为什么必须常驻会话，而不是 `matlab -batch`\n\n`matlab -batch` 每次调用都要**约 20 秒冷启动**，而且什么都不保留：变量、打开的图形、断点全部丢失。更关键的是它**无法单步调试**——断点命中时 MATLAB 自己的命令循环被阻塞，要发出 `dbstep` 必须有带外求值器，而官方 MATLAB Engine API 提供的正是这个。\n\n```\nDSH 会话 ──ctx.subprocess.spawn──▶ python ml_driver.py\n                                    │ matlab.engine\n                                    ▼\n                          常驻、可调试的 MATLAB\n```\n\n## 环境要求\n\n| | |\n|---|---|\n| MATLAB | R2020a 或更新（需要 `exportgraphics`）。任意标准安装即可，用的是它自带的 `extern/engines/python`。 |\n| Python | 3.9 – 3.13，需在 `PATH` 上 |\n| Node.js | 20 或更新 |\n\n引擎自带的声明是支持 Python 3.9–3.12，但它附带的是**稳定 ABI（`abi3`）**扩展模块，实测在 3.13 上也能正常装载和运行。\n\n## 安装\n\n```sh\n# 1. 把包装进你的 DSH profile\ndsh plugin --profile <profile> add @alotop/dsh-matlab-bridge\n\n# 2. 在「已安装的那份」里铺开 Engine 运行库\nnode \"<profile>/node_modules/@alotop/dsh-matlab-bridge/scripts/setup-engine.mjs\"\n\n# 3. 重启 DSH，让新的 bundle 层被组装进去\n```\n\n第 2 步会从你**已经装好的** MATLAB 里复制引擎，并生成引擎定位原生库所需的 `_arch.txt`。不下载任何东西，也不再分发任何 MathWorks 代码——详见 [LICENSE](LICENSE)。\n\n**第 2 步必须针对「已安装的那份」执行，不要跑仓库里的检出。** 脚本会写到它自己旁边的 `python/pylibs`，而插件是从自己的安装位置加载运行库的——铺到别处，已安装的那份仍然是空的。同一份安装也提供 `<profile>/node_modules/.bin/dsh-matlab-bridge-setup` 这个命令。\n\n### 为什么要声明 `dsh.bundle`\n\n`dsh plugin add` 只有在包的 `package.json` 声明了 `dsh.bundle` 时，才会把它记为 **profile layer**。本包把它指向 [`cordis.patch.yml`](cordis.patch.yml)，由后者插入 `matlab-bridge` 这一行。没有它，安装照样成功但**什么都不会注册**，DSH 也会明确提示：*declares no dsh.bundle — installed as a plain dependency, not a profile layer*。\n\n### 备选：写成 preset 行\n\n同一个插件也可以不用 profile bundle，而是从 agent preset 组装。该行只注册工具、不发布服务，因此直接放在 preset 顶层即可，不需要 `isolate` realm。\n\n```yaml\n- id: matlab-bridge\n  name: '@alotop/dsh-matlab-bridge'\n```\n\n### 独立使用，或从检出安装\n\n用于开发这个桥接本身，或者包还没发到 npm 之前：\n\n```sh\nnpm pack                                                       # 得到 alotop-dsh-matlab-bridge-<版本>.tgz\nnpx ./alotop-dsh-matlab-bridge-<版本>.tgz                      # 直接从 tarball 跑安装命令\nnpm install -g ./alotop-dsh-matlab-bridge-<版本>.tgz           # 或全局安装\nnpm install --no-save ./alotop-dsh-matlab-bridge-<版本>.tgz    # 或装进某个工程\n```\n\n只想试一下 tarball 时记得加 `--no-save`；否则 npm 会在那个工程的 `package.json` 里记下一条指向 tarball 的 `file:` 依赖。\n\n**只有一个包。** `dsh-matlab-bridge-setup` 是它的一个 `bin` 入口，不是独立包——`npx @alotop/dsh-matlab-bridge` 之所以能跑起它，是因为它是该包唯一的可执行文件。\n\n### 行配置\n\n全部可选，正常机器上无需任何配置。\n\n```yaml\n- id: matlab-bridge\n  name: '@alotop/dsh-matlab-bridge'\n  config:\n    pythonPath: python3.12            # 默认：PATH 上第一个 python3 / python\n    workDir: /path/to/project         # 默认：调用方会话的 cwd\n    figureDir: /tmp/figures           # 默认：<workDir>/.matlab-figures\n    timeoutMs: 180000                 # 默认：180000\n    shutdownEngineOnExit: true        # 默认：true\n```\n\n## 工具\n\n### `matlab_run`\n\n在常驻会话里运行 MATLAB 代码，返回命令窗口输出。**变量、图形、数据跨调用保留。** 用 `disp`/`fprintf` 打印，或者传入单个裸表达式让它显示值。失败时返回 MATLAB 错误信息与错误栈。\n\n### `matlab_debug`\n\n驱动 MATLAB 调试器。动作：`break`、`breakError`、`clearBreaks`、`run`、`status`、`stack`、`vars`、`get`、`eval`、`step`、`stepIn`、`stepOut`、`continue`、`quit`、`finish`。\n\n一次真实会话：\n\n```\nmatlab_debug action=break file=myfunc line=12   → ok\nmatlab_debug action=run   code=\"myfunc(data)\"   → state: paused\nmatlab_debug action=vars                        → 暂停帧的局部变量\nmatlab_debug action=get   name=startIndex       → 7\nmatlab_debug action=eval  code=\"n - k + 1\"      → 8\nmatlab_debug action=step                        → state: paused（下一行）\nmatlab_debug action=continue                    → state: completed\n```\n\n`eval` 在**暂停帧内部**求值，所以可以在不改文件的前提下验证对某个活变量的推断。断点打在注释或空行上会绑定到下一个可执行行，与 MATLAB 编辑器行为一致。\n\n### `matlab_figure`\n\n检查与导出图形。`list` 列出打开的 figure，`save` 把每张图导出为 150 DPI 的 PNG 并返回路径，`close` 关闭一张或全部。\n\n先用 `matlab_run` 画图，再导出——figure 留在会话里。**拿到路径后要用 `read_image` 把 PNG 读回来**；只拿路径等于没看图。\n\n### `matlab_session`\n\n`start`、`status`、`stop`。MATLAB 启动要几十秒，所以会话保持热态并复用。\n\n`status` 会报告包路径、**驱动实际使用的 Python 解释器**、驱动是否在跑、引擎运行库是否已铺开、以及退出 DSH 时是否关闭 MATLAB。解释器值得显示出来——在有多个 Python 的机器上，PATH 上先解析到的那个不一定是 setup 验证过的那个，两者不一致时 `pythonPath` 就是解药。\n\n## 命令\n\n四个人工入口，用于那些不该出现在模型工具面上的操作：\n\n| 命令 | 作用 |\n|---|---|\n| `/matlab-status` | 与 `matlab_session status` 同一份报告 |\n| `/matlab-start` | 启动常驻引擎会话 |\n| `/matlab-stop` | 关闭 MATLAB 并停止驱动 |\n| `/matlab-setup` | 从本地 MATLAB 铺开引擎运行库 |\n\n`/matlab-setup` 走的是与其它操作相同的非受限 subprocess 通道，因此它能写入**已安装的包目录**（位于任何会话工作区之外），不需要你另开终端。\n\n### DSH 退出时是否关闭 MATLAB\n\n`shutdownEngineOnExit`（默认 `true`）决定关闭 DSH 时是否一并关闭 MATLAB。默认开启，因为驱动是子进程：直接杀掉它会留下一个**无人认领**的 MATLAB 引擎。\n\n两条机制覆盖 DSH 两种退出方式：\n\n- 正常的插件卸载会写入关闭请求并关闭驱动的 stdin，驱动自己跑完 `engine.quit()` 后退出；\n- 如果 DSH 根本没卸载插件就退出，那条管道关闭会以 **EOF** 形式到达驱动，驱动同样退出 MATLAB 后再结束。\n\n设为 `false` 可让 DSH 退出时保留 MATLAB。但在没有 shared engine 会话的前提下，没有任何东西能重接上去，它只会变成一个孤儿进程——适合临时查看一个活会话，不是\"保留会话\"的办法。\n\n## 工作原理\n\n| 文件 | 作用 |\n|---|---|\n| `src/plugin.mjs` | Cordis 插件：定位自身文件、持有驱动进程、注册工具 |\n| `python/ml_driver.py` | 常驻驱动。stdin/stdout 上是行分隔 JSON，持有一个 MATLAB Engine 会话 |\n| `python/mfiles/dsh_evalbase.m` | 在 base 工作区求值，复现命令窗口的回显语义 |\n| `python/mfiles/dsh_figure_*.m` | 以 JSON 形式列举与导出 figure |\n| `scripts/setup-engine.mjs` | 从本地 MATLAB 铺开引擎运行库 |\n| `python/selftest.py` | 对真实 MATLAB 的端到端自检 |\n\n### 为什么协议要带 `@@DSH:` 前缀\n\nMATLAB Engine 会把 MATLAB 命令窗口输出转发到驱动的 stdout，裸 JSON 协议会和这些输出抢同一个流。因此每一行协议都带 `@@DSH:` 前缀，不带前缀的行一律视为 MATLAB 输出（诊断信息），而不是去解析它。\n\n### 命令窗口回显语义\n\n`dsh_evalbase.m` 调用 `evalc('evalin(''base'', code)')`，并且**刻意不给 `evalin` 输出参数**。这才让捕获行为与命令窗口一致：赋值回显 `x = 41`，裸表达式回显 `ans = 42`，无值语句不输出。反过来，去要输出参数会把这三者全部抑制；而靠源码文本猜\"是不是表达式\"则会误判命令语法（如 `dbstop in f at 4`）和无输出参数的调用（如 `disp('hi')`）。\n\n## 开发\n\n```sh\ngit clone https://github.com/alotop/dsh-matlab.git\ncd dsh-matlab\nnpm run setup      # 从本地 MATLAB 铺开引擎运行库\nnpm run selftest   # 对真实 MATLAB 的端到端检查（会启动一个）\nnpm run check      # 语法检查插件与脚本\n```\n\n`npm run selftest` 覆盖协议、输出捕获、错误上报、图形导出，以及完整的断点单步链路。它失败 = 驱动有问题，而不是插件或传输层的问题，故障域因此很小。\n\n## 已知限制\n\n- **图形以文件交付，不是内联图像。** `matlab_figure` 返回 PNG 路径。工具结果理论上可以携带内联图像块，但那要走附件服务换取引用；路径加 `read_image` 已经能让图可见，且不依赖任何服务契约。\n- **驱动被强杀可能遗留 MATLAB 进程。** 驱动在 `atexit` 里退出引擎，但被硬终止时 `atexit` 不会执行。用 `matlab_session` 的 `action=\"stop\"` 正常收尾。\n- **MATLAB 忙时查询会排队。** 引擎在单线程上串行处理请求，所以后台运行未命中时发出的 `dbstack` 探测会阻塞到该调用让出控制权。`run` 已改为先查完成状态再探栈，规避了最糟的情况。\n- **单步调试目前只在 Windows 上验证过。** 引擎铺开逻辑支持 `glnxa64` 与 `maca64`/`maci64`，但只有 Windows 跑过完整的端到端。欢迎其他平台的反馈。\n\n## 许可\n\n[MIT](LICENSE)。本包不再分发任何 MathWorks 代码；见许可文件末尾的说明。\n","readmeFilename":"README.zh-CN.md"}