dsh-remote-vs 0.0.0-stage → 0.8.3
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/LICENSE +21 -0
- package/README.en.md +385 -0
- package/README.md +347 -2
- package/cordis.patch.yml +259 -0
- package/icon.svg +7 -0
- package/lib/client.js +62602 -0
- package/lib/index.js +4287 -0
- package/lib/p2-bridge-refs.js +10 -0
- package/lib/p2-bridge.js +16 -0
- package/lib/p2-router-fs.js +252 -0
- package/lib/p2-router-refs.js +466 -0
- package/lib/p2-router-spill.js +62 -0
- package/lib/p2-router-subprocess.js +64 -0
- package/lib/p2-shell-bash.js +24 -0
- package/lib/ssh-proc-arI5lm4W.js +632 -0
- package/lib/types/changes/recorder.d.ts +240 -0
- package/lib/types/changes/status.d.ts +201 -0
- package/lib/types/changes/text-diff.d.ts +65 -0
- package/lib/types/client/CodeEditor.d.ts +125 -0
- package/lib/types/client/Dialog.d.ts +14 -0
- package/lib/types/client/DirectoryFlow.d.ts +30 -0
- package/lib/types/client/EditorPane.d.ts +30 -0
- package/lib/types/client/HostsView.d.ts +10 -0
- package/lib/types/client/NativeExplorer.d.ts +39 -0
- package/lib/types/client/RemoteDirectoryPicker.d.ts +16 -0
- package/lib/types/client/RemoteEditorView.d.ts +20 -0
- package/lib/types/client/RemoteExplorer.d.ts +18 -0
- package/lib/types/client/RemoteRoot.d.ts +16 -0
- package/lib/types/client/SearchView.d.ts +14 -0
- package/lib/types/client/SettingsHosts.d.ts +15 -0
- package/lib/types/client/TerminalView.d.ts +16 -0
- package/lib/types/client/WorkspaceWizard.d.ts +16 -0
- package/lib/types/client/WorkspacesView.d.ts +14 -0
- package/lib/types/client/XTerm.d.ts +15 -0
- package/lib/types/client/api.d.ts +162 -0
- package/lib/types/client/changes/ChangesDock.d.ts +35 -0
- package/lib/types/client/changes/model.d.ts +36 -0
- package/lib/types/client/changes/undo-affordance.d.ts +48 -0
- package/lib/types/client/changes/undo-context.d.ts +25 -0
- package/lib/types/client/composer.d.ts +165 -0
- package/lib/types/client/i18n.d.ts +17 -0
- package/lib/types/client/index.d.ts +14 -0
- package/lib/types/client/remote-file-open-target.d.ts +247 -0
- package/lib/types/client/remote-file-open.d.ts +35 -0
- package/lib/types/client/reveal.d.ts +15 -0
- package/lib/types/client/scm/DiffView.d.ts +24 -0
- package/lib/types/client/scm/HistoryPanel.d.ts +12 -0
- package/lib/types/client/scm/RepoPicker.d.ts +24 -0
- package/lib/types/client/scm/ScmPanel.d.ts +15 -0
- package/lib/types/client/scm/actions.d.ts +170 -0
- package/lib/types/client/scm/diff-model.d.ts +29 -0
- package/lib/types/client/scm/stage-queue.d.ts +99 -0
- package/lib/types/client/scm/status-map.d.ts +157 -0
- package/lib/types/client/scm/untracked-dirs.d.ts +72 -0
- package/lib/types/client/selection-popup.d.ts +61 -0
- package/lib/types/client/store.d.ts +437 -0
- package/lib/types/client/theme.d.ts +15 -0
- package/lib/types/client/ui.d.ts +46 -0
- package/lib/types/client/upload-plan.d.ts +78 -0
- package/lib/types/client/upload-source.d.ts +46 -0
- package/lib/types/client/use-remote-chat-target.d.ts +17 -0
- package/lib/types/client/vsc/FindWidget.d.ts +81 -0
- package/lib/types/client/vsc/change-marks.d.ts +150 -0
- package/lib/types/client/vsc/editor-langs.d.ts +5 -0
- package/lib/types/client/vsc/editor-palette.d.ts +37 -0
- package/lib/types/client/vsc/editor-theme.d.ts +32 -0
- package/lib/types/client/vsc/fallback-highlight.d.ts +26 -0
- package/lib/types/client/vsc/kit.d.ts +195 -0
- package/lib/types/client/vsc/markdown.d.ts +11 -0
- package/lib/types/client/vsc/reveal-line.d.ts +38 -0
- package/lib/types/client/vsc/tokenize.d.ts +104 -0
- package/lib/types/deploy.d.ts +94 -0
- package/lib/types/fs-ops.d.ts +8 -0
- package/lib/types/git-format.d.ts +34 -0
- package/lib/types/git-ops.d.ts +183 -0
- package/lib/types/http.d.ts +14 -0
- package/lib/types/importers.d.ts +20 -0
- package/lib/types/index.d.ts +87 -0
- package/lib/types/keygen.d.ts +19 -0
- package/lib/types/loopback.d.ts +7 -0
- package/lib/types/p2/bridge-refs.d.ts +21 -0
- package/lib/types/p2/bridge.d.ts +24 -0
- package/lib/types/p2/file-refs.d.ts +73 -0
- package/lib/types/p2/helper-rpc.d.ts +63 -0
- package/lib/types/p2/in-flight-gate.d.ts +25 -0
- package/lib/types/p2/router-fs.d.ts +92 -0
- package/lib/types/p2/router-refs.d.ts +45 -0
- package/lib/types/p2/router-spill.d.ts +11 -0
- package/lib/types/p2/router-subprocess.d.ts +23 -0
- package/lib/types/p2/shell-bash.d.ts +16 -0
- package/lib/types/p2/ssh-proc.d.ts +22 -0
- package/lib/types/p2/worlds.d.ts +179 -0
- package/lib/types/paths.d.ts +12 -0
- package/lib/types/pool.d.ts +105 -0
- package/lib/types/protocol.d.ts +452 -0
- package/lib/types/routes.d.ts +27 -0
- package/lib/types/search-ops.d.ts +68 -0
- package/lib/types/sftp.d.ts +90 -0
- package/lib/types/store.d.ts +66 -0
- package/lib/types/terminal.d.ts +51 -0
- package/lib/types/timeouts.d.ts +83 -0
- package/lib/types/tools.d.ts +41 -0
- package/lib/worlds-PUumRIh7.js +18765 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +189 -4
- package/src/changes/recorder.ts +902 -0
- package/src/changes/status.ts +448 -0
- package/src/changes/text-diff.ts +377 -0
- package/src/client/CodeEditor.tsx +923 -0
- package/src/client/Dialog.tsx +76 -0
- package/src/client/DirectoryFlow.tsx +431 -0
- package/src/client/EditorPane.tsx +512 -0
- package/src/client/HostsView.tsx +312 -0
- package/src/client/NativeExplorer.tsx +121 -0
- package/src/client/RemoteDirectoryPicker.tsx +157 -0
- package/src/client/RemoteEditorView.tsx +54 -0
- package/src/client/RemoteExplorer.tsx +1398 -0
- package/src/client/RemoteRoot.tsx +389 -0
- package/src/client/SearchView.tsx +407 -0
- package/src/client/SettingsHosts.tsx +136 -0
- package/src/client/TerminalView.tsx +308 -0
- package/src/client/WorkspaceWizard.tsx +199 -0
- package/src/client/WorkspacesView.tsx +93 -0
- package/src/client/XTerm.tsx +308 -0
- package/src/client/api.ts +331 -0
- package/src/client/changes/ChangesDock.tsx +348 -0
- package/src/client/changes/changes.css +230 -0
- package/src/client/changes/model.ts +347 -0
- package/src/client/changes/undo-affordance.ts +389 -0
- package/src/client/changes/undo-context.ts +34 -0
- package/src/client/composer.ts +436 -0
- package/src/client/css.d.ts +7 -0
- package/src/client/i18n.ts +702 -0
- package/src/client/index.tsx +286 -0
- package/src/client/remote-file-open-target.ts +553 -0
- package/src/client/remote-file-open.ts +261 -0
- package/src/client/reveal.ts +33 -0
- package/src/client/scm/DiffView.tsx +570 -0
- package/src/client/scm/HistoryPanel.tsx +353 -0
- package/src/client/scm/RepoPicker.tsx +238 -0
- package/src/client/scm/ScmPanel.tsx +857 -0
- package/src/client/scm/actions.ts +460 -0
- package/src/client/scm/diff-model.ts +206 -0
- package/src/client/scm/stage-queue.ts +264 -0
- package/src/client/scm/status-map.ts +381 -0
- package/src/client/scm/untracked-dirs.ts +139 -0
- package/src/client/selection-popup.ts +157 -0
- package/src/client/store.tsx +1670 -0
- package/src/client/theme.ts +54 -0
- package/src/client/ui.tsx +136 -0
- package/src/client/upload-plan.ts +153 -0
- package/src/client/upload-source.ts +145 -0
- package/src/client/use-remote-chat-target.ts +153 -0
- package/src/client/vsc/FindWidget.tsx +446 -0
- package/src/client/vsc/change-marks.ts +586 -0
- package/src/client/vsc/editor-langs.ts +137 -0
- package/src/client/vsc/editor-palette.ts +107 -0
- package/src/client/vsc/editor-theme.ts +93 -0
- package/src/client/vsc/fallback-highlight.ts +145 -0
- package/src/client/vsc/kit.tsx +777 -0
- package/src/client/vsc/markdown.tsx +172 -0
- package/src/client/vsc/reveal-line.ts +142 -0
- package/src/client/vsc/tokenize.ts +569 -0
- package/src/client/vsc/vsc.css +2669 -0
- package/src/deploy.ts +481 -0
- package/src/fs-ops.ts +57 -0
- package/src/git-format.ts +205 -0
- package/src/git-ops.ts +693 -0
- package/src/http.ts +55 -0
- package/src/importers.ts +141 -0
- package/src/index.ts +442 -0
- package/src/keygen.ts +77 -0
- package/src/loopback.ts +47 -0
- package/src/p2/bridge-refs.ts +27 -0
- package/src/p2/bridge.ts +32 -0
- package/src/p2/file-refs.ts +392 -0
- package/src/p2/helper-rpc.ts +394 -0
- package/src/p2/in-flight-gate.ts +63 -0
- package/src/p2/router-fs.ts +327 -0
- package/src/p2/router-refs.ts +166 -0
- package/src/p2/router-spill.ts +75 -0
- package/src/p2/router-subprocess.ts +92 -0
- package/src/p2/shell-bash.ts +30 -0
- package/src/p2/ssh-proc.ts +802 -0
- package/src/p2/worlds.ts +735 -0
- package/src/paths.ts +50 -0
- package/src/pool.ts +811 -0
- package/src/protocol.ts +460 -0
- package/src/routes.ts +802 -0
- package/src/search-ops.ts +220 -0
- package/src/sftp.ts +677 -0
- package/src/store.ts +364 -0
- package/src/terminal.ts +291 -0
- package/src/timeouts.ts +122 -0
- package/src/tools.ts +320 -0
- package/vendor/dsh-remote-helpers/dsh-ssh-helper-0.2.1-alpha.2-linux-x64.helper.json +16 -0
- package/vendor/dsh-remote-helpers/dsh-ssh-helper-0.2.1-alpha.2-linux-x64.tar.gz +4 -0
- package/vendor/dsh-remote-helpers/dsh-ssh-helper-0.2.1-alpha.2-linux-x64.tar.gz.sha256 +1 -0
- package/vendor/dsh-remote-helpers/glibc-ceiling.patch +31 -0
package/README.md
CHANGED
|
@@ -1,3 +1,348 @@
|
|
|
1
|
-
#
|
|
1
|
+
# dsh-remote-vs · DSH 远程开发(VSCode 式)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](./LICENSE)
|
|
4
|
+
|
|
5
|
+
中文 | [English](./README.en.md)
|
|
6
|
+
|
|
7
|
+
Host 进程内的 SSH 主机管理 + helper 推送流水线 + **VS Code 式远端工作台**
|
|
8
|
+
(资源管理器 / 搜索 / 源代码管理 / 提交图 / 多标签编辑器 / 并排 Diff / 多终端)。
|
|
9
|
+
主机配在 DSH 设置里(“远程主机”项);装了 `dsh-better-sidebar` 时另有
|
|
10
|
+
独立“远程”tab,没装则退到原生右侧栏“远程”页(同内容,引导页自助开,per-session 实例)。
|
|
11
|
+
编辑器还额外挂到会话视图槽,与“对话 / 轨迹”并列成一个**远程编辑器**标签,
|
|
12
|
+
这样代码区是整屏宽的;右侧栏那份是窄屏备用面。
|
|
13
|
+
P2 起原生工具在远端工作区里透明跑远端(见下)。
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
┌─ 本机 DSH Host ─────────────────────────────────┐
|
|
17
|
+
│ 本插件 Host 半 │ Client 半(浏览器) │
|
|
18
|
+
│ 主机/密钥/推送/路由 │ 设置两节 + 原生入口接管 │
|
|
19
|
+
│ /api/dsh-remote/* │ 工作台(右侧栏 + 会话视图)│
|
|
20
|
+
└──────────────────────┴──────────────────────────┘
|
|
21
|
+
│ ssh2(文件/进程/终端)+ helper RPC(远端 fs)
|
|
22
|
+
▼
|
|
23
|
+
┌─ 远端 Linux ─────────────────────────────────┐
|
|
24
|
+
│ ~/.dsh-helpers/<ver>/<arch>/dsh-ssh-helper │
|
|
25
|
+
│ 用户指定的远端工作目录 │
|
|
26
|
+
└──────────────────────────────────────────────┘
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 安装
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
dsh plugin --profile web add dsh-remote-vs
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
(从 npm 装,推荐;也可以直接跟仓库装:`dsh plugin --profile web add github:xiray-xia/dsh-remote-vs`。)
|
|
36
|
+
|
|
37
|
+
要求 DSH `0.2.1-alpha.3` 及以上(`engines.dsh` 门到底;**当前实测基线 `0.2.1-rc.2`**)。
|
|
38
|
+
`--profile web` 指明装进哪个 profile —— 本插件是 Web 插件,
|
|
39
|
+
必须装进 Web GUI 所用的那个(`web` 是常见命名,以你自己的 profile 名为准)。
|
|
40
|
+
|
|
41
|
+
**这一条命令就够了,不需要放行任何构建脚本**:包本身没有 `prepare`/`postinstall`,依赖树里也没有任何
|
|
42
|
+
带安装脚本的包(`ssh2` 是**打进产物**的,不是依赖);走仓库安装时还带着构建好的 `lib/`。
|
|
43
|
+
以前需要「在 profile 的 `pnpm-workspace.yaml` 里放行构建脚本后重跑」,那是 pnpm 12 对
|
|
44
|
+
「带安装脚本的依赖」的硬策略门(`ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED` / `ERR_PNPM_IGNORED_BUILDS`),
|
|
45
|
+
依赖侧无法豁免,只能从树里消掉。装完重启 `dsh web`,打开设置 → 远程主机开配。
|
|
46
|
+
|
|
47
|
+
> 包内含预编译的 helper(`vendor/dsh-remote-helpers/`,约 45 MB),所以首次安装下载量偏大 ——
|
|
48
|
+
> 它是**唯一**的 helper 投放渠道(官方 Release 不带 helper 可执行文件),去掉它就没法给新主机部署。
|
|
49
|
+
|
|
50
|
+
## 能力
|
|
51
|
+
|
|
52
|
+
### 远端工作台(VS Code 式 UI)
|
|
53
|
+
|
|
54
|
+
| 能力 | 说明 |
|
|
55
|
+
| --- | --- |
|
|
56
|
+
| 资源管理器 | 懒加载目录树 + 展开折叠 + 隐藏文件开关;右键菜单:新建/改名/删除/复制/移动/粘贴/在此文件夹查找/插入 `@` 引用;git 状态色与文件夹聚合标记 |
|
|
57
|
+
| 搜索 | 两档:**文件名**(远端 `find`)与**内容**(远端 `grep`)。内容档带范围目录、`Aa`(大小写)/`ab_`(全字)/`.*`(正则)、结果按文件分组、命中高亮,点条目跳到该行 |
|
|
58
|
+
| 源代码管理 | **仓库目录选择器**(工作区里的 git 在子目录时用:浏览远端目录、一键跳到工作区内发现的仓库、手输相对/绝对路径,并逐目录提示会落在哪个仓库);变更/暂存/未跟踪/忽略分桶,**未跟踪目录行可点击展开**,逐文件与**逐 hunk** 暂存/还原、丢弃(带确认)、提交;分支/远程/stash 面板;同步(fetch/pull/push) |
|
|
59
|
+
| 会话改动审阅 | 输入框上方的**可收纳**面板,按**会话**列出改了什么(一行一个文件、文件类型图标、右侧 `+a −b`);点文件在远程编辑器里打开并画**整行着色 + 行内字符级差异**,右上角 `n/N ↑↓` 跳改动点,悬浮改动行可**撤销**这处改动(远端 `git apply -R`)。详见下文「会话改动审阅」 |
|
|
60
|
+
| 并排 Diff | 左右**严格等分** + 中间 gutter 逐 hunk 按钮 + **顶部横向滚动条**(一行很长也不会破坏对称)+ 行号钉在左侧,**只渲染视口内的行**(3000 行文件从 9000 个行容器降到约 174 个,滚动范围与整篇渲染完全一致);可切「变更前 / 变更后」,变更后可编辑并保存 |
|
|
61
|
+
| 提交图 | SVG 分支/合并图 + 提交详情 + 点击提交展开变更文件 + 进文件看 diff |
|
|
62
|
+
| 多标签编辑器 | 打开/保存/重载、脏标记、多文件标签并存;图片预览、Markdown/HTML 预览(源码/预览切换) |
|
|
63
|
+
| 语法高亮 | VS Code **Dark+ / Light+** 配色;覆盖 java/aidl/smali、c/c++、go、rust、js/ts、json、py、yaml、xml、html/css、md、sh、properties/rc/toml、diff 等;**兜底着色器**在语法包没命中时自动接管,不会出现整篇无色。诚实说明:kotlin / gradle / smali 用 Java 语法着色(没有专用语法包),效果是关键字/字符串/注释正确、专有语法不细分 |
|
|
64
|
+
| 查找 | 编辑器内 `Ctrl+F`(`Aa`/`ab_`/`.*`、`3/17` 计数、↑↓、`F3`/`Shift+F3`、`Esc`);**选中文本按 `Ctrl+F` 直接填入**;查找框钉在右上角,滚动不带走 |
|
|
65
|
+
| 跳转 | 从搜索结果点进文件 → 跳到该行 + 垂直居中 + **落地行高亮**(约 2.6 秒后淡出);同文件反复跳都生效 |
|
|
66
|
+
| 多终端 | 标签式多终端(`+` 新建、`✕`/中键关闭带确认)、可跨主机;刷新页面按 session id 自动重连回原会话,**socket 全断开后会话保留 10 分钟**(够刷新、够切浏览器标签页接回),超时才关闭远端 shell |
|
|
67
|
+
| 工作区 | 绑定列表 + 路由档位下拉 + 新建工作区双模向导(本地 / 远端) |
|
|
68
|
+
|
|
69
|
+
### 主机与通道
|
|
70
|
+
|
|
71
|
+
| 能力 | 说明 |
|
|
72
|
+
| --- | --- |
|
|
73
|
+
| 主机管理 | 增删改查、连接测试;证书 / 密码认证;配置存 `$DSH_HOME/dsh-remote.json`(0600),与 `dsh-ssh.json` 独立 |
|
|
74
|
+
| 密钥 bootstrap | 密码主机一键生成专用密钥对并下发 `authorized_keys`,之后走密钥 |
|
|
75
|
+
| 推送流水线 | 远端 arch/系统探测 → 版本比对 → 一致跳过 / 否则推送;executable 通道推送自编译 helper。失败后不再每次远端文件操作都重试:按 **5 秒起步、上限 5 分钟**的退避重试,设置页「推送」按钮可强制立即重试 |
|
|
76
|
+
| 远端文件 | SFTP 浏览 / 读 / 写 / 新建 / 删除 / 改名。边界已加固:0 字节文件不再卡死,每个 SFTP 操作 60s 超时回收通道;**单个目录列表上限 20000 条**(按"目录在前、其余按名"排序后取前 20000,宿主日志说明——协议里没有"已截断"字段,界面上没有标记) |
|
|
77
|
+
| 远端终端 | ssh2 PTY + WebSocket,xterm 渲染(复制粘贴/主题跟随/刷新重连);**重新挂接只接管、不改尺寸**(刷新页面不会把运行中的 shell 缩成 80×24);输出积压时对远端施加真背压;**单帧上限 1 MiB**,超过 64 Ki 字符的粘贴在客户端按码点分块发送,不再撑断连接 |
|
|
78
|
+
| 并发通道 | 每主机同时最多 **6 条**远端通道(不再撞远端 sshd 的 `MaxSessions`);第 7 个排队最多等 **30 秒**,超时明确报 `remote host <alias> is busy`,而不是无限堆连接 |
|
|
79
|
+
| 超时与进程清理 | exec 跑在独立会话里(`setsid --wait`),超时先发 TERM、**3 秒后升级 KILL**,连同子进程一起收掉;远端没有 `setsid --wait` 时探测一次即知,退回旧行为并在宿主日志里写明"超时可能没停掉远端命令" |
|
|
80
|
+
| Git 图谱 | 远端仓库状态 + 分支 + SVG 提交图 + 提交详情(exec + 前端解析,零 Host 增量)|
|
|
81
|
+
| 导入 | 从 `~/.ssh/config`、从现有 `dsh-ssh.json` 一键导入(只读一次,不耦合)|
|
|
82
|
+
|
|
83
|
+
### Agent 能力
|
|
84
|
+
|
|
85
|
+
| 能力 | 说明 |
|
|
86
|
+
| --- | --- |
|
|
87
|
+
| Agent 工具 | `remote_hosts` / `remote_exec` / `remote_read` / `remote_write` / `remote_ls` |
|
|
88
|
+
| **P2 透明远端执行** | 远端工作区里原生 `read/write/edit/bash/glob/grep/jobs` 直接跑在远端 |
|
|
89
|
+
| **P3 远端 @ 引用** | 远端会话 `@` 出远端文件候选(路由 fileReferences,scoped 实时/bare 走远端 rg 索引) |
|
|
90
|
+
|
|
91
|
+
## 工程结构
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
dsh_remote_vs/
|
|
95
|
+
├── cordis.patch.yml # 组合声明:插件行 + 私有本地 realm + 三路由 + preset-remote
|
|
96
|
+
├── src/
|
|
97
|
+
│ ├── index.ts # 插件入口:store/pool/worlds/路由/工具/预设切换接线
|
|
98
|
+
│ ├── protocol.ts # 前后端 wire 契约(路由表 + 纯类型,两边共用)
|
|
99
|
+
│ ├── paths.ts # $DSH_HOME 下四件套寻址(库/密钥/构建缓存/别名目录)
|
|
100
|
+
│ ├── store.ts # 主机 + 绑定 + 墓碑持久化(0600 JSON,原子写)
|
|
101
|
+
│ ├── pool.ts # ssh2 长连接池(exec/shell/sftp/putFile,TOFU 主机键)
|
|
102
|
+
│ ├── sftp.ts # 远端文件引擎(SFTP 窗口读写/目录树操作)
|
|
103
|
+
│ ├── keygen.ts # 密码机密钥 bootstrap(生成→下发→翻转)
|
|
104
|
+
│ ├── deploy.ts # 推送流水线(探测/比对/传包/双验/manifest)
|
|
105
|
+
│ ├── importers.ts # ssh_config / dsh-ssh.json 解析导入
|
|
106
|
+
│ ├── routes.ts # /api/dsh-remote/* 路由表 + 终端 WebSocket 升级
|
|
107
|
+
│ ├── terminal.ts # PTY 会话注册表(刷新重连/断开清理)
|
|
108
|
+
│ ├── tools.ts # 5 个 Agent 工具定义
|
|
109
|
+
│ ├── http.ts / loopback.ts # JSON 体读写 + 回环信任围栏
|
|
110
|
+
│ ├── git-format.ts # git 命令构造 + 纯前端解析(Host 零增量)
|
|
111
|
+
│ ├── git-ops.ts # 远端 git 全量动作:status/diff/分支/远程/stash/提交/hunk 补丁构造 + 解析器
|
|
112
|
+
│ ├── fs-ops.ts # 远端文件操作命令构造(复制/移动/删除/stat)
|
|
113
|
+
│ ├── search-ops.ts # 远端内容搜索(grep 构造 + NUL 分隔解析 + 命中切分)
|
|
114
|
+
│ ├── p2/ # ── P2 透明路由 ──
|
|
115
|
+
│ │ ├── worlds.ts # 世界判定(cwd 键/别名/墓碑)+ RPC/FS/进程远端上下文
|
|
116
|
+
│ │ ├── helper-rpc.ts # ssh2 exec 通道上的 helper wire 协议(握手/心跳)
|
|
117
|
+
│ │ ├── router-fs.ts # 透明 fs 路由(目标→世界映射/路径翻译/策略重写)
|
|
118
|
+
│ │ ├── router-subprocess.ts # 透明进程路由(argv0 归约/pwsh 门)
|
|
119
|
+
│ │ ├── ssh-proc.ts # ssh2 进程运行时(setsid 组杀/marker/stdin/spill)
|
|
120
|
+
│ │ ├── shell-bash.ts # 路由 bash 执行器(本地原样/远端去 DSH_*)
|
|
121
|
+
│ │ ├── router-spill.ts # 透明 spill 路由(session 世界键/远端目录)
|
|
122
|
+
│ │ ├── router-refs.ts # 透明 @ 引用路由(agent 世界键,P3)
|
|
123
|
+
│ │ ├── file-refs.ts # 远端 @ 搜索(fs-ssh 实时列/rg 索引/官方评分移植)
|
|
124
|
+
│ │ ├── bridge.ts # 私有 realm 本地件发布(localFs 等早期服务)
|
|
125
|
+
│ │ └── bridge-refs.ts # refs 独立桥(local-refs 依赖 workingDirectory,必须分离)
|
|
126
|
+
│ └── client/ # ── 浏览器半(React,打包进 lib/client.js)──
|
|
127
|
+
│ ├── index.tsx # 双面决策(better 优先/settle 加速/原生兜底)+ 设置两节 + directoryFlow 双槽接管
|
|
128
|
+
│ ├── store.tsx # 双面共用的模块级状态(useSyncExternalStore;打开的文件/终端/视图都在这)
|
|
129
|
+
│ ├── RemoteRoot.tsx # 右侧栏挂载面:VS Code 式活动栏(资源管理器/搜索/SCM/提交图/编辑器/终端/工作区)
|
|
130
|
+
│ ├── RemoteEditorView.tsx # 会话视图挂载面(与 对话/轨迹 并列的「远程编辑器」标签,整屏宽)
|
|
131
|
+
│ ├── RemoteExplorer.tsx # 资源管理器:树 + 右键菜单 + 文件操作 + @ 引用 + 状态标记
|
|
132
|
+
│ ├── SearchView.tsx # 搜索面板:文件名 / 内容 两档 + Aa/ab_/.* + 分组结果 + 跳转
|
|
133
|
+
│ ├── EditorPane.tsx # 编辑器面板:多标签 + 信息栏(构建戳/tok 计数)+ 图片/MD/HTML 预览
|
|
134
|
+
│ ├── CodeEditor.tsx # CodeMirror 封装:语法包表/主题/查找框/跳转/兜底着色接线
|
|
135
|
+
│ ├── scm/ # ── 源代码管理 ──
|
|
136
|
+
│ │ ├── ScmPanel.tsx # 变更/暂存/未跟踪 + 逐文件逐 hunk 操作 + 提交框
|
|
137
|
+
│ │ ├── DiffView.tsx # 并排 diff(顶部横向滚动条/hunk 按钮/可编辑变更后侧)
|
|
138
|
+
│ │ ├── HistoryPanel.tsx # SVG 提交图 + 提交详情 + 展开变更文件
|
|
139
|
+
│ │ ├── actions.ts # 远端 git 动作层(exec 通道)
|
|
140
|
+
│ │ ├── diff-model.ts # unified diff → 并排行投影(纯函数)
|
|
141
|
+
│ │ └── status-map.ts # 状态分桶 + 树标记(纯函数)
|
|
142
|
+
│ ├── vsc/ # ── VS Code 皮肤与控件(零新依赖)──
|
|
143
|
+
│ │ ├── kit.tsx / vsc.css # 图标/对话框/右键菜单/分段控件 + 全部样式(.rvs-root 作用域)
|
|
144
|
+
│ │ ├── editor-palette.ts # Dark+/Light+ 配色 + 固定类名(rvs-ck-*)
|
|
145
|
+
│ │ ├── editor-theme.ts # 编辑器容器主题(明暗热切换)
|
|
146
|
+
│ │ ├── editor-langs.ts # 扩展名 → CodeMirror 语法包
|
|
147
|
+
│ │ ├── fallback-highlight.ts# 语法包没命中时的兜底着色(用 tokenize.ts)
|
|
148
|
+
│ │ ├── FindWidget.tsx # Ctrl+F 查找框(固定右上角)
|
|
149
|
+
│ │ ├── reveal-line.ts # 跳转 + 落地行高亮
|
|
150
|
+
│ │ ├── tokenize.ts / markdown.tsx # 只读面板分词器 / 零依赖 Markdown 渲染
|
|
151
|
+
│ ├── NativeExplorer.tsx# 原生页类型定义 + seat 正文(无 sidebar 兜底)
|
|
152
|
+
│ ├── composer.ts / use-remote-chat-target.ts / selection-popup.ts # 远端 @引用/选中加对话
|
|
153
|
+
│ ├── api.ts # /api/dsh-remote 类型化 fetch 封装
|
|
154
|
+
│ ├── HostsView / WorkspacesView / WorkspaceWizard / TerminalView / XTerm / Dialog
|
|
155
|
+
│ ├── SettingsHosts.tsx # 设置两节 occupant(主机管理/绑定列表,自取数)
|
|
156
|
+
│ ├── DirectoryFlow.tsx # 原生入口 occupant(本地双模/远端向导)
|
|
157
|
+
│ ├── RemoteDirectoryPicker.tsx# 远端目录浏览弹窗
|
|
158
|
+
│ └── i18n.ts / theme.ts / ui.tsx # 双语词典/主题信号/共享样式
|
|
159
|
+
├── vendor/dsh-remote-helpers/ # helper 种子(随包发布,启动铺缓存,见下)
|
|
160
|
+
├── docs/ # 本地工作文档(不推送 GitHub)
|
|
161
|
+
│ ├── P2-PLAN.md # P2 架构/分期/验收矩阵(含逐项状态)
|
|
162
|
+
│ └── MAINTENANCE.md # 本地私有(.gitignore),不入库:DSH 升级影响面 + helper 升级流程
|
|
163
|
+
├── locale/ # 插件元信息双语
|
|
164
|
+
└── lib/ # 构建产物(gitignored,link 安装后重启即生效)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
`vendor/dsh-remote-helpers/`(入库)是 helper 种子:插件启动时自动铺到
|
|
168
|
+
`$DSH_HOME/dsh-remote-helpers/`(缺啥补啥,永不覆盖),新机器装完即能推送。
|
|
169
|
+
新版本 helper 编好后把 4 件套(tarball + sha256 + helper.json + 补丁说明)
|
|
170
|
+
换进 vendor 并提交即可(详细步骤在本地维护文档 `docs/MAINTENANCE.md` §4,该文件被 .gitignore,不随仓库分发)。
|
|
171
|
+
|
|
172
|
+
`.spike/`(gitignored)是真机验证脚本 + 本地自检脚本:`p2-router.ts` 主回归(真远端 + 真
|
|
173
|
+
Cordis + 真路由类)+ `grep-probe.mjs` 等探针(构建见 `tsconfig.scratch.json`),以及不需要真机的
|
|
174
|
+
`model-check.mjs` / `reveal-check.mjs` / `fallback-check.mjs` / `client-load-check.mjs` /
|
|
175
|
+
`tool-schema-check.mjs`(见下文“开发”)。
|
|
176
|
+
|
|
177
|
+
## 远端工作台(VS Code 式)
|
|
178
|
+
|
|
179
|
+

|
|
180
|
+
|
|
181
|
+
两个挂载面共用一份状态(`store.tsx`):**右侧栏「远程」**(装了 better-sidebar 走独立 tab,
|
|
182
|
+
否则走原生右栏页)与**会话视图「远程编辑器」**(与 对话/轨迹 并列,代码区整屏宽)。
|
|
183
|
+
|
|
184
|
+
- **活动栏**:资源管理器 / 搜索 / 源代码管理 / 提交图 / 编辑器 / 终端 / 工作区;面板首次访问后
|
|
185
|
+
保持挂载,切回来不重新拉取、不闪。隐藏期间**不做远端工作**(目录列表、SCM 的 stash/分支/远程查询、
|
|
186
|
+
编辑器图片读取都等回到前台再补一次),可见性是对插件根节点实测的(IntersectionObserver),
|
|
187
|
+
不靠宿主传参。
|
|
188
|
+
- **编辑器**:多标签 + 信息栏(路径、语言、**构建戳**、`tok N` 着色 token 数、已保存状态、重载/保存)。
|
|
189
|
+
信息栏三个标记是给排障用的:构建戳判定"浏览器跑的是不是刚编的包",`tok 0` 判定语法包是否命中。
|
|
190
|
+
- **查找与跳转**:`Ctrl+F` 查找框固定右上角(`position: fixed` 锚定编辑器矩形,任何祖先滚动都不带走);
|
|
191
|
+
选中文本按 `Ctrl+F` 直接填入;从搜索结果跳转会**居中 + 落地行高亮**。
|
|
192
|
+
- **终端**:标签式多终端,session id 逐个持久化,刷新页面自动重连回原会话;**重连只接管、不改尺寸**
|
|
193
|
+
(活着的 shell 不会被缩成 80×24——真实尺寸由能测到自己的那个标签发 `resize` 帧);socket 全断开后
|
|
194
|
+
会话保留 **10 分钟**,超时才关闭远端 shell(以前是永不回收,关掉浏览器后远端 shell 一直占着 sshd 会话槽)。
|
|
195
|
+
- **已知边界(诚实说明)**:
|
|
196
|
+
- 切到「远程编辑器」标签**没有公开 API**,插件只能按标签文字点击外壳自己的 tab,失败时给 toast
|
|
197
|
+
提示手动切(`revealEditor()`);
|
|
198
|
+
- 未跟踪目录在状态里是**一行**(`dir/`),点它**展开**该目录里的文件(只发一条限定路径的
|
|
199
|
+
`git status -uall -- dir/`,成本随目录而不随仓库;再点收起);展开态是「展开那一刻」的快照,
|
|
200
|
+
折叠再展开即刷新;
|
|
201
|
+
- 打开文件读取上限 8MiB(helper 官方常量),超限以只读方式呈现;
|
|
202
|
+
- 查找框用固定定位浮在代码上方(与 VS Code 一致),不占布局空间;
|
|
203
|
+
- 输出背压是**按 shell** 的:某个跟不上的标签会连带暂停该 shell 的所有标签(宁可让最慢的消费者
|
|
204
|
+
拖住远端命令,也不让宿主内存无界增长);
|
|
205
|
+
- 目录列表超过 20000 条会被截断,而协议里没有"已截断"字段 ⇒ 界面上没有任何标记,只有宿主日志里的
|
|
206
|
+
`listing <path> on <alias> shows 20000 of N entries`。
|
|
207
|
+
|
|
208
|
+
## 会话改动审阅(Cursor 式)
|
|
209
|
+
|
|
210
|
+

|
|
211
|
+
|
|
212
|
+
输入框上方那条**可收纳**的面板(标题「本次改动」)按**会话**回答"这一轮改了什么"。数据来自插件自己的
|
|
213
|
+
会话改动账本(`/api/dsh-remote/changes`),不是 DSH 的 `workspaceChanges` —— 后者看不见被路由的会话
|
|
214
|
+
(探针实测:58 个远端会话、0 个改动事件)。
|
|
215
|
+
|
|
216
|
+
- **面板**:一行一个文件(文件类型图标 + 相对路径 + 右侧 `+a −b`),宽度与输入卡**左右对齐**;
|
|
217
|
+
点标题栏折叠/展开,`⟳` 强制立即重扫。没有改动时显示「本会话还没有改动文件。」;统计不出来时显示
|
|
218
|
+
**具体原因**(见下面的边界),不会丢一个空列表让人猜。
|
|
219
|
+
- **点文件**在远程编辑器里打开,并画上改动标记:新增行**绿色行背景**,删除的字符用**行内删除线 chip**
|
|
220
|
+
表示(被删的字符在新文件里不存在,只能用插入的 widget 画),左侧 gutter 一列改动色条。
|
|
221
|
+
- **跳改动点**:编辑器右上角悬浮 `n/N ↑↓`(快捷键 `Alt+Shift+Cmd/Ctrl+↓/↑`),在改动点之间循环跳转;
|
|
222
|
+
编辑器里一敲字,标记即作废并提示「位置已过期」。
|
|
223
|
+
- **撤销这处改动**:悬浮在改动行上点一下 → 远端 `git apply -R`。上下文对不上时远端直接拒绝(文件一个
|
|
224
|
+
字节都不动);标签页里有未保存内容时先拒绝,绝不会用远端补丁盖掉你的编辑;成功后光标留在原处,
|
|
225
|
+
标记自动重读刷新(不会因为"撤销了"就整片标记消失)。
|
|
226
|
+
- **跟随会话工作区**:侧栏、编辑器下拉、文件树三者跟着**当前会话所在的工作区**走;用户手动切换后同一
|
|
227
|
+
会话内不再被拉回,换会话重新跟随。跟随能力在 store 层,**侧栏从未打开过也照样跟随**;在改动面板点
|
|
228
|
+
文件属于"看结果",不算手动切换。
|
|
229
|
+
- **仓库目录**:沿用「源代码管理 → 仓库目录」里用户选的那个(显式选择永远优先);会话根不是仓库时,
|
|
230
|
+
只在**唯一候选**(根下一层只有一个仓库)时自动采用,多个候选会明确提示去「源代码管理」设置里指定。
|
|
231
|
+
|
|
232
|
+
**已知边界(如实写)**:
|
|
233
|
+
|
|
234
|
+
- 改动统计以**会话起点**为基线(不是 HEAD):会话开始前就存在的未跟踪文件不会被算成本次改动。
|
|
235
|
+
- 已跟踪文件的数字随**轮次结束**刷新(面板每 3 秒轮询兜底,通常一两秒内跟上);**新文件**(在 shell 里
|
|
236
|
+
创建的)靠**慢扫描**发现,单次预算最长约 **3 分钟**,重扫间隔按上次耗时自适应(至少 5 秒,大仓库会
|
|
237
|
+
自然拉长);点 `⟳` 可强制立即重扫。
|
|
238
|
+
- 非 git 工作区、或工作区里有多个仓库而没指定仓库目录时,面板显示明确原因
|
|
239
|
+
(`no git repository at the workspace root, and N candidates below it — set the repository directory in Source Control`),不显示空列表。
|
|
240
|
+
- 二进制文件与超大文件只在行尾标「二进制 / 过大」,不给字符级差异。
|
|
241
|
+
|
|
242
|
+
## P2 透明远端执行(Windows 原生)
|
|
243
|
+
|
|
244
|
+
单 Host 混合路由:原生工具按会话 cwd 落在哪个世界自动分发 —— 远端 alias 走
|
|
245
|
+
helper RPC(fs)/ ssh2(进程),本地一切不变;两者同 Host、共 GUI。
|
|
246
|
+
|
|
247
|
+
- 别名目录:`$DSH_HOME/remote-ssh/aliases/<id>`(空壳,只做路由键),自动注册进原生工作区列表,标题 `<server> > <base>`
|
|
248
|
+
- 路由开关(设置 → 远程主机页顶部下拉;底层是 profile patch `- id: remote-vs` 下 `config.routingMode`,volatile,免重启):
|
|
249
|
+
`off`(默认,直通本地)/ `shadow`(记日志仍走本地)/ `enforce`(真路由)
|
|
250
|
+
- 新建工作区:原生"添加工作区…"入口已接管(本地/远端双 tab;远端腿=主机→推送→绑定向导)
|
|
251
|
+
- 预设:`Remote` 预设(bash 工具集);enforce 下远端新会话自动切过去(默认预设才切,不践踏显式选择)
|
|
252
|
+
- 顶层真相(实测结论,非假设):
|
|
253
|
+
- 远端 `grep/glob` 经路由调远端 `rg`(两台实测机自带 rg 13;远端无 rg 则查不到)
|
|
254
|
+
- 整包读 >8MiB 报 `FS_TOO_LARGE`(helper 官方上限),用流读/分页;**写无上限**(46MiB 整包写实测通过)
|
|
255
|
+
- 超长进程输出落 Host 临时 spill 文件(`readFrom` 返 tail + 路径,全文住文件里,与官方一致)
|
|
256
|
+
- 删绑定后新调用明确拒绝(墓碑 fail-closed),历史记录可读
|
|
257
|
+
- 断线:在途不重放;新调用自动重连
|
|
258
|
+
- 验证:`npx tsc -p tsconfig.scratch.json && node .spike/build/.spike/p2-router.js`
|
|
259
|
+
(真远端 + 真 Cordis + 真路由类,61/61;P0 路由与 GUI 需重启 Host 后冒烟)
|
|
260
|
+
- 详见 `docs/P2-PLAN.md`(§8 验收矩阵逐项状态)
|
|
261
|
+
|
|
262
|
+
## Helper 自编译(P1)
|
|
263
|
+
|
|
264
|
+
官方从未发布 helper 二进制(Release assets 全空),本插件走自编译:
|
|
265
|
+
|
|
266
|
+
- 构建机:WSL2 Ubuntu-22.04(glibc 2.35,与目标远端一致),Node v24.21.0 + pnpm 11.28.5
|
|
267
|
+
- 源码:`dsh-v0.2.1-alpha.2` tag(**构建基线**:对齐的是 wire 协议号,不是 Host 版本号 —— 协议号至今仍是 2,故 Host 升到 alpha.4 / alpha.5 都无需重编)
|
|
268
|
+
- 命令:官方原脚本 `pnpm exec tsx scripts/build-exe-for-ssh-helper.ts --target=node24-linux-x64`
|
|
269
|
+
- 唯一偏离:无 docker 跑不了 manylinux 2.28 重编,加了 `DSH_GLIBC_CEILING`
|
|
270
|
+
环境覆盖(默认仍 2.28),本次以 2.35 构建(见缓存目录 `glibc-ceiling.patch`)
|
|
271
|
+
- 校验:官方 `verify-ssh-helper-artifact.ts --sandbox=required` 8 项全绿
|
|
272
|
+
- 缓存:`$DSH_HOME/dsh-remote-helpers/`(`*.tar.gz` + `.sha256` + `.helper.json`
|
|
273
|
+
含 binarySha256,供 P2 的 helperHash)
|
|
274
|
+
- 升级重编全流程见本地维护文档 `docs/MAINTENANCE.md` §4(.gitignore,不随仓库分发)
|
|
275
|
+
|
|
276
|
+
## 安全模型
|
|
277
|
+
|
|
278
|
+
- 所有 `/api/dsh-remote/*` 路由仅限 loopback + 同源访问。
|
|
279
|
+
- 密码 / 私钥口令以明文保存在 `dsh-remote.json`(0600),与现有 SSH 插件同一信任模型。
|
|
280
|
+
- 推送物逐包验 sha256(tarball 进、binary 出,双重校验);helper 安装目录与工作区分开。
|
|
281
|
+
- 远端会话可读显式本机绝对路径(工具 spill 文件契约要求);同模型信任下可接受,见 `docs/P2-PLAN.md` §4 备注。
|
|
282
|
+
|
|
283
|
+
## 开发
|
|
284
|
+
|
|
285
|
+
```sh
|
|
286
|
+
pnpm install
|
|
287
|
+
pnpm run typecheck
|
|
288
|
+
pnpm run build
|
|
289
|
+
dsh plugin --profile web add link:<本目录绝对路径>
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
**改完怎么生效:`pnpm run build` 之后重启 `dsh web` —— host 半与客户端半都是。**
|
|
293
|
+
**`lib/` 是入库的**:本包没有 `prepare`(pnpm 12 会拦),别人 `dsh plugin add github:…` 拿到的是仓库内容,
|
|
294
|
+
所以**改完源码必须 `npm run build` 并把 `lib/` 一起提交**——`pnpm check` 的第一步
|
|
295
|
+
(`scripts/verify-lib.mjs`)会在 `lib/` 没入库或加载即抛错时直接失败。
|
|
296
|
+
Host 在启动时把插件包读进内存(`initialBundleSnapshot`:先记录 mtime/ctime/size 作为 rev,再读字节;
|
|
297
|
+
响应头 `Cache-Control: public, max-age=31536000, immutable`),所以**只改 `src/client/**` 也一样**:
|
|
298
|
+
浏览器刷新——包括 `Ctrl+Shift+R`——只会取回启动时抓下的那批字节,rev 不变。判定方法:
|
|
299
|
+
|
|
300
|
+
1. 构建后 `lib/client.js` 里会注入构建戳(`MMDD-HHmm`),编辑器信息栏右侧显示的就是它;
|
|
301
|
+
2. 重启 `dsh web` → 刷新页面:**戳变了才算生效**(没变 = 拿到的还是启动时那批字节);
|
|
302
|
+
3. 颜色类问题再看 `tok N`:`0` = 该扩展名没命中语法包,且兜底着色器也没接管(会给括号里的文件路径)。
|
|
303
|
+
|
|
304
|
+
> 唯一的例外是 DSH 自己的开发 watcher(`pnpm run dev:web`,走 `ClientModuleRegistry.rebuilt`);
|
|
305
|
+
> 插件用户侧没有 watcher,`dsh web --help` 也没有 watch 选项,所以按"必须重启"执行。
|
|
306
|
+
|
|
307
|
+
自检(不需要真机、不需要 DSH,几十秒):
|
|
308
|
+
|
|
309
|
+
```sh
|
|
310
|
+
node .spike/client-load-check.mjs # 真求值客户端模块:加载期错误(模块级 TDZ 之类)tsc、打包、其它 harness 都看不见
|
|
311
|
+
node .spike/tool-schema-check.mjs # 5 个 agent 工具:跑一遍 execute,用运行时的同一个校验器核对返回值和声明的输出 schema
|
|
312
|
+
node .spike/model-check.mjs # 55 项:真 git 输出 → 解析器、diff 模型、hunk 补丁可应用性、类名↔CSS 契约
|
|
313
|
+
node .spike/reveal-check.mjs # 5 项:跳转落点、落地高亮、同文件二次跳转
|
|
314
|
+
node .spike/fallback-check.mjs # 12 项:兜底着色器在真 DOM 里给 java/cpp/shell 上色
|
|
315
|
+
node .spike/editor-dom-check.mjs # 12 项:真 CodeMirror 在 jsdom 里对 java/shell/cpp 产出着色 span
|
|
316
|
+
node .spike/i18n-check.mjs # 中英词典一致性:无缺失键、无孤儿键、占位符形状一致
|
|
317
|
+
node .spike/ref-check.mjs # 32 项:assertRef 接受合法修订后缀、拒绝一切注入面
|
|
318
|
+
node .spike/status-check.mjs # 真 shell 里跑生成的 git 命令,验证退出码不再被管道掩盖
|
|
319
|
+
node .spike/cache-check.mjs # 增量分词缓存 vs 整篇分词,9 种语言 × 8 种编辑形态逐字节比对
|
|
320
|
+
node .spike/layout-check.mjs # 高度链与滚动条契约:标签栏固定不被顶走、编辑器滚动条够宽可点
|
|
321
|
+
node .spike/viewstate-check.mjs # 滚动+光标跨重挂的往返(有状态 scrollTop,能区分"恢复"与"被重置")
|
|
322
|
+
node .spike/tabswitch-check.mjs # 真 React 驱动三种接线:两种读 ref 的必须失败,上报式必须成功
|
|
323
|
+
node .spike/letter-check.mjs # 状态字母:未跟踪 ? 与冲突 U 不再撞车,其它映射与两处渲染点
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
`.spike/layout-fixture.html`(由 `build-fixture.mjs` 生成)是浏览器里量布局用的夹具:
|
|
327
|
+
它把**宿主真实的插槽 CSS** 和**线上 vsc.css** 机械内联进去,改完 CSS 重跑
|
|
328
|
+
`node .spike/build-fixture.mjs` 即可在真浏览器里量高度链、滚动容器与滚动条宽度——
|
|
329
|
+
纯 CSS 的问题 tsc、打包、jsdom 都看不见,这个夹具是唯一能复现它们的地方。
|
|
330
|
+
|
|
331
|
+
`markdown-check.ts` 需要先编译(它 import `.tsx`,Node 不能直跑):
|
|
332
|
+
`npx tsc -p tsconfig.scratch.json && node .spike/build/.spike/markdown-check.js`。
|
|
333
|
+
|
|
334
|
+
> `.spike/` 被 `.gitignore` 排除,这些检查只在本地存在、没有 CI;因此**引用任何数字前都要当场跑一遍**,
|
|
335
|
+
> 不要照抄任何一处写着的数字(同一个 `model-check` 曾在 README / 本地维护文档 / 评审报告之间漂移出
|
|
336
|
+
> 44 / 48 / 55 三种,而它实际打印 55/55 —— 脚本里有 57 处 `check(` 调用点,其中 2 处在循环里且只在
|
|
337
|
+
> 失败时才触发,所以「调用点 57」与「跑出来 55」本来就该差 2)。
|
|
338
|
+
|
|
339
|
+
真机回归仍是 `npx tsc -p tsconfig.scratch.json && node .spike/build/.spike/p2-router.js`。
|
|
340
|
+
DSH 发新版时先读本地维护文档 `docs/MAINTENANCE.md`(§2 逐项耦合点 + §3 升级清单)再动手;该文件被 .gitignore,克隆仓库的人看不到,改动 host 半后的必做动作是 `pnpm run verify:lib` + 加载自检。
|
|
341
|
+
|
|
342
|
+
## 开源许可
|
|
343
|
+
|
|
344
|
+
MIT © 2026 xiray-xia —— 见 [LICENSE](./LICENSE)。
|
|
345
|
+
|
|
346
|
+
`vendor/` 里的 helper 种子由 DeepSeek Harness 源码(MIT)按 `dsh-v0.2.1-alpha.2`
|
|
347
|
+
tag 以官方原脚本构建,具体流程与唯一有记录的偏离见上文"Helper 自编译"节
|
|
348
|
+
(种子包里的 `glibc-ceiling.patch`)。
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# dsh-remote-vs bundle patch: inserts the dual-face plugin row into the profile
|
|
2
|
+
# roster. The node half (exports ".") runs in the host process (remote store,
|
|
3
|
+
# ssh2 pool, /api/dsh-remote routes, agent tools); the browser half (exports
|
|
4
|
+
# "./client") registers the remote explorer tab into dsh-better-sidebar.
|
|
5
|
+
# P2 adds a private local realm + transparent routers (fs/subprocess/spill)
|
|
6
|
+
# and a bash shell for the Remote preset. Stock tool rows are untouched: tools
|
|
7
|
+
# resolve the routed root services dynamically.
|
|
8
|
+
- insert:
|
|
9
|
+
- id: remote-vs
|
|
10
|
+
name: 'dsh-remote-vs'
|
|
11
|
+
|
|
12
|
+
# Preserve the stock local providers in a private realm. The bridge
|
|
13
|
+
# publishes them under non-conflicting names consumed by the routers.
|
|
14
|
+
- id: remote-vs-local-world
|
|
15
|
+
name: cordis:group
|
|
16
|
+
group: true
|
|
17
|
+
isolate:
|
|
18
|
+
fileReferences: true
|
|
19
|
+
fs: true
|
|
20
|
+
subprocess: true
|
|
21
|
+
spillStore: true
|
|
22
|
+
config:
|
|
23
|
+
- id: local-subprocess
|
|
24
|
+
name: '@deepseek-ai/dsh-subprocess-local'
|
|
25
|
+
- id: local-fs
|
|
26
|
+
name: '@deepseek-ai/dsh-fs-sandbox'
|
|
27
|
+
- id: local-spill
|
|
28
|
+
name: '@deepseek-ai/dsh-spill-local'
|
|
29
|
+
- id: local-refs
|
|
30
|
+
name: '@deepseek-ai/dsh-file-reference-local'
|
|
31
|
+
- id: local-bridge
|
|
32
|
+
name: dsh-remote-vs/p2-bridge
|
|
33
|
+
inject: [fs, subprocess, spillStore]
|
|
34
|
+
# Separate bridge: local-refs injects workingDirectory (downstream of
|
|
35
|
+
# our replaced fs), so it must not gate fs/subprocess/spillStore.
|
|
36
|
+
- id: local-bridge-refs
|
|
37
|
+
name: dsh-remote-vs/p2-bridge-refs
|
|
38
|
+
inject: [fileReferences]
|
|
39
|
+
|
|
40
|
+
- id: remote-vs-fs-router
|
|
41
|
+
name: dsh-remote-vs/p2-router-fs
|
|
42
|
+
inject: [localFs, remoteWorlds]
|
|
43
|
+
|
|
44
|
+
- id: remote-vs-subprocess-router
|
|
45
|
+
name: dsh-remote-vs/p2-router-subprocess
|
|
46
|
+
inject: [localSubprocess, remoteWorlds]
|
|
47
|
+
|
|
48
|
+
- id: remote-vs-spill-router
|
|
49
|
+
name: dsh-remote-vs/p2-router-spill
|
|
50
|
+
inject: [localSpillStore, remoteWorlds]
|
|
51
|
+
|
|
52
|
+
- id: remote-vs-file-refs-router
|
|
53
|
+
name: dsh-remote-vs/p2-router-refs
|
|
54
|
+
inject: [localFileReferences, remoteWorlds]
|
|
55
|
+
|
|
56
|
+
# Remote agent preset, bound to this bundle's lifecycle.
|
|
57
|
+
# Mirrored from preset-standard @ dsh 0.2.1-alpha.3 with these diffs:
|
|
58
|
+
# 1. persona prefix reframed for remote SSH work (transparent routing);
|
|
59
|
+
# 2. tool-bash moved into an isolated shell group with our routed bash
|
|
60
|
+
# executor (stock root shell stays pwsh on Windows);
|
|
61
|
+
# 3. tool-pwsh row dropped.
|
|
62
|
+
# Everything else is byte-identical so future diffs against stock stay obvious.
|
|
63
|
+
# alpha.3 note: stock dropped `toolFilter` (subagent children now inherit
|
|
64
|
+
# the parent composition; fork must not select presets) — our mirror drops
|
|
65
|
+
# both blocks with it.
|
|
66
|
+
# alpha.4 note: stock added `tool-plugin-market` (disabled: true in every
|
|
67
|
+
# preset) right after `tool-plugin-manager` — mirrored here for the same
|
|
68
|
+
# reason as above: a row missing from the mirror is a preset that silently
|
|
69
|
+
# loads a different toolset than stock.
|
|
70
|
+
- id: preset-remote
|
|
71
|
+
name: '@deepseek-ai/dsh-agent-preset'
|
|
72
|
+
config:
|
|
73
|
+
id: remote
|
|
74
|
+
name: Remote
|
|
75
|
+
description: 'Remote SSH development (POSIX): bash toolset, remote conventions, transparent remote execution.'
|
|
76
|
+
order: 5
|
|
77
|
+
plugins:
|
|
78
|
+
- id: persona
|
|
79
|
+
name: '@deepseek-ai/dsh-persona'
|
|
80
|
+
config:
|
|
81
|
+
prefix: >-
|
|
82
|
+
You are a coding agent powered by the {{model}} model, working with REMOTE SSH hosts (POSIX/Linux)
|
|
83
|
+
and local paths transparently: tools follow the session workspace — remote workspaces execute on
|
|
84
|
+
their SSH host, local paths stay local. Prefer bash and POSIX absolute paths for remote work;
|
|
85
|
+
remote_hosts lists configured hosts when you need explicit cross-world operations. A `remote
|
|
86
|
+
workspace` context block states this session's alias→host→root mapping when remote; trust it.
|
|
87
|
+
- id: agent-instructions
|
|
88
|
+
name: '@deepseek-ai/dsh-agent-instructions'
|
|
89
|
+
config:
|
|
90
|
+
maxBytes: 65536
|
|
91
|
+
- id: time-context
|
|
92
|
+
name: '@deepseek-ai/dsh-time-context'
|
|
93
|
+
- id: remote-shell
|
|
94
|
+
name: cordis:group
|
|
95
|
+
group: true
|
|
96
|
+
isolate:
|
|
97
|
+
shell: true
|
|
98
|
+
config:
|
|
99
|
+
- id: remote-bash-shell
|
|
100
|
+
name: dsh-remote-vs/p2-shell-bash
|
|
101
|
+
inject: [subprocess, remoteWorlds]
|
|
102
|
+
config:
|
|
103
|
+
timeoutMs: 60000
|
|
104
|
+
- id: tool-bash
|
|
105
|
+
name: '@deepseek-ai/dsh-tool-bash'
|
|
106
|
+
- id: tool-fs
|
|
107
|
+
name: '@deepseek-ai/dsh-tool-fs'
|
|
108
|
+
- id: tool-fs-search
|
|
109
|
+
name: '@deepseek-ai/dsh-tool-fs-search'
|
|
110
|
+
config:
|
|
111
|
+
sampleOverCapGlobResults: false
|
|
112
|
+
- id: tool-jobs
|
|
113
|
+
name: '@deepseek-ai/dsh-tool-jobs'
|
|
114
|
+
- id: tool-schedule
|
|
115
|
+
name: '@deepseek-ai/dsh-tool-schedule'
|
|
116
|
+
- id: skill-filesystem
|
|
117
|
+
name: '@deepseek-ai/dsh-skill-filesystem'
|
|
118
|
+
- id: tool-skill
|
|
119
|
+
name: '@deepseek-ai/dsh-tool-skill'
|
|
120
|
+
- id: command-goal
|
|
121
|
+
name: '@deepseek-ai/dsh-command-goal'
|
|
122
|
+
- id: tool-goal
|
|
123
|
+
name: '@deepseek-ai/dsh-tool-goal'
|
|
124
|
+
- id: planning
|
|
125
|
+
name: cordis:group
|
|
126
|
+
group: true
|
|
127
|
+
isolate:
|
|
128
|
+
planMode: true
|
|
129
|
+
config:
|
|
130
|
+
- id: plan-mode
|
|
131
|
+
name: '@deepseek-ai/dsh-plan-mode'
|
|
132
|
+
config:
|
|
133
|
+
section: >
|
|
134
|
+
You are in plan mode. Stay in plan mode until the user approves your plan through exit_plan_mode
|
|
135
|
+
or switches the session mode. Imperative
|
|
136
|
+
language to implement changes means plan the implementation, not
|
|
137
|
+
execute it. A user's conversational agreement — including an
|
|
138
|
+
answer confirming something you asked — approves nothing and
|
|
139
|
+
does not end plan mode; fold the confirmed decision into the
|
|
140
|
+
plan and submit it through exit_plan_mode.
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
Explore first. Use non-mutating reads, searches, static
|
|
144
|
+
analysis, and checks to ground the plan in the actual
|
|
145
|
+
repository. Do not edit or write files, change configuration,
|
|
146
|
+
run formatters or code generation that rewrites tracked files,
|
|
147
|
+
commit, or otherwise carry out the plan. Prefer existing
|
|
148
|
+
functions and patterns over new machinery.
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
The tool catalog stays the same across modes for request-cache
|
|
152
|
+
stability. These plan-mode rules override any later tool
|
|
153
|
+
description or guidance that suggests using mutation tools;
|
|
154
|
+
those tools remain listed to keep the tool catalog unchanged. Do
|
|
155
|
+
not use todo_write to track this planning phase: it tracks
|
|
156
|
+
implementation after an approved plan, while the plan itself
|
|
157
|
+
belongs in exit_plan_mode.
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
Resolve discoverable facts by inspection. Use ask_user_question
|
|
161
|
+
only for user-owned choices or material ambiguity that
|
|
162
|
+
inspection cannot answer. Do not ask the user where code lives
|
|
163
|
+
or how current behavior works when you can find out.
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
Make the plan decision-complete: state the goal and success
|
|
167
|
+
criteria; group implementation changes by subsystem; identify
|
|
168
|
+
public API, schema, and data-flow changes; cover edge cases,
|
|
169
|
+
failure modes, tests, acceptance criteria, and explicit
|
|
170
|
+
assumptions. Keep it concise enough to review but detailed
|
|
171
|
+
enough that another engineer can implement it without making
|
|
172
|
+
design decisions.
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
When ready, call exit_plan_mode with the complete plan markdown,
|
|
176
|
+
starting with a # title. Make exit_plan_mode the only and final
|
|
177
|
+
tool call in that assistant response: it presents the plan for
|
|
178
|
+
approval, and implementation begins only in a later step after
|
|
179
|
+
approval. Do not paste the final plan as a plain reply or ask
|
|
180
|
+
"should I proceed?" through prose or ask_user_question. If
|
|
181
|
+
review rejects it, incorporate the feedback and present again.
|
|
182
|
+
If the review channel is unavailable or aborted, stay in plan
|
|
183
|
+
mode and ask the user to switch modes manually; do not proceed
|
|
184
|
+
with implementation.
|
|
185
|
+
- id: compaction
|
|
186
|
+
name: cordis:group
|
|
187
|
+
group: true
|
|
188
|
+
isolate:
|
|
189
|
+
compaction: true
|
|
190
|
+
toolResultPruner: true
|
|
191
|
+
config:
|
|
192
|
+
- id: compaction-basic
|
|
193
|
+
name: '@deepseek-ai/dsh-compaction-basic'
|
|
194
|
+
- id: command-compact
|
|
195
|
+
name: '@deepseek-ai/dsh-command-compact'
|
|
196
|
+
- id: tool-result-pruner
|
|
197
|
+
name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
|
|
198
|
+
config:
|
|
199
|
+
thresholdChars: 8192
|
|
200
|
+
headChars: 4096
|
|
201
|
+
tailChars: 1024
|
|
202
|
+
- id: delegation
|
|
203
|
+
name: cordis:group
|
|
204
|
+
group: true
|
|
205
|
+
isolate:
|
|
206
|
+
workflowEngine: true
|
|
207
|
+
config:
|
|
208
|
+
- id: tool-subagent-control
|
|
209
|
+
name: '@deepseek-ai/dsh-tool-subagent-control'
|
|
210
|
+
- id: tool-subagent-list-agents
|
|
211
|
+
name: '@deepseek-ai/dsh-tool-subagent-control/list-agents'
|
|
212
|
+
- id: tool-subagent
|
|
213
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
214
|
+
config:
|
|
215
|
+
provider: spawn
|
|
216
|
+
toolName: subagent
|
|
217
|
+
modelSelectionSettings: true
|
|
218
|
+
- id: tool-subagent-fork
|
|
219
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
220
|
+
config:
|
|
221
|
+
provider: fork
|
|
222
|
+
toolName: subagent_fork
|
|
223
|
+
- id: workflow-ptc
|
|
224
|
+
name: '@deepseek-ai/dsh-workflow-ptc'
|
|
225
|
+
config:
|
|
226
|
+
provider: spawn
|
|
227
|
+
- id: tool-workflow
|
|
228
|
+
name: '@deepseek-ai/dsh-tool-workflow'
|
|
229
|
+
- id: tool-ask-user
|
|
230
|
+
name: '@deepseek-ai/dsh-tool-ask-user'
|
|
231
|
+
- id: tool-todo
|
|
232
|
+
name: '@deepseek-ai/dsh-tool-todo'
|
|
233
|
+
config:
|
|
234
|
+
allowParallelInProgress: true
|
|
235
|
+
- id: tool-web
|
|
236
|
+
name: '@deepseek-ai/dsh-tool-web'
|
|
237
|
+
config:
|
|
238
|
+
fetch: true
|
|
239
|
+
searchTimeoutMs: 60000
|
|
240
|
+
- id: present
|
|
241
|
+
name: '@deepseek-ai/dsh-tool-present'
|
|
242
|
+
- id: tool-plugin-manager
|
|
243
|
+
name: '@deepseek-ai/dsh-plugin-manager/tools'
|
|
244
|
+
disabled: true
|
|
245
|
+
- id: tool-plugin-market
|
|
246
|
+
name: '@deepseek-ai/dsh-plugin-market/tools'
|
|
247
|
+
disabled: true
|
|
248
|
+
|
|
249
|
+
# P2 root replacement: stock providers yield to the transparent routers (local
|
|
250
|
+
# behavior preserved inside remote-vs-local-world). Tool, shell-dialect and
|
|
251
|
+
# preset rows are untouched; rollback = disable this bundle.
|
|
252
|
+
- id: subprocess
|
|
253
|
+
disabled: true
|
|
254
|
+
- id: fs-sandbox
|
|
255
|
+
disabled: true
|
|
256
|
+
- id: spill-local
|
|
257
|
+
disabled: true
|
|
258
|
+
- id: file-reference-local
|
|
259
|
+
disabled: true
|
package/icon.svg
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
|
2
|
+
<rect x="4" y="4" width="56" height="56" rx="12" fill="#1b2436"/>
|
|
3
|
+
<rect x="4" y="4" width="56" height="56" rx="12" fill="none" stroke="#4d6bfe" stroke-width="2.5"/>
|
|
4
|
+
<text x="12" y="42" font-family="monospace" font-size="26" font-weight="bold" fill="#7ee2a8">>_</text>
|
|
5
|
+
<circle cx="47" cy="22" r="6" fill="none" stroke="#e8b84b" stroke-width="2.5"/>
|
|
6
|
+
<path d="M51 26 L57 32" stroke="#e8b84b" stroke-width="2.5" stroke-linecap="round"/>
|
|
7
|
+
</svg>
|