dsh-vscode-mode 0.23.4 → 0.24.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 +118 -24
- package/lib/client.js +202 -15
- package/lib/client.js.map +2 -2
- package/lib/index.js +60 -16
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client/loadFailure.ts +84 -0
- package/src/client/monaco/loader.ts +9 -6
- package/src/client/pdf/pdfLoader.ts +10 -4
- package/src/client/rpc.ts +54 -10
- package/src/client/state/diffSummary.ts +4 -0
- package/src/client/ui/DiffBadge.ts +2 -2
- package/src/client/ui/EditorView.ts +2 -1
- package/src/pending/decide.ts +9 -2
- package/src/pending/store.ts +13 -9
- package/src/pendingCompat.ts +7 -1
- package/src/pendingRpc.ts +5 -2
- package/src/reviewDb.ts +25 -0
- package/src/reviewRpc.ts +7 -3
- package/src/shared/remoteChannel.ts +59 -0
- package/src/shared/rpc.ts +2 -2
package/README.md
CHANGED
|
@@ -1,13 +1,34 @@
|
|
|
1
1
|
# dsh-vscode-mode
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/dsh-vscode-mode)
|
|
4
|
+
[](https://github.com/Lenonss/DSH_VsCodeMode/releases)
|
|
5
|
+
[](https://github.com/Lenonss/DSH_VsCodeMode/actions/workflows/ci.yml)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
3
8
|
> DSH 上的**类 VSCode 编码体验**:Monaco 文件编辑器 + Agent 差异审查 + LSP 智能。
|
|
4
9
|
> 由 `@dsh-external/dsh-edit-review` 重构而来。
|
|
5
10
|
|
|
11
|
+

|
|
12
|
+
|
|
6
13
|
- 📝 **同屏编辑**:DSH 0.1.5+ 官方右侧 Sidebar,AI 对话与文件编辑同屏
|
|
7
14
|
- 🔍 **差异审查**:Keep / Undo / 回滚 / 归档,状态持久化重启不丢
|
|
8
15
|
- 🧠 **LSP 智能**:转到定义 / 查找引用 / Peek 多结果选择 / 智能补全(注释索引)/ 签名帮助
|
|
16
|
+
- 🐞 **断点调试**:DAP 桥通用化,行内断点、`.dsh/launch.json`、四段调试面板
|
|
9
17
|
- ⌨️ **命令面板**:`Ctrl+Shift+P`,19 条命令开箱即用,可编程扩展
|
|
10
18
|
|
|
19
|
+
**安装**:`npm i dsh-vscode-mode`(需 DSH 0.1.5+,装完重启 DSH)→ 详见[安装](#安装)。
|
|
20
|
+
|
|
21
|
+
**能力速览**
|
|
22
|
+
|
|
23
|
+
| 场景 | 你能得到什么 |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| 同屏编码 | 中央对话 + 右侧 Monaco,官方 Sidebar 多标签 / 分栏 / 浮出 / 全屏 |
|
|
26
|
+
| 审改动 | 行内红绿差异、累计基线待审、Keep / Undo / 回滚 / 归档,重启不丢 |
|
|
27
|
+
| 懂代码 | LSP:定义 / 引用 / Peek / 补全 / 签名帮助,按文件语言自动选后端 |
|
|
28
|
+
| 调问题 | DAP:断点、调用堆栈、变量、监视、调试控制台 REPL(Lua attach / .NET) |
|
|
29
|
+
| 管文件 | 活动栏 + 资源管理器 + 右键菜单 + 工作区搜索 + SVN 状态徽标 |
|
|
30
|
+
| 看文档 | Markdown 预览、PDF 注释编辑、Excel 基础编辑与只读数据预览 |
|
|
31
|
+
|
|
11
32
|
## 目录
|
|
12
33
|
|
|
13
34
|
- [特性](#特性)
|
|
@@ -336,7 +357,7 @@ DSH 启动回放 `~/.dsh/sessions` 全部会话(V8 展开约 10×,可能 OOM
|
|
|
336
357
|
- 治理原则:存量靠归档、增量靠压缩调优 + 短会话习惯 + 体积指示器;packChunks
|
|
337
358
|
(chunk 打包存储)为 DSH 默认开启,无需再配置。
|
|
338
359
|
|
|
339
|
-
### 14.
|
|
360
|
+
### 14. 外部改动自动同步(v0.4.4)
|
|
340
361
|
|
|
341
362
|
磁盘文件被外部改动(其他编辑器 / Unity / 脚本 / agent 工具 / 同步盘)后自动
|
|
342
363
|
跟进,不必手点 ⟳:
|
|
@@ -453,7 +474,7 @@ TortoiseSVN(`TortoiseProc.exe`)仅作 Windows 过渡增强:自研能力覆
|
|
|
453
474
|
|
|
454
475
|
> 说明:`plans/`(含对标蓝图与实测结论)为本地开发资料,不入库。
|
|
455
476
|
|
|
456
|
-
### 17. 断点调试(DAP
|
|
477
|
+
### 17. 断点调试(DAP,v0.6.0)
|
|
457
478
|
|
|
458
479
|
编辑器内断点调试(DAP 桥通用化:适配器由扩展清单 `contributes.debuggers` 驱动,
|
|
459
480
|
不限定语言;Lua 链路复用已装 emmylua 扩展适配器,**零游戏侧改动**):
|
|
@@ -517,29 +538,47 @@ DSH 每次启动监听随机端口,`http://127.0.0.1:<port>` 就是浏览器 o
|
|
|
517
538
|
`DSH_HOME/dsh-vscode-mode/logs/debug.<hashOf(cwd)>.log`(无会话期诊断落在
|
|
518
539
|
`debug.<hashOf('ui-state')>.log`)。
|
|
519
540
|
|
|
541
|
+
### 19. 远程访问兼容(经第三方远程访问插件访问)
|
|
542
|
+
|
|
543
|
+
宿主 `/edrv/*` 的准入是 `connection.requestRejection()`,**Host 围栏优先于登录态**:
|
|
544
|
+
只认 loopback、监听 bind IP 与 `trustedHosts`。远程设备访问时 `Host` 不符即 403,
|
|
545
|
+
与是否已经登录无关(401 才是登录失效)。第三方远程访问插件
|
|
546
|
+
(`@linxin666/dsh-remote-web-ui` 等)把 `/api/`、`/sidebar/`、`/git/`、`/pet/` 改写到它的
|
|
547
|
+
`/remote` 通道,`/edrv/` 不在白名单内,所以文件管理器 RPC 与 Monaco 静态资源全部直连
|
|
548
|
+
宿主被拒。
|
|
549
|
+
|
|
550
|
+
本插件按「通道前缀」适配(`src/shared/remoteChannel.ts`):
|
|
551
|
+
|
|
552
|
+
- **判定**:远程通道在 `<head>` 解析期安装座位对象 `__DSH_REMOTE_CHANNEL_BOOT__`;
|
|
553
|
+
存在即认为本页经远程通道访问,前缀取 `/remote`,否则为空串。
|
|
554
|
+
- **覆盖**:`/edrv/rpc`(业务 RPC 与二进制预览)、Monaco 的 `loader.js` / AMD 模块 /
|
|
555
|
+
`editor.main.css` / codicon 字体 / 语言 Worker(随 `paths.vs` 继承)、pdf.js 的
|
|
556
|
+
worker 与 cmaps、`/edrv/assets/*` 图片全部走 `transportUrl()`,`appUrl()` 继续负责
|
|
557
|
+
应用 base 与桌面 `dsh-app://` 协议,不硬编码主机或端口。
|
|
558
|
+
- **为什么不是 `/api/edrv`**:远程插件的补丁只改 fetch / EventSource / WebSocket 与
|
|
559
|
+
`<img|script|iframe>.src`,`<link rel=stylesheet>`、CSS `url()`、`new Worker`、
|
|
560
|
+
ESM `import` 都不经过补丁;服务端 `/remote/<内部路径>` 才是覆盖全资源类型的正式通道。
|
|
561
|
+
- **安全与兼容**:不新增路由、不改 `admitRoute`、不公开任何静态资源;`/remote` 门禁
|
|
562
|
+
仍要求已配对设备(其设备 cookie 同源携带),转发到回环后本插件的权限校验照常执行;
|
|
563
|
+
本地与桌面入口保持 `/edrv/*` 原样,未装远程插件时行为不变。
|
|
564
|
+
|
|
520
565
|
## 安装
|
|
521
566
|
|
|
522
567
|
官方 `dsh plugin` 方式,三选一。下面以 `web` profile 为例;Desktop 或其他命名
|
|
523
|
-
profile 请替换为实际目标,不要把示例目录当成当前运行 profile
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
**v0.22.0** 的累计基线待审(非 UI 能力对齐 dsh-diff-approval):同一文件的多次编辑折叠成一条待审、基线保留最早内容,A→B→C 显示 A→C、A→B→A 自然归零;Keep 只推进基线不改磁盘,Revert 走版本守卫写回并读回校验,撤销/重做用游标模型跨重启保留;新增 `str_replace_editor` 预像配对、`fs/observed` 终像、已入列路径的外部改动吸收与缺失/不可读生命周期、git/svn/Perforce 基线导入,以及旧 sidecar 写入口对已接管路径的服务端拒绝。差异仍在编辑器内行内展示、块级 Keep/Undo 用药丸,文件级在差异栏;详情面板与批注(含「让 AI 应答」)本版移除。验收边界:p4 仅有假 shell 单测(本机无 Perforce 客户端),「让 AI 应答」随批注一并下线故不再验证;本版未在宿主上重启验收 GUI 全流程,见 [0.22.0 发布说明](docs/release-0.22.0.md)。以下保留历史版本事实:
|
|
528
|
-
**v0.21.4** 的任务发送结果分类与诚实草稿降级:只有明确 accepted 才等待分析方案;unknown/submitted/cancelled 不另填草稿或重发,安全降级只填实际当前会话草稿并提示手动发送。旧 boolean 接口保留,legacy true 不等于受理。开发 link 客户端 rev458288ddb012 的真实公开入口与目标受理已验;完整 SVN 分析/方案投递因 `SetNamedSecurityInfoW failed (Win32 5)` 未完成,用户仅本批接受此缺口,不代表 Host 整体升级或当前实例已安装 npm 0.21.4。见 [0.21.4 发布说明](docs/release-0.21.4.md)。保留以下历史版本事实:
|
|
529
|
-
**v0.21.3** 的 MCP 初始化失败结果与安全收尾解耦:已进入 startup 的调用者在失败或截止时间到达时及时收到拒绝,不再等待旧资源收尾;旧 work/close 未确认完成前仍占冷启动名额、阻止同 key 重建,确认收尾后才开始冷却。首次偶发超时根因仍未知,排队和其他屏障仍可能无界;本版当前 Host/GUI 未部署未验证,用户仅本批接受官方实装隔离模块与 JS 套件替代验收,见 [0.21.3 发布说明](docs/release-0.21.3.md)。官方 bridge 隔离 fixture 同步迁移到当前公开 native 执行器及批调用契约,不代表生产执行器故障修复。以下为历史版本事实,不代表本版现场验收:
|
|
530
|
-
**v0.21.2** 的新版 DSH 会话 Controller 与 MCP 公开工具目录适配:任务发送按目标会话持有生命周期,受理不明时不跨通道重发;文件范围引用的剪贴板与降级文本保留行区间;MCP 初始化失败增加脱敏持久化诊断。当前 Web Host 已完成真实 CodeGraph 调用,但首次连接偶发超时根因尚未证实,不宣称已修复,见 [0.21.2 发布说明](docs/release-0.21.2.md)。保留以下历史版本能力与验收边界:
|
|
531
|
-
**v0.21.1** 修复缺失历史文件:按完整快照显示整文件删除,Keep 保留删除、Undo 安全恢复快照,预览只读且拒绝覆盖重新出现的文件;真实 GUI 验收缺口已明确保留,见 [0.21.1 发布说明](docs/release-0.21.1.md)。保留 **v0.21.0** 新增 XLSX 基础编辑与浏览器导出副本,原件不自动写回,高级应用通过官方 Host 打开;官方差异定位统一 BOM 与 LF/CRLF/混合行尾口径,并区分内容缺失和多处命中。定位修复不扩展 CRLF patch Undo 能力,目标官方记录 ↑/↓ 的真实点击验收仍保留缺口。保留 **v0.20.5** 跨 DSH 实例只读互通——桌面端与 Web 端各自运行独立宿主时,官方审查列表/详情与工作区只读接口改按持久化会话头的 cwd 解析,另一实例创建的会话也能只读打开官方差异栏,写入类接口仍要求本端活跃会话。保留 **v0.20.4** 统一两套差异栏外观——非官方记录栏角标由内部术语「侧车记录」改为「历史改动」,悬停说明 Keep 只标记已看过、不改写磁盘,Undo 逐项校验后写回,两者都不影响官方审查;官方元数据不可用时给出可读原因与重试按钮,不再静默降级;「会话没在当前端激活」由红色告警改为中性说明。保留 v0.20.3 修复官方差异全部无法定位时差异栏无提示、上下箭头静默禁用(显示「无可跳转」与失效原因,Keep 说明只标记已采纳、不改写磁盘,会话缺失等宿主错误改为可读提示)、v0.20.2 的 MCP 状态告警收敛与原生确认弹窗,以及 v0.20.1 的文件内差异展示、块级/文件级安全审查和跨分页批量操作。升级后重启 DSH 并刷新页面;持久化与回退边界见 [0.20.0 发布说明](docs/release-0.20.0.md);从 0.14.2 或更旧版本升级还须阅读
|
|
532
|
-
[0.14.3 数据迁移与回退说明](docs/release-0.14.3.md)。
|
|
568
|
+
profile 请替换为实际目标,不要把示例目录当成当前运行 profile。
|
|
569
|
+
|
|
570
|
+
> **升级须知**:近期版本的修复要点、验收缺口与回退边界见[更新日志](#更新日志);
|
|
571
|
+
> 从 0.14.2 或更旧版本升级还须阅读[0.14.3 数据迁移与回退说明](docs/release-0.14.3.md)。
|
|
533
572
|
|
|
534
573
|
```bash
|
|
535
574
|
# ① Git 安装(clone + prepare 构建;推荐打固定 tag)
|
|
536
|
-
dsh plugin --profile web add github:Lenonss/DSH_VsCodeMode#v0.
|
|
575
|
+
dsh plugin --profile web add github:Lenonss/DSH_VsCodeMode#v0.24.0
|
|
537
576
|
|
|
538
577
|
# ② npm 注册表(发布到 npm 后)
|
|
539
|
-
dsh plugin --profile web add dsh-vscode-mode@0.
|
|
578
|
+
dsh plugin --profile web add dsh-vscode-mode@0.24.0
|
|
540
579
|
|
|
541
580
|
# ③ GitHub Release tgz 直装(Release asset 可用后)
|
|
542
|
-
dsh plugin --profile web add https://github.com/Lenonss/DSH_VsCodeMode/releases/download/v0.
|
|
581
|
+
dsh plugin --profile web add https://github.com/Lenonss/DSH_VsCodeMode/releases/download/v0.24.0/dsh-vscode-mode-0.24.0.tgz
|
|
543
582
|
```
|
|
544
583
|
|
|
545
584
|
> **DSH 版本政策(0.17.0 起)**:六项 DSH peer 仍统一声明为 `*`,另以
|
|
@@ -666,15 +705,29 @@ v0.13.1 起插件不再自建录键界面(原独立「快捷键」设置页与
|
|
|
666
705
|
|
|
667
706
|
## 截图
|
|
668
707
|
|
|
669
|
-
|
|
708
|
+
> 以下截图取自 v0.23.5 的真实运行界面(DSH Web GUI + dsh-vscode-mode 右侧栏)。
|
|
709
|
+
|
|
710
|
+
### 同屏工作台
|
|
711
|
+
|
|
712
|
+

|
|
670
713
|
|
|
671
|
-
>
|
|
672
|
-
>
|
|
673
|
-
>
|
|
714
|
+
> AI 对话(中央)与 Monaco 文件编辑器(右侧官方 Sidebar)同屏;页签带差异角标,
|
|
715
|
+
> 底部原生 dock 汇总「差异 N 个文件」并提供 Keep All / Undo All。编辑器打开时
|
|
716
|
+
> 面板区可收起(`Ctrl+B` 切换,图标列常显),把宽度全部让给代码。
|
|
674
717
|
|
|
675
|
-
|
|
718
|
+
### 命令面板
|
|
676
719
|
|
|
677
|
-

|
|
721
|
+
|
|
722
|
+
> `Ctrl+Shift+P` 打开命令面板,命令按类别分组并支持模糊搜索;命令既可来自扩展清单
|
|
723
|
+
> 注册,也可由插件通过 `edrv.executeCommand` 编程调用。
|
|
724
|
+
|
|
725
|
+
### 差异审查
|
|
726
|
+
|
|
727
|
+

|
|
728
|
+
|
|
729
|
+
> 资源管理器展开工作区文件树(带差异角标),编辑器用行内红绿高亮展示 Agent 改动,
|
|
730
|
+
> 底部 dock 可逐文件切换、Keep / Undo,并提示当前记录还有几个待审文件。
|
|
678
731
|
|
|
679
732
|
## 开发
|
|
680
733
|
|
|
@@ -720,7 +773,7 @@ Desktop 应沿用当前 `dsh-app:` 应用上下文,不拼接固定 `localhost`
|
|
|
720
773
|
```
|
|
721
774
|
src/
|
|
722
775
|
├── index.ts Host 入口:name/inject/apply(薄装配,含兼容性报告启动日志)
|
|
723
|
-
├── shared/ ★ 双面契约(禁 node/react):types/rpc/compat/mcp
|
|
776
|
+
├── shared/ ★ 双面契约(禁 node/react):types/rpc/compat/mcp + remoteChannel(远程通道前缀)
|
|
724
777
|
├── compat.ts ★ Host 兼容层:外部插件探测、路由/重复装配护栏、兼容性报告
|
|
725
778
|
├── devForm.ts Host 开发形态管理:link:/junction 切换(RPC vscode.devForm*)
|
|
726
779
|
├── model.ts Host 纯域逻辑(可单测):normalize/markDecision/summary/批次/归档
|
|
@@ -875,11 +928,50 @@ Keep All / Undo All 却是亮的。修复:单文件 Keep / Undo 覆盖冲突
|
|
|
875
928
|
技能名必须 kebab-case + `dsh-vscodemode-` 前缀(下划线非法),frontmatter 用
|
|
876
929
|
官方字段名(见[特性 12](#12-插件自带技能组v033))。
|
|
877
930
|
|
|
931
|
+
**8. 远程访问时文件管理器报「DSH 拒绝了当前页面的访问」、编辑器报「Monaco loader 加载失败」**
|
|
932
|
+
|
|
933
|
+
根因:宿主的 `/edrv/*` 路由准入走 `connection.requestRejection()`,其中 **Host 围栏
|
|
934
|
+
(`isTrustedApiRequest`)先于任何登录态校验**——只放行 loopback / 监听 bind IP /
|
|
935
|
+
声明过的 `trustedHosts`。手机、平板或隧道域名访问时 `Host` 既不是 loopback 也不在
|
|
936
|
+
白名单,因此**登录态再有效也一律 403**(`401` 才是登录失效)。远程访问插件
|
|
937
|
+
(`@linxin666/dsh-remote-web-ui`)只把 `/api/`、`/sidebar/`、`/git/`、`/pet/` 改写到
|
|
938
|
+
它自己的 `/remote` 通道,`/edrv/` 不在其中,于是 RPC、Monaco 的 loader/AMD 模块/CSS/
|
|
939
|
+
字体/Worker、pdf.js、预览图片全部直连宿主被拒。
|
|
940
|
+
|
|
941
|
+
修复(**纯客户端**,宿主路由与鉴权零改动):远程通道在 `<head>` 解析期会
|
|
942
|
+
安装 `window.__DSH_REMOTE_CHANNEL_BOOT__` 座位对象;检测到它时,插件把所有内部地址
|
|
943
|
+
(`/edrv/rpc`、`/edrv/vendor/*`、`/edrv/assets/*`)**统一前缀成 `/remote/edrv/...`**,
|
|
944
|
+
由远程插件的服务端 catch-all 代理回环转发——该代理带同源设备 cookie 并换用进程内凭据
|
|
945
|
+
重发到 `127.0.0.1`,于是我们的 Host 围栏与登录校验**照常执行且通过**;任何子资源类型
|
|
946
|
+
(`<link>`、CSS `url()`、`new Worker`、ESM `import`)都覆盖,不依赖主线程 fetch 补丁。
|
|
947
|
+
本地页面、桌面 `dsh-app://`、未装远程插件时前缀为空,行为与之前完全一致。
|
|
948
|
+
|
|
949
|
+
- 未做也不建议:把所有 `/edrv/` 硬改成 `/api/edrv/`(补丁不覆盖 `link.href`/Worker/模块
|
|
950
|
+
import,会留下半成品);公开 vendor 路由;要求手工配 `trustedHosts`。
|
|
951
|
+
- 诊断:加载失败会先 HEAD 探测真实状态码再给结论——403 指「宿主拒绝了当前页面」、
|
|
952
|
+
401 指登录态失效、404 指资源缺失、0 指请求没到宿主;远程通道 403 若是设备未配对,
|
|
953
|
+
会直接提示「远程访问设备尚未配对」。
|
|
954
|
+
|
|
878
955
|
## 更新日志
|
|
879
956
|
|
|
880
957
|
完整变更见 [GitHub Releases](https://github.com/Lenonss/DSH_VsCodeMode/releases)。
|
|
881
|
-
近期关键版本:
|
|
882
958
|
|
|
959
|
+
| 版本 | 要点 |
|
|
960
|
+
| --- | --- |
|
|
961
|
+
| v0.24.0 | 经第三方远程访问插件时,文件管理器与 Monaco 恢复可用;加载失败提示按状态区分 |
|
|
962
|
+
| v0.23.5 | 同一文件不再算成两条差异;新建文件按整文件新增渲染 |
|
|
963
|
+
| v0.23.4 | 计划卡「查看全文」直通编辑器,不再闪一下再关 |
|
|
964
|
+
| v0.23.3 | 已删除文件的差异条目不再卡死;重启后不再成串「采集不完整」 |
|
|
965
|
+
| v0.23.2 | 桌面端 Keep 点了没反应的问题修复 |
|
|
966
|
+
| v0.23.1 | Keep All / Undo All 在待审超过一页时不再中止 |
|
|
967
|
+
| v0.23.0 | 快捷菜单:可拖动悬浮按钮 + 自定义菜单树 |
|
|
968
|
+
|
|
969
|
+
<details>
|
|
970
|
+
<summary>完整版本记录(v0.24.0 → v0.1.5x,点击展开)</summary>
|
|
971
|
+
|
|
972
|
+
|
|
973
|
+
- **v0.24.0**:修复经第三方远程访问插件(如 `@linxin666/dsh-remote-web-ui`)访问 DSH Web GUI 时,文件管理器报「DSH 拒绝了当前页面的访问」、编辑器报「Monaco loader 加载失败」。根因在宿主准入顺序:`connection.requestRejection()` 先用 `isTrustedApiRequest` 判 Host/Origin,不属于回环、监听地址或 `trustedHosts` 就**直接 403**,根本不看登录态(401 才是认证失败),而本插件的 `/edrv/rpc` 与 `/edrv/vendor/**` 都不在远程插件的改写白名单里,于是 RPC、Monaco 的脚本/CSS/字体/Worker、pdf.js 模块 import 与角标图片全部直连宿主被拒。现按远程通道选路径前缀:`window.__DSH_REMOTE_CHANNEL_BOOT__` 存在(远程插件在 `<head>` 解析期安装的座位对象)时,所有插件内部路径改挂其已接管的 `/remote` catch-all(`/remote/edrv/...`),本地与桌面入口保持 `/edrv/...` 原样。新增 `src/shared/remoteChannel.ts`(`channelPrefix` / `transportPath` / `transportUrl`,仍经 `appUrl` 继承应用基址与 `dsh-app:`),RPC、二进制预览、Monaco 基址、pdf.js 基址与角标图片统一走它;**服务端零改动**,不新增路由、不取消鉴权、不读也不写任何凭据,`/remote` 门禁仍要求已配对设备。另新增 `src/client/loadFailure.ts`:加载失败先 HEAD 探测真实状态,403(Host 围栏)/401(登录失效)/404(资源或路由缺失)/0(请求未到达宿主)分别给不同提示,且只带 pathname 与状态码;设备未配对(403 `code:'unpaired'`)直接提示去配对,不再把所有 Monaco 失败都说成「检查资源是否完整」。验证:typecheck 0 error;全量 284 文件、3691 通过 + 22 跳过;`node --test tests/nativeOpen.test.mjs` 9/9;build 四 bundle 通过;本机 GUI 全链 200 并确认无 cookie 仍 401;远程通道用本地回环代理复刻转发语义后,138/138 请求落 `/remote/edrv/…`、目录/读/写/保存与 Monaco+Worker 全部通;**真机 + 真插件的配对门禁与 TLS 未验收(缺口保留)**。见 [0.24.0 发布说明](docs/release-0.24.0.md)。
|
|
974
|
+
- **v0.23.5**:修复差异栏把同一文件算成两条(差异文件数偏大)。待审条目存的是写入时的相对路径,官方导航用绝对身份,而 `mergedPage()` 与 `diffSummary` 的去重都只按 path 建覆盖集,相对路径的待审行压不掉绝对身份的官方行,于是同一文件同时留下待审行与官方汇总行;现两侧覆盖集都补入条目身份(与官方 identity 同源)。另修复本会话新建的文件被渲染成一堆修改块:累计基线保留「最早内容」,新建文件首次采集时磁盘已有会话自己的中间产物,基线因此非空,「新增 516 行」被切成若干 `-`/`+` 混合块,与官方整文件新增(`before=false`、`oldLines=0`)口径相反;现按每个文件在该会话内最早的官方记录判定整文件新增,命中时待审侧基线置空,列表与详情只出一块全加差异、增删计数等于整文件行数,`addedFiles()` 查询失败则回退旧口径。验证:typecheck 0 error;全量单测通过;`npm run build` 通过;本版未做 GUI 点按验收(缺口保留)。见 [0.23.5 发布说明](docs/release-0.23.5.md)。
|
|
883
975
|
- **v0.23.4**:修复桌面端点计划卡「查看全文」会先闪开一页官方计划预览、随即自动关闭。根因:官方卡片走 `ctx.sidebarRight.openResource(planAddress(callId))`,而本插件以 extension 优先级认领了 `dsh-resource://plan/**` 与 `dsh-resource://plan-review/**`,于是侧栏先按本插件类型建出一个页签(正文「正在打开计划预览…」),挂载后才把计划转进「文件编辑」、再把这个页签关掉——用户看到的就是这次建而即关。现由新增 `src/client/planDirect.ts` 在装配期包装 `sidebarRight.openResource`:只接管「2 段计划地址 + 会话为在屏会话」,正文依次取回顾卡片的 `params.planReview`、插件侧地址→正文缓存、可选 `resources.source()` 资源流(上限 1.5s),拿到正文后经 `requestOpen(..., { preview: true })` 直通本插件编辑器的只读计划页签,不再创建侧栏页签;非计划地址、跨会话与 subagent 5 段地址、正文不可得、编辑器 5s 未回执、以及服务对象只读导致包装赋值失败,一律回落原生 `openResource`,原「认领 + 挂载后转移」链路保留为后备。`openReceipt` 新增可选 `timeoutMs`,`planState` 新增有界(64 条)地址→正文缓存并由 live `exit_plan_mode` 写入。验证:typecheck 0 error;`tests/planDirect.test.ts`(新增 9 例)、`tests/planBridge.test.ts`(13)、`tests/planState.test.ts`(10)、`tests/openReceipt.test.ts`(9)四套 41/41;`npm run build` 双 bundle 通过(含客户端产物完整性校验);浏览器确认新 bundle 已加载且 Console 无「计划直通装配失败」;GUI 点按由用户在本机 Web 端手动复验后发布。见 [发布说明](docs/release-0.23.4.md)。
|
|
884
976
|
- **v0.23.3**:修复 issue #13(已删除文件的差异条目把人卡死)与 #12(重启后成串「采集不完整」)。①文件在磁盘上被删掉时,客户端申请整文件删除预览被「已有官方审查记录」拒绝,而拒绝只是一条普通 `Error`,于是落到通用加载失败分支——「文件加载失败:…」+ 进度钉在 0%、重试同错、标签页关不掉;`edrv.review.detail` 还把 Undo 不可用解释成「缺少可验证的原始字节」,而真实原因是文件已不在。现缺失文件预览的可预期拒绝带稳定码(`official-covered` / `official-decided` / `no-records` / `no-evidence` / `too-large`),客户端据此显示「文件已在磁盘删除(· 有官方待审改动)」终态:标题 + 原因 + 重试 / 关闭标签页,不再画 0% 进度条;官方待审记录在磁盘已删除时给出「Keep 按删除结案、Undo 需要读写该文件」的准确原因(Keep 语义不变,仍只写共享审查库),记录都已结案时提示可直接关闭;`!review` 的磁盘状态抖动改为最多重读 2 次后给终态,消除缺失↔重现的无限递归。v0.22.0 起 `hasOfficial()` 已用 `typeof path !== 'string'` 守卫堵掉把不透明 FsTarget 绑进 SQL 导致的 `Unknown named parameter 'targetKey'`,本版不再复现。②官方 `workspace/changes` 的 summary 只存在宿主内存里,插件启动补采原先无条件把历史事件全部入队,重启后每一轮都必然抛「summary 已失效或尚不可用」并写成不可修复的 `gap`(面板成串「轮次 N 采集不完整」);现补采先 `summary()` 探测再入队,失效事件只记一条汇总日志。验证:typecheck 与基线同为 37 个既有错误(`fflate/browser` 依赖缺失)、零新增;定向单测 111/111(含新增 `tests/deletedFileReview.test.ts` 5 例与 `tests/officialBackfill.test.ts` 2 例)、EditorView 相关 82/82;`npm run build` 四个 bundle 通过。见 [发布说明](docs/release-0.23.3.md)。
|
|
885
977
|
- **v0.23.2**:修复 Keep 在非活跃端(桌面端)点了没反应,两处成因。①`edrv.review.decide` 原先一律要求本端活跃会话,而能力位只按审查库推导,会话在另一实例时按钮亮着、点击后抛错被兜底成 HTTP 500。现按写入副作用区分:官方记录 Keep 只写共享审查库(`BEGIN IMMEDIATE` + 幂等键 + 版本 CAS),冷端放行;官方 Undo(校验证据并写回源文件)与待审投影条目(本机 JSON 无跨进程锁)仍限活跃端,返回可读跨端原因而非 500;详情新增 `capability.live`,冷端禁用 Undo 并说明、Keep 提示补「写入共享审查库,仍可执行」。②已结算待审投影的 `capability.keep` 恒为假,却因排在 `items[0]`、同路径官方待审行被历史过滤,把官方记录挤出差异栏(表现为「待审 0」+Keep 禁用+点击无反应);现 `pendingPageOf()` 剔除已结算投影,官方记录重新成为审查目标。另详情未加载时点 Keep 不再静默失败;打开文件时若某条官方记录的改动已全部不在当前文件中(无可定位差异且缓冲区干净),自动按 Keep 结案(只标记不写盘),差异栏不再显示「本记录 N 处改动均已不在当前文件中」;官方元数据首次载入期间差异栏显示 `—` 而非按历史记录报数,重启瞬间不再闪出几十条假待审。验证:typecheck 0 error、目标单测 57/57、build 通过、真实审查库探针确认首条回到官方记录且 `capability={keep:true,undo:true,live:true}`;桌面端 GUI 点按验收因重启后恢复的是另一个会话未完成,缺口保留。发布不自动部署,升级后重启 DSH 并刷新页面。见 [发布说明](docs/release-0.23.2.md)。
|
|
@@ -1057,8 +1149,10 @@ Keep All / Undo All 却是亮的。修复:单文件 Keep / Undo 覆盖冲突
|
|
|
1057
1149
|
多选比较 / 区间 / Stop on copy / Include merged revisions / Statistics)、
|
|
1058
1150
|
并排差异(基线 / 版本间 / 与工作副本)、诊断日志查看器。
|
|
1059
1151
|
- **v0.4.x**:LSP 与 Monaco 系列修复(见[常见问题](#常见问题));外部改动自动
|
|
1060
|
-
|
|
1152
|
+
同步(v0.4.4)。
|
|
1061
1153
|
- **v0.3.x**:命令栏(v0.2.0)→ 代码片段 / 快捷引用(v0.3.0)→ 插件技能组
|
|
1062
1154
|
(v0.3.3)。
|
|
1063
1155
|
- **v0.1.5x**:官方侧边栏形态(v0.1.60 推荐)、PDF 浏览编辑(v0.1.55)、
|
|
1064
1156
|
系统集成(v0.1.53)、规则管理(v0.1.49 / 50)。
|
|
1157
|
+
|
|
1158
|
+
</details>
|
package/lib/client.js
CHANGED
|
@@ -3040,6 +3040,61 @@ window.__ModuleLoader__.load({
|
|
|
3040
3040
|
return new URL(path.slice(1), root).href;
|
|
3041
3041
|
}
|
|
3042
3042
|
//#endregion
|
|
3043
|
+
//#region src/shared/remoteChannel.ts
|
|
3044
|
+
/**
|
|
3045
|
+
* 远程访问通道适配:插件内部路径 → 远程传输可达路径。
|
|
3046
|
+
*
|
|
3047
|
+
* 背景:宿主 connection 插件对 Host 不是 loopback / bind 地址 / trustedHosts 的请求一律回 403
|
|
3048
|
+
* (Host 围栏先于任何 cookie 校验),因此 /edrv/rpc 与 /edrv/vendor/** 在局域网 IP 或隧道域名
|
|
3049
|
+
* 页面上必然被拒。第三方远程访问插件(@linxin666/dsh-remote-web-ui)提供 /remote/<内部路径>
|
|
3050
|
+
* 的 catch-all 代理:校验配对设备后回环重发到本进程,本插件自身的准入照旧执行。
|
|
3051
|
+
*
|
|
3052
|
+
* 该插件在 <head> 首部内联一段 classic script(解析期同步执行,早于任何 module script),并在
|
|
3053
|
+
* window 上安装 seat 对象作为「本页已接入通道」的唯一标记。本模块据此选前缀:
|
|
3054
|
+
* 有标记 ⇒ '/remote' + 原路径;无标记 ⇒ 原路径(本机、桌面 dsh-app:、未装该插件均不受影响)。
|
|
3055
|
+
* 只决定 URL 前缀,不读取、不写入、不转发任何 cookie 或凭据。
|
|
3056
|
+
*
|
|
3057
|
+
* Purity rule: no node/react imports(与 appUrl.ts 一致)。
|
|
3058
|
+
* @author ddj 2026年11月02号
|
|
3059
|
+
*/
|
|
3060
|
+
/** 远程访问插件在解析期安装的通道 seat 全局名(其 REMOTE_CHANNEL_BOOT_GLOBAL)。 */
|
|
3061
|
+
const CHANNEL_SEAT = "__DSH_REMOTE_CHANNEL_BOOT__";
|
|
3062
|
+
/** 远程访问插件接管的前缀:/remote/<内部路径> 由服务端回环转发。 */
|
|
3063
|
+
const CHANNEL_PREFIX = "/remote";
|
|
3064
|
+
/**
|
|
3065
|
+
* 当前页面的通道前缀。
|
|
3066
|
+
* @author ddj 2026年11月02号
|
|
3067
|
+
* @returns 本页已接入远程通道时为 '/remote',否则空串(保持既有本地路径)。
|
|
3068
|
+
*/
|
|
3069
|
+
function channelPrefix() {
|
|
3070
|
+
if (typeof window === "undefined") return "";
|
|
3071
|
+
try {
|
|
3072
|
+
const seat = window[CHANNEL_SEAT];
|
|
3073
|
+
return seat && typeof seat === "object" ? CHANNEL_PREFIX : "";
|
|
3074
|
+
} catch (e) {
|
|
3075
|
+
return "";
|
|
3076
|
+
}
|
|
3077
|
+
}
|
|
3078
|
+
/**
|
|
3079
|
+
* 给插件内部路径加通道前缀。
|
|
3080
|
+
* @author ddj 2026年11月02号
|
|
3081
|
+
* @param path 以 '/' 开头的插件内部路径(合法性由 {@link transportUrl} 内的 appUrl 兜底校验)
|
|
3082
|
+
* @returns 带通道前缀的路径;本机页面原样返回
|
|
3083
|
+
*/
|
|
3084
|
+
function transportPath(path) {
|
|
3085
|
+
return channelPrefix() + path;
|
|
3086
|
+
}
|
|
3087
|
+
/**
|
|
3088
|
+
* 把插件内部路径解析为当前页面可请求的地址(继承通道前缀、反向代理前缀与桌面协议)。
|
|
3089
|
+
* @author ddj 2026年11月02号
|
|
3090
|
+
* @param path 以 '/' 开头的插件内部路径
|
|
3091
|
+
* @param base 测试用显式 document base;缺省同 appUrl(document.baseURI → location.href)
|
|
3092
|
+
* @returns 应用地址;无浏览器环境时返回原根路径
|
|
3093
|
+
*/
|
|
3094
|
+
function transportUrl(path, base) {
|
|
3095
|
+
return appUrl(transportPath(path), base);
|
|
3096
|
+
}
|
|
3097
|
+
//#endregion
|
|
3043
3098
|
//#region src/shared/rpc.ts
|
|
3044
3099
|
/** webServer 精确路由。 */
|
|
3045
3100
|
const RPC_PATH = "/edrv/rpc";
|
|
@@ -3127,7 +3182,7 @@ window.__ModuleLoader__.load({
|
|
|
3127
3182
|
*/
|
|
3128
3183
|
async function tryBinaryRead(args) {
|
|
3129
3184
|
try {
|
|
3130
|
-
const res = await fetch(
|
|
3185
|
+
const res = await fetch(transportUrl(RPC_PATH), {
|
|
3131
3186
|
method: "POST",
|
|
3132
3187
|
headers: { "content-type": "application/json" },
|
|
3133
3188
|
body: JSON.stringify({
|
|
@@ -3271,7 +3326,7 @@ window.__ModuleLoader__.load({
|
|
|
3271
3326
|
}
|
|
3272
3327
|
/** @private @author ddj 2026年10月10号 @param method Typed method. @param args Request. @param signal Fetch lifetime. @returns Validated authenticated business response. @throws Transport/format errors. */
|
|
3273
3328
|
async function rpcFetch(method, args, signal) {
|
|
3274
|
-
const res = await fetch(
|
|
3329
|
+
const res = await fetch(transportUrl(RPC_PATH), {
|
|
3275
3330
|
method: "POST",
|
|
3276
3331
|
credentials: "same-origin",
|
|
3277
3332
|
headers: { "content-type": "application/json" },
|
|
@@ -3281,16 +3336,60 @@ window.__ModuleLoader__.load({
|
|
|
3281
3336
|
}),
|
|
3282
3337
|
signal
|
|
3283
3338
|
});
|
|
3284
|
-
if (!res.ok)
|
|
3285
|
-
const message = res.status === 401 ? "DSH 登录已失效,请重新打开已登录的应用页面" : res.status === 403 ? "DSH 拒绝了当前页面的访问" : res.status === 413 ? "请求超过支持的文件大小" : res.status === 503 ? "DSH 认证服务尚未就绪" : "DSH 请求失败(HTTP " + res.status + ")";
|
|
3286
|
-
throw new Error(message);
|
|
3287
|
-
}
|
|
3339
|
+
if (!res.ok) throw new Error(await failureMessage(res));
|
|
3288
3340
|
if (!/^application\/json(?:\s*;|\s*$)/i.test(res.headers.get("content-type") ?? "")) throw new Error("DSH 返回了非 JSON 响应,请检查应用地址和代理配置");
|
|
3289
3341
|
const value = await res.json();
|
|
3290
3342
|
if (!value || typeof value !== "object" || typeof value.ok !== "boolean") throw new Error("DSH RPC 响应格式不正确");
|
|
3291
3343
|
return value;
|
|
3292
3344
|
}
|
|
3293
3345
|
/**
|
|
3346
|
+
* 非 2xx 响应 → 可读失败原因:403 再区分「远程设备未配对」与「Host 围栏拒绝」。
|
|
3347
|
+
* @author ddj 2026年11月02号
|
|
3348
|
+
* @param res 失败响应
|
|
3349
|
+
* @returns 用户可读原因
|
|
3350
|
+
*/
|
|
3351
|
+
async function failureMessage(res) {
|
|
3352
|
+
if (res.status === 403) {
|
|
3353
|
+
if (await unpairedDenied(res)) return "远程访问设备尚未配对:请在远程访问面板完成配对后重试(HTTP 403)";
|
|
3354
|
+
return "DSH 拒绝了当前页面的访问(HTTP 403,Host 校验未通过)" + channelNote();
|
|
3355
|
+
}
|
|
3356
|
+
if (res.status === 401) return "DSH 登录已失效,请重新打开已登录的应用页面";
|
|
3357
|
+
if (res.status === 404) return "插件路由不存在(HTTP 404),请确认 dsh-vscode-mode 与宿主版本匹配";
|
|
3358
|
+
if (res.status === 413) return "请求超过支持的文件大小";
|
|
3359
|
+
if (res.status === 503) return "DSH 认证服务尚未就绪";
|
|
3360
|
+
return "DSH 请求失败(HTTP " + res.status + ")";
|
|
3361
|
+
}
|
|
3362
|
+
/**
|
|
3363
|
+
* 403 是否为远程访问通道的「未配对」拒绝(远程插件以 `{result:{ok:false,error:{code}}}` 回)。
|
|
3364
|
+
* @author ddj 2026年11月02号
|
|
3365
|
+
* @param res 403 响应
|
|
3366
|
+
* @returns 是否为未配对拒绝
|
|
3367
|
+
*/
|
|
3368
|
+
async function unpairedDenied(res) {
|
|
3369
|
+
try {
|
|
3370
|
+
const body = await res.clone().json();
|
|
3371
|
+
return (body?.result?.error?.code ?? body?.error?.code) === "unpaired";
|
|
3372
|
+
} catch (e) {
|
|
3373
|
+
return false;
|
|
3374
|
+
}
|
|
3375
|
+
}
|
|
3376
|
+
/**
|
|
3377
|
+
* 网络来源页面却未接入远程通道时的补充提示(本机页面不追加)。
|
|
3378
|
+
* @author ddj 2026年11月02号
|
|
3379
|
+
* @returns 提示后缀;无需提示时为空串
|
|
3380
|
+
*/
|
|
3381
|
+
function channelNote() {
|
|
3382
|
+
if (channelPrefix() !== "") return "";
|
|
3383
|
+
try {
|
|
3384
|
+
if (typeof location === "undefined") return "";
|
|
3385
|
+
const host = location.hostname;
|
|
3386
|
+
if (host === "localhost" || host === "::1" || host === "[::1]" || /^127(\.\d{1,3}){3}$/.test(host)) return "";
|
|
3387
|
+
return ";本页未接入远程访问通道(远程访问插件未安装或未完成配对)";
|
|
3388
|
+
} catch (e) {
|
|
3389
|
+
return "";
|
|
3390
|
+
}
|
|
3391
|
+
}
|
|
3392
|
+
/**
|
|
3294
3393
|
* 诊断日志:开关关闭时直接返回(零 RPC 零落盘);开启时走 host edrv.debug 落盘。
|
|
3295
3394
|
* @author ddj 2026年08月26号 / 2026年09月17号
|
|
3296
3395
|
* @param sessionId 会话 id
|
|
@@ -4117,6 +4216,7 @@ window.__ModuleLoader__.load({
|
|
|
4117
4216
|
if (!item.id.startsWith("pending:")) continue;
|
|
4118
4217
|
const path = item.currentPath || item.path;
|
|
4119
4218
|
covered.add(diffPathKey(path));
|
|
4219
|
+
covered.add(diffPathKey(item.id.slice(8)));
|
|
4120
4220
|
rows.push({
|
|
4121
4221
|
path,
|
|
4122
4222
|
label: item.display || path,
|
|
@@ -5053,13 +5153,95 @@ window.__ModuleLoader__.load({
|
|
|
5053
5153
|
return scheme === "light" || scheme === "dark" ? scheme : void 0;
|
|
5054
5154
|
}
|
|
5055
5155
|
//#endregion
|
|
5156
|
+
//#region src/client/loadFailure.ts
|
|
5157
|
+
/**
|
|
5158
|
+
* dsh-vscode-mode client — 加载失败诊断(把「加载失败」拆成可定位的四类原因)。
|
|
5159
|
+
*
|
|
5160
|
+
* 为什么需要:宿主对非 loopback/bind/trustedHosts 的 Host 一律回 403(Host 围栏),
|
|
5161
|
+
* 认证失效回 401,路由或资源缺失回 404,另有纯网络失败。此前 Monaco/pdf.js 的失败面板
|
|
5162
|
+
* 一律提示「检查资源是否完整」,远程访问时会把 403 误报成资源缺失,误导排查方向。
|
|
5163
|
+
*
|
|
5164
|
+
* 文案只输出 pathname 与状态码,不含 origin、查询串、cookie 或任何凭据。
|
|
5165
|
+
* @author ddj 2026年11月02号
|
|
5166
|
+
*/
|
|
5167
|
+
/** 状态码 0:请求未完成(网络错误 / 被拦截 / 离线)。 */
|
|
5168
|
+
const NETWORK_FAILED = 0;
|
|
5169
|
+
/**
|
|
5170
|
+
* 探测资源地址的真实响应状态。
|
|
5171
|
+
* @author ddj 2026年11月02号
|
|
5172
|
+
* @param url 已解析的绝对或根路径地址
|
|
5173
|
+
* @returns HTTP 状态码;请求未完成时返回 0
|
|
5174
|
+
*/
|
|
5175
|
+
async function probeStatus(url) {
|
|
5176
|
+
try {
|
|
5177
|
+
return (await fetch(url, {
|
|
5178
|
+
method: "HEAD",
|
|
5179
|
+
credentials: "same-origin"
|
|
5180
|
+
})).status;
|
|
5181
|
+
} catch (e) {
|
|
5182
|
+
return NETWORK_FAILED;
|
|
5183
|
+
}
|
|
5184
|
+
}
|
|
5185
|
+
/**
|
|
5186
|
+
* 取地址的 pathname(只用于诊断文案,避免暴露 origin 与查询串)。
|
|
5187
|
+
* @author ddj 2026年11月02号
|
|
5188
|
+
* @param url 绝对或根路径地址
|
|
5189
|
+
* @returns pathname;无法解析时原样返回
|
|
5190
|
+
*/
|
|
5191
|
+
function pathOf$1(url) {
|
|
5192
|
+
try {
|
|
5193
|
+
return new URL(url, "http://localhost").pathname;
|
|
5194
|
+
} catch (e) {
|
|
5195
|
+
return url;
|
|
5196
|
+
}
|
|
5197
|
+
}
|
|
5198
|
+
/**
|
|
5199
|
+
* 状态码 → 可操作的原因说明(四类互不相同)。
|
|
5200
|
+
* @author ddj 2026年11月02号
|
|
5201
|
+
* @param status HTTP 状态码,0 表示请求未完成
|
|
5202
|
+
* @returns 原因说明
|
|
5203
|
+
*/
|
|
5204
|
+
function statusHint(status) {
|
|
5205
|
+
if (status === NETWORK_FAILED) return "请求未到达宿主(网络不可达、被浏览器或代理拦截、或宿主已停止)";
|
|
5206
|
+
if (status === 403) return "宿主拒绝了当前页面(Host/Origin 校验未通过;远程访问需经远程访问插件的通道)";
|
|
5207
|
+
if (status === 401) return "宿主登录态失效,请重新打开已登录的应用页面";
|
|
5208
|
+
if (status === 404) return "路由或资源不存在(插件资源缺失或插件版本与宿主不匹配)";
|
|
5209
|
+
return "宿主返回了非预期状态";
|
|
5210
|
+
}
|
|
5211
|
+
/**
|
|
5212
|
+
* 组装加载失败文案:标签 + 资源路径 + 状态 + 原因。
|
|
5213
|
+
* @author ddj 2026年11月02号
|
|
5214
|
+
* @param label 失败对象(如 'Monaco loader 加载失败')
|
|
5215
|
+
* @param url 加载地址
|
|
5216
|
+
* @param status 探测到的状态码(0=网络错误)
|
|
5217
|
+
* @returns 用户可读的诊断文案
|
|
5218
|
+
*/
|
|
5219
|
+
function loadFailureText(label, url, status) {
|
|
5220
|
+
const outcome = status === NETWORK_FAILED ? "请求未完成" : "返回 HTTP " + status;
|
|
5221
|
+
return label + ":" + pathOf$1(url) + " " + outcome + ";" + statusHint(status);
|
|
5222
|
+
}
|
|
5223
|
+
/**
|
|
5224
|
+
* Monaco 失败面板提示:按错误内容给出对应排查方向(不再一律提示「检查资源是否完整」)。
|
|
5225
|
+
* @author ddj 2026年11月02号
|
|
5226
|
+
* @param message 编辑器记录的失败原因
|
|
5227
|
+
* @returns 排查建议
|
|
5228
|
+
*/
|
|
5229
|
+
function monacoHint(message) {
|
|
5230
|
+
const text = String(message ?? "");
|
|
5231
|
+
if (/403/.test(text)) return "宿主拒绝了本次请求:远程访问需经远程访问插件的通道(本页已自动接入);本机访问请用 127.0.0.1 或 localhost 打开。";
|
|
5232
|
+
if (/401/.test(text)) return "宿主登录态失效:请重新打开已登录的应用页面后再试。";
|
|
5233
|
+
if (/404/.test(text)) return "Monaco 静态资源未找到:插件包 assets/vendor/monaco 可能不完整,或插件版本与宿主不匹配。";
|
|
5234
|
+
if (/请求未完成|Failed to fetch|NetworkError/i.test(text)) return "请求未能到达宿主:请检查网络、代理与宿主进程状态。";
|
|
5235
|
+
return "请展开下方详情,并在浏览器控制台确认失败请求的地址与状态码。";
|
|
5236
|
+
}
|
|
5237
|
+
//#endregion
|
|
5056
5238
|
//#region src/client/monaco/loader.ts
|
|
5057
5239
|
/**
|
|
5058
5240
|
* dsh-vscode-mode client — Monaco 加载与语言映射(AMD 构建,离线随包分发)。
|
|
5059
5241
|
* 迁移自原 src/client/index.ts 的 MONACO_BASE/LANG_BY_EXT/langOf/loadMonaco,语义不改。
|
|
5060
5242
|
* 作者 ddj 2026-08-20
|
|
5061
5243
|
*/
|
|
5062
|
-
const MONACO_BASE =
|
|
5244
|
+
const MONACO_BASE = transportUrl("/edrv/vendor/monaco/vs");
|
|
5063
5245
|
let monacoPromise = null;
|
|
5064
5246
|
let monacoStage = {
|
|
5065
5247
|
phase: "idle",
|
|
@@ -5273,9 +5455,10 @@ window.__ModuleLoader__.load({
|
|
|
5273
5455
|
s.src = MONACO_BASE + "/loader.js";
|
|
5274
5456
|
s.dataset.edrvMonacoLoader = "1";
|
|
5275
5457
|
s.onload = boot;
|
|
5276
|
-
s.onerror = (
|
|
5277
|
-
const
|
|
5278
|
-
|
|
5458
|
+
s.onerror = async () => {
|
|
5459
|
+
const loaderUrl = MONACO_BASE + "/loader.js";
|
|
5460
|
+
const status = await probeStatus(loaderUrl);
|
|
5461
|
+
fail(new Error(loadFailureText("Monaco loader 加载失败", loaderUrl, status)));
|
|
5279
5462
|
};
|
|
5280
5463
|
hideNodeGlobals();
|
|
5281
5464
|
document.head.appendChild(s);
|
|
@@ -376672,8 +376855,8 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
376672
376855
|
* 用 script 注入而非打包内 import():客户端包是 CJS,bundler 会改写动态 import 破坏 URL 语义。
|
|
376673
376856
|
* 作者 ddj 2026-09-22
|
|
376674
376857
|
*/
|
|
376675
|
-
/** vendor
|
|
376676
|
-
const PDFJS_BASE =
|
|
376858
|
+
/** vendor 根,保留官方桌面协议、反向代理前缀与远程访问通道前缀。 */
|
|
376859
|
+
const PDFJS_BASE = transportUrl("/edrv/vendor/pdfjs");
|
|
376677
376860
|
/** pdf.js Worker 地址(GlobalWorkerOptions.workerSrc)。 */
|
|
376678
376861
|
const PDFJS_WORKER_SRC = PDFJS_BASE + "/build/pdf.worker.mjs";
|
|
376679
376862
|
/** CJK 字符映射目录(中文 PDF 渲染必需,尾斜杠固定)。 */
|
|
@@ -376730,7 +376913,11 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
376730
376913
|
s.textContent = "import * as lib from \"" + PDFJS_BASE + "/build/pdf.mjs\";\nimport * as viewer from \"" + PDFJS_BASE + "/web/pdf_viewer.mjs\";\nwindow.__edrvPdfjs = { lib, viewer };\ndocument.querySelector(\"script[data-edrv-pdfjs-loader]\")?.dispatchEvent(new Event(\"edrv-pdfjs-ready\"));";
|
|
376731
376914
|
s.dataset.edrvPdfjsLoader = "1";
|
|
376732
376915
|
s.onload = boot;
|
|
376733
|
-
s.onerror = () =>
|
|
376916
|
+
s.onerror = async () => {
|
|
376917
|
+
const moduleUrl = PDFJS_BASE + "/build/pdf.mjs";
|
|
376918
|
+
const status = await probeStatus(moduleUrl);
|
|
376919
|
+
fail(new Error(loadFailureText("pdf.js 模块加载失败", moduleUrl, status)));
|
|
376920
|
+
};
|
|
376734
376921
|
document.head.appendChild(s);
|
|
376735
376922
|
});
|
|
376736
376923
|
return pdfjsPromise;
|
|
@@ -398686,7 +398873,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
398686
398873
|
loadPage: loadTextPage
|
|
398687
398874
|
});
|
|
398688
398875
|
else if (!monaco && !monacoErr) body = loadingBody(loadStage.message, loadStage.progress);
|
|
398689
|
-
else if (monacoErr) body = react$1.default.createElement("div", { className: "edrv-empty" }, react$1.default.createElement("div", null, "Monaco 编辑器加载失败:" + String(monacoErr)), react$1.default.createElement("div", { style: { fontSize: 11 } },
|
|
398876
|
+
else if (monacoErr) body = react$1.default.createElement("div", { className: "edrv-empty" }, react$1.default.createElement("div", null, "Monaco 编辑器加载失败:" + String(monacoErr)), react$1.default.createElement("div", { style: { fontSize: 11 } }, monacoHint(String(monacoErr))), react$1.default.createElement("button", {
|
|
398690
398877
|
className: "edrv-pill edrv-pill-ghost",
|
|
398691
398878
|
onClick: () => {
|
|
398692
398879
|
setMonacoErr(null);
|
|
@@ -399539,7 +399726,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
399539
399726
|
cursor: "pointer"
|
|
399540
399727
|
}
|
|
399541
399728
|
}, react$1.default.createElement("img", {
|
|
399542
|
-
src:
|
|
399729
|
+
src: transportUrl("/edrv/assets/compare-select.png"),
|
|
399543
399730
|
alt: "差异",
|
|
399544
399731
|
style: {
|
|
399545
399732
|
width: 22,
|
package/lib/client.js.map
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
[diffend] Oversized file quarantined before diffing.
|
|
2
2
|
name: package/lib/client.js.map
|
|
3
|
-
size:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 35705679 bytes
|
|
4
|
+
sha256: 99ccafcfabf9448fefe75878b567b71a795cb2d17af9ac3077189a81c6a0eb09
|