packages/dsh-task-board
zhu1090093659/dsh-web侧边栏多列任务看板:卡片交给真实 DSH 智能体会话执行,支持 cron 定时(Host 侧到点执行,关浏览器也生效)。
右侧栏文档预览的可写一半:编辑并原地保存任意文本文件。每次保存都带上「打开时的那一版」,编辑期间磁盘上的文件被改过就停下来问,不静默覆盖;预览工具栏多出「编辑」按钮和两步确认的「删除」按钮。另有一个「文件编辑」侧栏工具,自带文件树:新建、改名 / 移动、复制 / 剪切 / 粘贴(含把系统剪贴板里的文件粘进工作区)、删除、拖拽整理。两档文档渲染器共覆盖 107 个纯文本、配置与源码扩展名,其中第二档只作为「打开方式」出现,官方 Markdown 排版与代码高亮仍是默认视图。变更走插件自己的 Host 路由,过连接信任围栏、工作区包含性检查与沙箱策略三道闸。
在 DSH Web GUI 的右侧栏里直接把工作区文件改掉:官方文档预览注册的 Markdown / 代码 / 图片 / PDF / Office 渲染器全部只读,读文件的 Remote 命名空间 @deepseek-ai/dsh-api-workspace-files 也明确写着 *"The service exposes no mutation operation."*, 这个插件补上写与删的那一半 —— 可编辑的正文、保存按钮、未保存状态与冲突处理,预览头部 的「🗑 删除」按钮(两次点击确认),外加一个自带文件树的右侧栏工具 「文件编辑」:新建、 改名 / 移动、复制 / 剪切 / 粘贴、删除、拖拽整理,都在 GUI 里做完 —— 包括把系统剪贴板里复制好的 文件直接粘进工作区。它们全部打到本插件自己的 Host 路由。
与「用终端 / 让 Agent 改」的差别不是快慢,而是谁在改:人在 GUI 里改完点保存, 版本闸记得住「你读到的是哪一版」,磁盘中途被模型改过就停下来问,不静默覆盖; 删除同样带版本闸 —— 你确认期间文件被改过就停下来,要删得再点一次「仍然删除」。
四条实现约束的来龙去脉)。
已发布到 npm:@dongasai/dsh-editor, 当前 1.2.0 —— 与 git tag v1.2.0 是同一份内容(tarball shasum 一致)。最省事的装法就一条:
dsh plugin --profile web add @dongasai/dsh-editor两步:装插件 → 在右侧栏打开一个文件。
四种装法,按场景选。都走同一条 pnpm 路径(@deepseek-ai/dsh-plugin-manager/operations, 共用一把 profile 写锁),装完都会出现在侧栏「插件」页的已安装列表里。
都不需要手写注册行:本包在 package.json 里声明了 dsh.bundle.patch,只要这个 bundle 被选中,生效的那一行就来自本包自带的 cordis.patch.yml。命令行(方式二、 三、四)安装会顺带把它选进 dsh.profile.bundles;Web 上(方式一)是装完点 立即启用才选中 —— 不点就只是「装着但没启用」。
本包已发布到 npm(@dongasai/dsh-editor),所以 spec 有三种写法:包名(走 registry,最省事)、 git 地址、本地路径。包名这条最稳:npm 上的 tarball 就是同名 tag 的内容,版本号与 tag 逐字对应。
DSH Web → 左侧栏插件 → 添加插件 → 填入本仓库绝对路径 /data/ai/dsh/dsh_editor (或下面的 git 地址)→ 安装 → 装完点立即启用。
(镜像只提供注册表里的包与依赖,不代替 GitHub 仓库下载)。
dsh plugin --profile web add @dongasai/dsh-editor
# 钉版本
dsh plugin --profile web add @dongasai/dsh-editor@1.2.0registry.npmmirror.com 是镜像,与 npmjs 有同步延迟:刚发的版本可能要先等一会儿才装得到,急用就临时指定 npm_config_registry=https://registry.npmjs.org/ dsh plugin --profile web add @dongasai/dsh-editor。
index.js / client.js / cordis.patch.yml / locale/*.json /icon.svg,外加 README 与 IMPLEMENTATION.md),没有任何构建步骤,装完即用。
@1.2.0),不是 tag 名;两者逐字对应(v1.2.0 ↔ 1.2.0)。dsh plugin --profile web add github:dongasai/dsh_editor
# 或
dsh plugin --profile web add git+https://github.com/dongasai/dsh_editor.gitdsh plugin --profile 把参数转发给该 profile 目录里的 pnpm。装进来的是 副本:之后改本仓库代码不影响已装的副本(想边改边用就走方式四)。
--profile 必填(不写直接报 required option '--profile not specified');web 换成你要装进的 profile。
#,例如git+https://github.com/dongasai/dsh_editor.git#v1.2.0(tag / 分支 / commit 都行)。 本仓库当前 tag 是 `v1.2.0`,对应 package.json 的 1.2.0 —— 不带 # 就跟 main 走, 每次装到的都可能是新代码(本机开发用方式四的 link:,不受影响)。
git+ssh://git@github.com/dongasai/dsh_editor.git(需已配好 SSH key),或先把 HTTPS 凭据配好。
git@github.com:owner/repo.git 这种 scp 写法不会被认成git spec,pnpm 会把它当路径,装出一条指向不存在目录的 link: 死链(本机 profile 里就留着一条 这样的残留:依赖名 git → link:github.com:yangshen830-eng/dsh-editor.git,node_modules/git 是断链)。CLI 识别 git spec 的判定也是这个:/^git+|^github:|.git(?:#|$)/。
prepare 等依赖构建脚本;本包没有任何构建步骤(client.js 是手写的浏览器bundle,由 Host 直接读盘发出),不会遇到。
判定不兼容会回滚 package.json 与 pnpm-lock.yaml 并打印 allow-version 命令。本包没有声明 任何 DSH peer 依赖,不会触发。
dsh plugin --profile web add link:/data/ai/dsh/dsh_editor装成 link: 依赖,代码改动立刻是「已装的那份」—— 适合边改插件边用。
index.js):要重启 Harness 才生效(见「已知边界」)。client.js):刷新页面即可(bundle 每次请求都从磁盘现读,按内容 revision 换 URL),不需要重启。
Config.listConfigs(name: "@dongasai/dsh-editor")里能看到行、且 enabled 为真,即已生效。 再新开一个会话(或重启 Harness)让插件加载,然后按第 2 步在右侧栏验证。
.yaml .yml .toml .ini .cfg .conf .config .env .properties .lock` —— 官方对这些文件本来也只有只读纯文本 / 代码预览,没有不可替代的能力,所以直接给编辑器 当默认视图,点开就能改。
.md .ts .py .sh .html .css .sql .csv …):默认仍是官方的排版 /高亮预览。要编辑,点预览工具栏上的「✎ 编辑」按钮 —— 它用编辑器页签顶掉这张预览 页签(同一个面板、同一个位置);该文件的编辑器页签已经开着时只聚焦它。也可以走 「打开方式」下拉选「编辑器」,那是就地换渲染器,选择按标签页记住。
变成「确认删除」,第二下才真的删 —— 中间那几秒里如果你不点,它会自己变回「删除」。 删掉的文件不进回收站,页签会随之关掉,文件树里那一行也会消失(树自己盯着变更)。
它把「当前文件 + 选区所在行」拼成 @路径#L行号(选中多行是 @路径#L起-止,没有选区就是 光标所在行)插进当前会话的对话输入框,插在输入框光标上次所在的位置。工作区内的文件按 相对路径写,工作区外用绝对路径;路径带空格时按官方 grammar 加引号。插进去的是普通文本 (不是文件芯片),模型侧按 @…#L 引用语法解析。
右侧栏的加号 / 引导页里有一张「文件编辑」卡片(快捷键 Ctrl/Cmd+Alt+E,可在快捷键设置里改)。 它开一个自带文件树的页签:
想做什么 · 怎么做 看目录 · 点目录行展开 / 收起;条目默认「目录在前、再按名字」(工具条上的排序按钮可切成「按类型」,或关掉「目录优先」);一路只有一个子目录的链会折成一行(a/b/c,点它展开链尾);名字以点开头的条目淡显;目录变了会自己刷新(订阅了官方变更流) 找操作 · 每行行尾有常显的「⋯」(不用悬停),行上也有悬停出现的图标;右键任意一行是一份完整菜单 打开文件 · 单击文件行 → 在同一栏里开本插件的页签(面板自己不消失):文本进编辑器页签,图片进图片预览页签(见下) 新建 · 工具条上的「新建文件 / 新建文件夹」落在当前选中的目录(选中文件时是它所在的目录);也可以点某个目录行上的 + 改名 / 移动 · 四个入口:行上铅笔(悬停出现)、行尾常显的「⋯」菜单、右键菜单、工具条上的铅笔(作用于选中行)。输入框里回车提交,名字里带 / 就是搬到子目录(a/b.md);键盘党按 F2 创建副本 · 文件行上的复制按钮:同目录生成「xxx 副本」,重名自动往后编号;目录不支持复制 复制 / 剪切到剪贴板 · 「⋯」或右键菜单里的「复制到剪贴板」(只收文件)与「剪切」(文件与目录都行);键盘党在树上按 Ctrl/Cmd+C / Ctrl/Cmd+X。剪贴板贴着面板底部显示,带一个「清空」 粘贴 · Ctrl/Cmd+V 贴系统剪贴板里的文件(在系统文件管理器里复制一个文件,回面板按一下就行);菜单 / 工具条上的「粘贴」也贴同一份。有内部剪贴板时优先贴内部那一份:复制过来的是「再复制一份」(重名自动编号、剪贴板留着可以连贴),剪切过来的是移动(贴完剪贴板清空) 复制路径 · 「⋯」或右键菜单里的「复制路径」(这个条目的绝对路径)与「复制相对路径」(相对工作区根,如 sub/keep.txt)。成功时面板上方亮一条一次性提示(几秒后自己消失);写剪贴板失败时亮同一行提示但不会自动消失(带「取消」点掉) 在终端打开 · 「⋯」或右键菜单里的「在终端打开」:在右侧栏开一个终端页签,等它的 shell 一变得可写就替你敲一条 cd ''(目录行 = 它自己,文件行 = 它所在的目录),终端里能看到这一行。见下面「为什么是敲一条 cd」 删除 · 行上的垃圾桶按钮 → 确认条再点一次。空目录一次确认;非空目录确认条会报条目数,按钮是「递归删除」 拖拽 · 把行拖到目录行上松手 = 搬进它;拖到文件行上 = 搬到它所在的目录(所以拖到根下任意一个文件行就是搬到根);一开始拖,工具条下面会亮出「工作区根目录」落点条,丢到它上面(或树正文的空白处)就是搬到根目录。拖到自己身上、拖回原地、把目录拖进自己的子树都不接受 多选 · 每行左侧有一颗常显的勾选框 —— 点它就是多选的主入口(不用知道快捷键)。也可以 Ctrl/Cmd+点切换、Shift+点按可见行顺序取一段(这两种都不打开文件)、Ctrl/Cmd+A 全选可见行、Esc 或点空白处清空。普通单击只移动光标、不产生勾选。勾了至少一项就在工具条下方出现批量条:最左是全选框(全选 ✓ / 半选 −),后面是已选 N 项 / 复制路径 / 删除 / 清空 批量删除 · 批量条上的「删除」→ 一次确认条(里面有目录时会写明「会连内容一起删」)→ 逐条串行删除,每条都带自己的版本闸。部分失败时失败项留在选择里,并亮一条带「重试删除」的横幅(重试会重新取一遍基线,所以磁盘变过的那几条也能接着处理)
为什么是「敲一条 cd」而不是「让终端在该目录启动」:官方终端接口 (remote.terminal.create)只有 shellPath,没有 cwd —— 侧边栏终端一律从会话工作区根 起步,页签参数也只有 terminalId / shellPath。所以这个动作是「开页签 → 等它可写 → 替你敲一条 cd ''」:你能在终端里看到这行命令,之后就在那个目录里了。如果这个部署里没有侧边栏 终端(终端页签类型没注册),菜单项会直接说明,不会装作开了个终端。
删除同样带版本闸:你点「删除」的瞬间它会记下这个条目的版本,等你点确认时如果磁盘上已经变过 (模型或别的工具动过),Host 会拒绝,确认条上改说「这个条目在确认期间变过,没有删除」并把按钮换成 「仍然删除」——要删得再点一次。
批量删除刻意没有「整批仍然删除」这种口子:一次点下去就把 N 个条目全部无条件推平,比逐条重试 危险得多。所以部分失败时它只做两件事 —— 把失败项留在选择里、给一条带「重试删除」的横幅;重试会 重新取每一条的基线,于是「确认期间被改过」的那几条也能在你看过之后删掉。
排序与折叠都不改数据:排序只改渲染顺序(换一次排序键不会重新读盘);折叠只用已经读过的 层级 —— 为了知道「这一层是不是只有一个子目录」,它会对可见层级里那些还没读过的目录各探一次 (每次挂载最多 64 个,链一旦不是「唯一子目录」就停),但不会给预读到的目录订阅变更:折叠标签 只是显示,真要内容还是得展开(展开时才订阅)。
切走再回来不丢版面:这个面板注册成 keepMounted,点开一个文件(切到编辑器页签)再点回来, 展开的目录、滚动位置、光标都还在;以前每次回来都会重挂、缩回根一层。
面板最底部固定一行插件信息(工作区文件编辑器 · v1.1.0 这样),鼠标放上去显示插件的介绍; 标题与版本号是从 Host 的插件清单里现读的(按包名认领自己那一行),所以升级插件后这里自己就变, 不需要谁去改客户端;部署里没有插件管理器(读不到清单)时只显示包名 @dongasai/dsh-editor, 关掉面板重开一次会再试一遍。 「没有工作区根」那种情况下页脚同样在底部。
改一个字,底部状态条应当从「已与磁盘同步」变成「未保存的修改」并且「保存」按钮变成品牌色; 点保存后变「已保存」,用 cat / git diff 看磁盘,内容确实变了。看不到编辑器时按「排错」表逐条对。 在「文件编辑」面板里新建一个文件,ls 应当立刻看得到它 —— 面板自己的列表也会跟着刷出来。
在「文件编辑」面板里单击图片,开的是本插件的图片预览页签(不是文本编辑器 —— 那会得到 「这个文件不是 UTF-8 文本」):
时超出部分靠滚动看)。
宽×高 与 MIME 类型。tiff / heic 这类,本插件不内置解码器):明确说「浏览器解不开这个格式」,并给出「重试」与「用编辑器打开」两个出路(后者对 svg 看源码很顺手)。
官方那个图片渲染器完全不动:本插件只补自己的入口(「文件编辑」面板的单击)。官方文件树、 官方的自动打开、官方右上角的「打开方式」下拉都还走官方图片预览;图片也不进「哪些文件能进 编辑器」那两张表。
状态条会显示「已与磁盘同步 / 未保存的修改 / 保存中… / 已保存」,紧跟着这个文件的相对路径 (与右键「复制相对路径」同一份口径:工作区内显示成 docs/README.md,工作区外的文件自动退回绝对 路径);太长时从头部截断以保住文件名(…/that/going/README.md),完整绝对路径在鼠标悬停的 title 与 [data-workspace-editor-status-path] 上。标题栏右侧是「重新加载」 (丢弃本地修改、重读磁盘)与「保存」。编辑器页签里多一个「换行:开 / 关」(页签窄,默认开)。 图片预览那一面也显示同样的路径(同一份实现、同一个锚点)。
正文里右键有一份菜单,三组:剪切 / 复制 / 粘贴 / 全选,分隔线后的 「发送到 DSH 输入框」(禁用时把鼠标放上去会说明原因),再一条分隔线后的 「复制路径」「复制相对路径」「在终端打开」 —— 作用对象是正在编辑的这个文件: 路径优先用读盘拿到的绝对路径,「相对」是相对会话工作区根;「在终端打开」打开的是它所在的 目录(文件在根目录下就是工作区根)。这三项与「文件编辑」面板里的同名菜单项共用同一份实现 (含失败话术),只是横幅渲染在编辑器自己的位置。
正文带语法高亮:输入框的字是透明的(只留光标与选区),看得见的字形来自它底下那层等宽文本, 颜色用主题的 --shiki-* 令牌(与官方代码预览同一套配色,亮 / 暗主题都跟着走)。语言按后缀 判:JS / TS / JSON / HTML 系(含 Vue、Svelte、XML、SVG)/ CSS 系(含 SCSS、LESS)/ Markdown / YAML / INI 系(含 TOML、.env、properties)/ Python / Shell 系(含 PowerShell、批处理)/ SQL / diff / patch,以及 C 家族(C/C++/Java/C#/Go/Rust/Kotlin/Swift/PHP 等,按近似的关键字表上色); 认不出的后缀(.txt、Dockerfile、没有后缀的文件)按纯文本显示。
两个上限与一个前提:超过 256 KiB 字符或 2 万令牌就不上色(正文照旧能编辑、能存), 上色用 Custom Highlight API(Chrome 105+ / Safari 17.2+ / Firefox 140+),不支持它的浏览器按 纯文本显示。当前状态可以直接在元素上看:[data-workspace-editor-highlight] 是 on / plain / over-limit / unsupported。取舍与实测代价见 IMPLEMENTATION.md。
「✎ 编辑」按钮换的是页签而不是就地切换渲染器:预览用哪个渲染器由文档预览自己的