Jack 7 days ago
parent 218ee31adb
commit 96b15ab6ca
  1. 97
      app.go
  2. 157
      dsh-plugins-installed.md
  3. 6
      main.go

@ -13,6 +13,7 @@ import (
"regexp" "regexp"
"runtime" "runtime"
"runtime/debug" "runtime/debug"
"strconv"
"strings" "strings"
"sync" "sync"
"time" "time"
@ -295,20 +296,15 @@ func (a *App) Stop() StartResult {
cmd := a.dshCmd cmd := a.dshCmd
a.mu.Unlock() a.mu.Unlock()
if cmd == nil || cmd.Process == nil { if cmd != nil && cmd.Process != nil {
// 没记录,直接 pkill 兜底
if pkill := lookPath("pkill"); pkill != "" {
_ = exec.Command(pkill, "-f", "dsh/lib/bin.js").Run()
}
} else {
_ = cmd.Process.Kill() _ = cmd.Process.Kill()
_, _ = cmd.Process.Wait() _, _ = cmd.Process.Wait()
} }
// 兜底 pkill,确保所有 dsh 子进程都死 // 兜底:把 dsh 整个进程树都杀(dsh 自己 + dsh-pet Electron helper + GPU/renderer/utility 等)
if pkill := lookPath("pkill"); pkill != "" { // 不杀全,dsh-pet 会在 EPIPE 时弹 JavaScript 错误弹窗。
_ = exec.Command(pkill, "-f", "dsh/lib/bin.js").Run() killDSHTree()
}
time.Sleep(500 * time.Millisecond) time.Sleep(500 * time.Millisecond)
a.mu.Lock() a.mu.Lock()
@ -363,9 +359,7 @@ func (a *App) stopDSH() {
if cmd != nil && cmd.Process != nil { if cmd != nil && cmd.Process != nil {
_ = cmd.Process.Kill() _ = cmd.Process.Kill()
} }
if pkill := lookPath("pkill"); pkill != "" { killDSHTree()
_ = exec.Command(pkill, "-f", "dsh/lib/bin.js").Run()
}
} }
// buildChildEnv 手动把 homebrew 路径塞进子进程 PATH。 // buildChildEnv 手动把 homebrew 路径塞进子进程 PATH。
@ -659,8 +653,81 @@ type InstallResult struct {
Output string `json:"output"` Output string `json:"output"`
} }
// CheckUpdate runs `npm view <pkg> version` to get the latest version on the registry. // killDSHTree kills all processes related to the dsh service:
// 不依赖 outdated — outdated 需要本地有 installed record,registry-only 查不到。 // - the dsh CLI itself (npm/node dsh/lib/bin.js)
// - dsh-pet Electron helper (main / renderer / gpu / utility / network)
// - any Electron app launched from ~/.dsh/electron
//
// 不只 kill 主进程: dsh-pet 还在跑时,EPIPE 会在 pipe 关闭后让它抛
// "Uncaught Exception" 弹窗,污染退出 UX。
func killDSHTree() {
pids := listDSHPids()
if len(pids) == 0 {
return
}
log.Printf("killDSHTree: %d pids to kill", len(pids))
for _, pid := range pids {
// kill -9 强杀,避免 dsh-pet 还在做 graceful shutdown 又触发 EPIPE
if err := exec.Command("kill", "-9", pid).Run(); err != nil {
log.Printf("killDSHTree: kill %s: %v", pid, err)
}
}
}
// listDSHPids 列出所有跟 dsh 相关的进程 PID(去重 + 排除自身)。
// 用 ps + grep 而不是 pgrep,以兼容 macOS 默认 PATH 不带 /usr/bin 的情况。
func listDSHPids() []string {
out, err := runQuiet("ps", "-axo", "pid=,command=")
if err != nil {
log.Printf("listDSHPids: ps err: %v", err)
return nil
}
seen := map[string]bool{}
var pids []string
self := os.Getpid()
for _, line := range strings.Split(out, "\n") {
line = strings.TrimSpace(line)
if line == "" {
continue
}
// 格式: "PID COMMAND..."
sp := strings.IndexByte(line, ' ')
if sp <= 0 {
continue
}
pidStr := line[:sp]
cmd := line[sp+1:]
// 跳过自身进程,免得自杀
if pid, _ := strconv.Atoi(pidStr); pid == self {
continue
}
// 匹配规则: dsh 启动的所有相关进程
if isDSHProcess(cmd) {
if !seen[pidStr] {
seen[pidStr] = true
pids = append(pids, pidStr)
}
}
}
return pids
}
// isDSHProcess 判断一条 ps command 是不是 dsh 相关的进程。
// 规则:
func isDSHProcess(cmd string) bool {
matches := []string{
"dsh/lib/bin.js", // dsh CLI 主进程
"dsh-pet", // dsh-pet Electron helper
".dsh/electron", // dsh 内置的 Electron runtime
"dsh-pet-electron-helper", // dsh-pet user-data-dir
}
for _, m := range matches {
if strings.Contains(cmd, m) {
return true
}
}
return false
}
func (a *App) CheckUpdate() UpdateInfo { func (a *App) CheckUpdate() UpdateInfo {
installed := "" installed := ""
if p := lookPath("dsh"); p != "" { if p := lookPath("dsh"); p != "" {

@ -0,0 +1,157 @@
# DSH 已装插件清单
> 统计时间:2026-09-11
> 跳过安装:hindsight(用户要求)
> 卸载:dsh-deep-whale(用户决定不要)
> **合计:24 个插件**(web profile 23 + dsh-tui profile 1)
---
## Web profile(23 个)
DSH Web GUI 与命令行共用的主 profile。
### 基础(1 个)
| # | 插件 | 版本 | 简介 |
|---|---|---|---|
| 1 | dshmarket | 1.46.0 | 插件市场,3000+ 社区插件、分类筛选、一键更新停用、主题切换与配置备份 |
### 界面与终端(1 个,dsh-TUI 装在 tui profile)
### 多智能体与上下文(2 个)
| # | 插件 | 版本 | 简介 |
|---|---|---|---|
| 2 | @nanmicoder/dsh-agent-teams | 0.1.18 | 多智能体团队编排:分配任务、互发消息、共享状态 |
| 3 | dsh-context | 0.50.0 | 上下文占用可视化仪表盘 + `/context` 命令 |
### 记忆系统(1 个)
| # | 插件 | 版本 | 简介 |
|---|---|---|---|
| 4 | dsh-mnemon | 0.5.8 | 本地优先持久记忆、语义召回 + 知识图谱、跨 Agent 共享记忆 |
### 视觉能力(3 个)
| # | 插件 | 版本 | 简介 |
|---|---|---|---|
| 5 | @liustack/modlens | 3.16.6 | 图片转结构化 JSON(OCR、版面、语义) |
| 6 | @anionex/dsh-vision-toolkit | 0.1.44 | 免 Key 视觉工具箱:图片问答、多图比较、长截图 OCR、像素对比 |
| 7 | dsh-vision-router | 2.1.6 | 免 Key 视觉链:看图问答、视觉定位、裁剪、OCR、抠图 |
### 搜索与文档(2 个)
| # | 插件 | 版本 | 简介 |
|---|---|---|---|
| 8 | @liustack/modsearch | 5.10.2 | 联网搜索带引用:搜网页、搜 X、返回结构化 JSON 证据 |
| 9 | @tt-a1i/archify-dsh | 0.1.0 | 自动生成架构图、工作流图、时序图、数据流图、生命周期图 |
### 开发辅助(4 个)
| # | 插件 | 版本 | 简介 |
|---|---|---|---|
| 10 | @linxin666/dsh-web-all | 0.3.21 | Web UI 全家桶:任务看板、Git 泳道图、技能中心、远程移动端 UI |
| 11 | dsh-better-sidebar | 0.19.1 | 侧边栏工作台:文件渲染编辑、终端、Git 变更、子代理活动 |
| 12 | dsh-chat-import | 0.11.2 | 把 13 家 coding agent 的对话历史导入成可续聊的 DSH 会话 |
| 13 | dsh-cost-meter | 1.3.1 | 会话与当日 API 费用统计、预算进度、官方余额显示 |
| 14 | @yejiming/dsh-data-agent | 0.1.5 | 数据库连接、SQL 工具、共享数据分析预设(Web + TUI 都支持) |
### 日常办公(8 个)
| # | 插件 | 版本 | 简介 |
|---|---|---|---|
| 15 | dsh-univer-office | 0.2.14 | 表格/文档/幻灯片/画布/多维表格,多 Agent 协作工作树 |
| 16 | deepseek-ippt | 0.1.2 | 原生幻灯片编辑器 + 模板目录,Agent 可创建/编辑/导出 PPT |
| 17 | @ethanyoq/dsh-invoice-downloader | 0.1.1 | 本地 IMAP 邮箱发票下载 → OCR → 归档 → Excel 汇总 |
| 18 | @xmanrui/dsh-im | 4.20.2 | 接入 9 种聊天软件(飞书/微信/钉钉/企业微信/QQ/Slack/Telegram/Discord/WhatsApp) |
| 19 | dsh-plugin-reactive-resume | 0.1.0 | 基于 Reactive Resume 的简历制作与投递 |
| 20 | dsh-pocket | 2.10.6 | 手机远程访问 DSH Web,扫码即用,局域网/公网 |
| 21 | @zhaoolee/dsh-notes | 0.1.2 | 把 Agent 输出保存到自托管 Notes 服务 |
| 22 | @cloudbase/dsh-plugin | 0.1.1 | 腾讯云 CloudBase:数据库、存储、认证、部署 |
### 外观与娱乐(1 个)
| # | 插件 | 版本 | 简介 |
|---|---|---|---|
| 23 | dsh-pet | 0.2.8 | 25 个透明动画、屏幕漫游、点击反应、拖拽交互的桌面宠物(当前:400px、右下角、仅浏览器) |
---
## DSH-TUI profile(1 个)
| # | 插件 | 版本 | 简介 |
|---|---|---|---|
| 1 | @deepseek-harness-tui/dsh-tui | 0.10.1 | Claude Code 风格全屏终端:鲸鱼顶栏、实时工作状态、token 速度、键盘控制 |
---
## 用户自定义配置
### 1. dsh-pet 用户配置 — `~/.dsh/dsh-pet/main-config.json`
- 单只宠物,蓝毛小女仆,**size: 400px**,**display: 仅浏览器(web)**
- 位置:右下角,距右/下各 24px
- 启用碎碎念(whisper)、工作状态联动(workStatus)、余额展示
### 2. 插件 patch 层 — `~/.dsh/profiles/web/cordis.patch.yml`
- 禁用了 `@linxin666/dsh-web-all` 内置的 `web-ui-pet` 子模块(避免和 dsh-pet 重复出现)
---
## 跳过的插件
- **hindsight**(@vectorize-io/hindsight-coding-agents)—— 用户主动要求跳过
## 已卸载的插件
- **dsh-deep-whale**(鲸鱼娘皮肤)—— 用户决定不要,已完整卸载(package.json + node_modules 全清)
---
## 复现安装的完整命令清单
```bash
# 基础必装
dsh plugin --profile web add dshmarket
# 界面与终端
dsh plugin --profile dsh-tui add @deepseek-harness-tui/dsh-tui
dsh plugin --profile web add @linxin666/dsh-web-all@latest
dsh plugin --profile web add dsh-better-sidebar
# 多智能体与上下文
dsh plugin --profile web add @nanmicoder/dsh-agent-teams
dsh plugin --profile web add dsh-context
# 记忆系统
dsh plugin --profile web add dsh-mnemon
# 视觉能力
dsh plugin --profile web add @liustack/modlens@3.16.6
dsh plugin --profile web add @anionex/dsh-vision-toolkit
npx @deepseek-ai/dsh plugin --profile web add dsh-vision-router
# 搜索与文档
npx -y @deepseek-ai/dsh plugin --profile web add @liustack/modsearch@latest
dsh plugin --profile web add @tt-a1i/archify-dsh@0.1.0
# 开发辅助
dsh plugin --profile web add dsh-chat-import
dsh plugin --profile web add github:Han-1413141/dsh-cost-meter#v1.3.1
dsh plugin --profile web add @yejiming/dsh-data-agent
# 日常办公
dsh plugin --profile web add dsh-univer-office
dsh plugin --profile web add deepseek-ippt
dsh plugin --profile web add @ethanyoq/dsh-invoice-downloader
dsh plugin --profile web add @xmanrui/dsh-im
dsh plugin --profile web add dsh-plugin-reactive-resume
dsh plugin --profile web add dsh-pocket -w
dsh plugin --profile web add @zhaoolee/dsh-notes
dsh plugin --profile web add @cloudbase/dsh-plugin
# 外观与娱乐
dsh plugin --profile web add dsh-pet
```

@ -27,6 +27,12 @@ func main() {
u := app.CheckUpdate() u := app.CheckUpdate()
fmt.Printf("installed=%q latest=%q hasUpdate=%v\n", fmt.Printf("installed=%q latest=%q hasUpdate=%v\n",
u.Installed, u.Latest, u.HasUpdate) u.Installed, u.Latest, u.HasUpdate)
fmt.Println("=== listDSHPids ===")
pids := listDSHPids()
fmt.Printf("found %d dsh-related pids:\n", len(pids))
for _, p := range pids {
fmt.Printf(" - %s\n", p)
}
fmt.Println("=== done, exiting ===") fmt.Println("=== done, exiting ===")
return return
} }

Loading…
Cancel
Save