🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

PR 工作台 kermanx/dshw

DeepSeek Harness
kermanx8 天前有提交已提供中文文档扫描:含敏感能力

个人开源项目,非 DeepSeek 官方产品。

38.6/100
综合分
11
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/27 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

该插件未发布到 npm,按作者文档从 GitHub 源安装即可(静态检查只覆盖 npm 路径,不代表插件不可用)。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add kermanx/dshw
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · other
装得上吗
本站已真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 8 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装

engines.node 要求 >=24.0.0,不满足 Node 22.19.0

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✗npm 包dshw(未发布到 npm,仅可源码安装)
✗Node 引擎要求 >=24.0.0 · 基线 Node 22.19 不满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/30 15:55:04

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 112 处,展示前 103 条)
  • 读取本地文件
    src/cli.ts:171
    await access(path)
  • 读取本地文件
    src/clone.ts:49
    await access(path)
  • 读取本地文件
    src/clone.ts:60
    const entries = await readdir(MANAGED_ROOT, { withFileTypes: true }).catch(() => [])
  • 读取本地文件
    src/clone.ts:68
    const names = await readdir(candidate, { withFileTypes: true }).catch(() => [])
  • 写入本地文件
    src/clone.ts:158
    await mkdir(CLONES_ROOT, { recursive: true })
  • 删除本地文件递归
    src/clone.ts:171
    await rm(destination, { recursive: true, force: true })
  • 写入本地文件
    src/clone.ts:189
    await mkdir(CLONES_ROOT, { recursive: true })
  • 删除本地文件递归
    src/clone.ts:199
    await rm(destination, { recursive: true, force: true })
  • 删除本地文件递归
    src/clone.ts:223
    await rm(clone.path, { recursive: true, force: true })
  • 写入本地文件
    src/dsh-runtime.ts:53
    await mkdir(dirname(HARNESS_RUNTIME_ROOT), { recursive: true })
  • 读取本地文件
    src/dsh-runtime.ts:63
    path: await realpath(HARNESS_RUNTIME_ROOT),
  • 删除本地文件递归
    src/dsh-runtime.ts:71
    await rm(HARNESS_RUNTIME_ROOT, { recursive: true, force: true })
  • 读取本地文件
    src/dsh-runtime.ts:81
    if ((await readFile(readyPath, 'utf8')).trim() === marker
  • 写入本地文件
    src/dsh-runtime.ts:93
    await writeFile(readyPath, `${marker}\n`)
  • 读取本地文件
    src/dsh-runtime.ts:107
    await access(path)
  • 读取本地文件
    src/dsh-runtime.ts:129
    const actual = await realpath(HARNESS_RUNTIME_ROOT)
  • 读取本地文件
    src/dsh-runtime.ts:135
    const info = await lstat(actual)
  • 读取本地文件
    src/dsh-runtime.ts:137
    await access(join(actual, '.git'))
  • 读取本地文件
    src/install.ts:36
    const sourceRoot = await realpath(DSHW_ROOT)
  • 读取本地文件
    src/install.ts:55
    validateInstallation(record, await realpath(DSHW_ROOT))
  • 写入本地文件
    src/install.ts:71
    mkdir(DATA_ROOT, { recursive: true }),
  • 写入本地文件
    src/install.ts:72
    mkdir(dirname(HARNESS_ROOT), { recursive: true }),
  • 写入本地文件
    src/install.ts:73
    mkdir(dirname(HARNESS_RUNTIME_ROOT), { recursive: true }),
  • 写入本地文件
    src/install.ts:74
    mkdir(CLONES_ROOT, { recursive: true }),
  • 写入本地文件
    src/install.ts:75
    mkdir(LOG_ROOT, { recursive: true }),
  • 写入本地文件
    src/install.ts:76
    mkdir(WORKER_ROOT, { recursive: true }),
  • 删除本地文件递归
    src/install.ts:111
    await rm(temporary, { recursive: true, force: true })
  • 读取本地文件
    src/install.ts:117
    path: await realpath(HARNESS_ROOT),
  • 读取本地文件
    src/install.ts:145
    const actual = await realpath(HARNESS_ROOT)
  • 读取本地文件
    src/install.ts:150
    const sourceInfo = await lstat(HARNESS_ROOT)
  • 读取本地文件
    src/install.ts:152
    const info = await lstat(actual)
  • 写入本地文件
    src/service.ts:141
    await mkdir(CLONES_ROOT, { recursive: true })
  • 写入本地文件
    src/service.ts:2104
    await appendFile(join(LOG_ROOT, `${handle.runId}.log`), `${line}\n`, 'utf8').catch(() => {})
  • 发起网络请求
    src/service-manager.ts:180
    response = await fetch(`http://${HOST}:${PORT}/api/state`, { signal: AbortSignal.timeout(8_000) })
  • 发起网络请求
    src/service-manager.ts:196
    response = await fetch(`http://${HOST}:${PORT}${path}`, {
  • 发起网络请求
    src/service-manager.ts:226
    const response = await fetch(`http://${HOST}:${PORT}/api/identity`, { signal: AbortSignal.timeout(1_000) })
  • 读取本地文件
    src/service-manager.ts:245
    info = await lstat(SERVICE_PLIST)
  • 读取本地文件
    src/service-manager.ts:251
    const owner = parseServiceOwner(await readFile(SERVICE_PLIST, 'utf8'))
  • 写入本地文件
    src/service-manager.ts:294
    await mkdir(dirname(SERVICE_PLIST), { recursive: true })
  • 写入本地文件
    src/service-manager.ts:296
    await writeFile(temporary, contents, { mode: 0o600 })
  • 写入本地文件
    src/service-manager.ts:297
    await rename(temporary, SERVICE_PLIST)
  • 读取本地文件
    src/service-manager.ts:321
    return await realpath(path)
  • 执行外部命令来自配置/变量
    src/util.ts:43
    const child = spawn(command, args, {
  • 读取本地文件
    src/util.ts:129
    return JSON.parse(await readFile(path, 'utf8')) as T
  • 写入本地文件
    src/util.ts:137
    await mkdir(dirname(path), { recursive: true })
  • 写入本地文件
    src/util.ts:139
    await writeFile(temporary, `${JSON.stringify(value, null, 2)}\n`)
  • 写入本地文件
    src/util.ts:140
    await rename(temporary, path)
  • 读取本地文件
    src/repos.ts:9
    await access(path)
  • 写入本地文件
    src/repos.ts:38
    await mkdir(dirname(root), { recursive: true })
  • 读取本地文件
    src/git.ts:51
    return await realpath(result.stdout.trim())
  • 读取本地文件
    src/git.ts:56
    return await realpath(resolve(cwd, result.stdout.trim()))
  • 写入本地文件
    src/state.ts:36
    await mkdir(dirname(EVENT_LOG_FILE), { recursive: true })
  • 读取本地文件
    src/state.ts:39
    logSize = (await stat(EVENT_LOG_FILE)).size
  • 写入本地文件
    src/state.ts:43
    await writeFile(EVENT_LOG_FILE, state.events.map(record => `${JSON.stringify(record)}\n`).join(''))
  • 写入本地文件
    src/state.ts:77
    this.#logWriteChain = this.#logWriteChain.then(() => appendFile(EVENT_LOG_FILE, `${JSON.stringify(record)}\n`))
  • 读取本地文件
    src/state.ts:127
    const size = (await stat(path).catch(() => ({ size: 0 }))).size
  • 写入本地文件
    src/worker-config.ts:199
    await writeFile(this.#secretFile, `${lines.join('\n')}${lines.length === 0 ? '' : '\n'}`, { mode: 0o600 })
  • 写入本地文件
    src/worker-config.ts:200
    await chmod(this.#secretFile, 0o600)
  • 读取本地文件
    src/worker-config.ts:234
    return parseEnv(await readFile(filename, 'utf8')) as Record<string, string>
  • 读取本地文件
    src/dsh.ts:107
    const template = await readFile(join(DSHW_ROOT, 'prompts', 'review.md'), 'utf8')
  • 读取本地文件
    src/dsh.ts:121
    const template = await readFile(join(DSHW_ROOT, 'prompts', filename), 'utf8')
  • 写入本地文件
    src/dsh.ts:147
    await mkdir(directory, { recursive: true })
  • 写入本地文件
    src/dsh.ts:148
    await mkdir(controlRoot, { recursive: true, mode: 0o700 })
  • 写入本地文件
    src/dsh.ts:149
    await chmod(controlRoot, 0o700)
  • 写入本地文件
    src/dsh.ts:153
    await writeFile(patchPath, [
  • 写入本地文件
    src/dsh.ts:213
    await writeFile(plistPath, plist, { mode: 0o600 })
  • 读取本地文件
    src/dsh.ts:297
    const source = await readFile(join(LOG_ROOT, `${runId}.log`), 'utf8')
  • 读取本地文件
    src/dsh.ts:398
    const stderr = (await readFile(join(dirname(handle.requestPath), 'worker.stderr.log'), 'utf8')).trim()
  • 写入本地文件
    src/dsh.ts:414
    await mkdir(LOG_ROOT, { recursive: true })
  • 读取本地文件
    src/dsh-launch-env.ts:31
    fallback = parseEnv(readFileSync(userEnvFile, 'utf8'))
  • 写入本地文件
    src/codex.ts:42
    await mkdir(directory, { recursive: true })
  • 写入本地文件
    src/codex.ts:43
    await mkdir(controlRoot, { recursive: true, mode: 0o700 })
  • 写入本地文件
    src/codex.ts:44
    await chmod(controlRoot, 0o700)
  • 写入本地文件
    src/codex.ts:79
    await writeFile(plistPath, plist, { mode: 0o600 })
  • 发起网络请求
    src/codex-runtime.ts:19
    client.request('config/read', { cwd, includeLayers: false }),
  • 发起网络请求
    src/codex-runtime.ts:72
    const response = await client.request('model/list', { limit: 100, ...(cursor === undefined ? {} : { cursor }) })
  • 读取本地文件
    src/codex-runtime.ts:107
    await access(candidate, constants.X_OK)
  • 执行外部命令来自配置/变量
    src/codex-app-server.ts:22
    this.#child = spawn(executable, ['app-server', '--stdio'], { cwd, env: process.env, stdio: ['pipe', 'pipe', 'pipe'] })
  • 发起网络请求
    src/codex-app-server.ts:38
    await this.request('initialize', { clientInfo: { name: 'dshw', title: 'dshw', version: '0.1.0' } })
  • 发起网络请求
    plugin/src/data.ts:121
    const response = await fetch(`${baseUrl}/api/state`)
  • 写入本地文件
    src/codex-session-worker.ts:89
    await mkdir(dirname(request.controlSocketPath), { recursive: true })
  • 删除本地文件
    src/codex-session-worker.ts:90
    await rm(request.controlSocketPath, { force: true })
  • 写入本地文件
    src/codex-session-worker.ts:91
    const eventStream = createWriteStream(request.eventLogPath, { flags: 'a' })
  • 写入本地文件
    src/codex-session-worker.ts:92
    const outputStream = createWriteStream(request.outputLogPath, { flags: 'a' })
  • 写入本地文件
    src/codex-session-worker.ts:134
    await writeFile(join(dirname(request.resultPath), 'final.txt'), `${output}\n`)
  • 删除本地文件
    src/codex-session-worker.ts:143
    await rm(request.controlSocketPath, { force: true })
  • 发起网络请求
    src/codex-session-worker.ts:200
    const response = await client.request('turn/start', codexTurnStartParams(threadId, prompt, request.worker))
  • 发起网络请求
    src/codex-session-worker.ts:218
    await client.request('turn/steer', {
  • 发起网络请求
    src/codex-session-worker.ts:229
    await client.request('turn/interrupt', { threadId, turnId: activeTurnId })
  • 发起网络请求
    src/codex-session-worker.ts:234
    const threadResponse = await client.request('thread/start', codexThreadStartParams(request))
  • 发起网络请求
    src/codex-session-worker.ts:258
    await client.request('turn/interrupt', { threadId, turnId: activeTurnId }).catch(() => {})
  • 写入本地文件
    src/codex-session-worker.ts:275
    await chmod(request.controlSocketPath, 0o600)
  • 写入本地文件
    src/dsh-session-plugin.ts:104
    await mkdir(dirname(request.controlSocketPath), { recursive: true })
  • 删除本地文件
    src/dsh-session-plugin.ts:105
    await rm(request.controlSocketPath, { force: true })
  • 写入本地文件
    src/dsh-session-plugin.ts:106
    const eventStream = createWriteStream(request.eventLogPath, { flags: 'a' })
  • 写入本地文件
    src/dsh-session-plugin.ts:107
    const outputStream = createWriteStream(request.outputLogPath, { flags: 'a' })
  • 写入本地文件
    src/dsh-session-plugin.ts:175
    await writeFile(join(dirname(request.resultPath), 'final.txt'), `${output}\n`)
  • 删除本地文件
    src/dsh-session-plugin.ts:290
    await rm(request.controlSocketPath, { force: true })
  • 写入本地文件
    src/dsh-session-plugin.ts:305
    await chmod(request.controlSocketPath, 0o600)
  • 读取本地文件
    src/dsh-session-plugin.ts:332
    for (const group of await readdir(packagesRoot, { withFileTypes: true })) {
  • 读取本地文件
    src/dsh-session-plugin.ts:335
    for (const candidate of await readdir(groupRoot, { withFileTypes: true })) {
  • 读取本地文件
    src/dsh-session-plugin.ts:339
    const manifest = JSON.parse(await readFile(join(directory, 'package.json'), 'utf8')) as { name?: string; main?: string }
  • 发起网络请求
    src/worker-progress.ts:20
    await fetch(progressUrl, {
扫描于 2026/11/3(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

界面预览

1 张 · 点击查看大图

功能亮点

  • PR工作流

DeepSeek Harness 的 PR 工作流插件

README

由 DeepSeek 最新模型翻译生成
dshw 个人开源项目,非 DeepSeek 官方产品。 dshw 是 DeepSeek Harness 的本机 PR 工作流工具,以看板形式嵌入 Harness Web。它会自动追踪你创建的、以及 assign 给你的 PR,克隆到本地独立目录,持续同步目标分支、监控 CI,并在需要时用 dsh Agent 自动处理冲突合并、修复 CI 失败、解决 review 评论。 功能 - Pull requests:按仓库列出你创建或 assign 给你的 open PR,展示 CI、review、合并与同步状态;冲突、落后、失败检查都有一键或自动处理入口。stacked PR 以 target master 的 PR 为顶层根节点,所有直接和间接依赖它的 PR 按深度优先顺序连续排列,统一缩进一层;其他 PR 保持顶层 - Reviews:列出待你 review 的 PR - Git:仓库分支与提交历史可视化 - Jobs:后台任务列表与详情,运行中的任务可 steer、暂停、终止 - Logs:服务与任务日志 - Settings: - Repos:选择要监控的 GitHub 仓库(勾选并排序,顺序即各页展示顺序) - Workers:配置 dsh / Codex 等执行器 - System:更新 dshw、同步主仓库、清理过期 worktree
展开完整文档(README 剩余 1 节)
dshw

个人开源项目,非 DeepSeek 官方产品。

dshw 是 DeepSeek Harness 的本机 PR 工作流工具,以看板形式嵌入 Harness Web。它会自动追踪你创建的、以及 assign 给你的 PR,克隆到本地独立目录,持续同步目标分支、监控 CI,并在需要时用 dsh Agent 自动处理冲突合并、修复 CI 失败、解决 review 评论。

功能

- Pull requests:按仓库列出你创建或 assign 给你的 open PR,展示 CI、review、合并与同步状态;冲突、落后、失败检查都有一键或自动处理入口。stacked PR 以 target master 的 PR 为顶层根节点,所有直接和间接依赖它的 PR 按深度优先顺序连续排列,统一缩进一层;其他 PR 保持顶层
- Reviews:列出待你 review 的 PR
- Git:仓库分支与提交历史可视化
- Jobs:后台任务列表与详情,运行中的任务可 steer、暂停、终止
- Logs:服务与任务日志
- Settings:
- Repos:选择要监控的 GitHub 仓库(勾选并排序,顺序即各页展示顺序)
- Workers:配置 dsh / Codex 等执行器
- System:更新 dshw、同步主仓库、清理过期 worktree

支持同时监控多个仓库;新增仓库后,它的 PR 会被自动发现并展示。

看板会跟随所在面板的宽度排版:窄侧栏将视图选择和工具按钮收在一行,PR 以标题、分支和状态摘要呈现,点击状态行展开具体操作;宽面板保留多列表格。「展开看板」可临时放大整个工作区;在窄侧栏打开 Review diff 时也会自动展开,返回后恢复原列表与滚动位置。样式尺寸参考 VS Code Classic 的 SidebarTitle、ActionBar、SelectBox 和 Pane。

安装

在「DS 内部插件市场」安装「DSHW 工作看板」即可加载看板插件。看板连接本机 http://127.0.0.1:7849 服务;仍需按下述步骤在 macOS 上安装并启动 dshw daemon。

前置条件

- macOS
- Node.js 24+
- pnpm
- Git
- GitHub CLI,并已运行 gh auth login
- DeepSeek Harness

步骤

git clone https://github.com/kermanx/dshw.git
cd dshw
pnpm install
pnpm dshw start # 初始化并后台启动服务

首次启动会准备托管仓库与运行时、构建插件、注册 LaunchAgent,可能需要几分钟。

然后把看板装进你的 dsh:

dsh plugin --profile web add "$PWD"

重启你的 dsh Web 服务(停掉后重新运行 dsh web),刷新页面即可在左侧栏的标准面板列表看到看板入口。需要支持 sidebar.panellist 与 main 面板接口的新版 Harness。插件列表在启动时组装,新增插件必须重启 dsh web 才会生效。

使用要点

- 看板数据由本机后台服务实时提供,无需手动刷新
- 服务默认监听 127.0.0.1:7849,可用环境变量 DSHW_PORT 修改;换端口后在看板的连接失败界面修改服务地址即可
- 更新:git pull 后运行 pnpm dshw restart 即可。
- 卸载:dsh plugin --profile web remove dshw,再重启 dsh web

Worker 配置

Settings 的 Workers 页可以维护多个执行器配置并拖动排序,第一项即默认执行器。支持:

- dsh:填写 Provider、模型、API Key 等即可使用
- Codex:使用本机 Codex CLI 与登录状态
- Claude Code:仅保留入口,尚未接入

直接输入的 API Key 不会出现在配置文件里,而是以受限权限单独保存。PR 操作按钮左键使用默认执行器,右键可为本次任务选择其他执行器。

任务控制

运行中的任务可以:

- Steer:在下一个 step 前插入指令
- 暂停 / 继续:暂停当前 turn,输入新指令后继续同一个任务
- 终止:结束任务

daemon 重启后会重新接管运行中的任务。

安全与运维

- dshw 只注册当前用户的 LaunchAgent,不使用 sudo,不创建系统级服务
- 所有数据都在仓库的 .dshw/ 目录内(已被 Git 忽略)
- worker 使用独立的运行环境,不会写入你的全局配置
- 每份 clone 有独立身份;不同安装互不干扰,冲突操作会明确拒绝

常用命令

pnpm dshw start # 初始化并启动
pnpm dshw stop # 停止
pnpm dshw restart # 构建插件并重启
pnpm dshw status # 查看状态
pnpm dshw code # 打开当前分支对应的 worktree
pnpm dshw doctor # 检查环境

开发

pnpm check # 类型检查 + 构建 + 测试

修改正式服务代码后运行 pnpm dshw restart。
预览分享卡片长什么样 ↓kermanx/dshw
分享 · DeepSeek Harness Hub
kermanx/dshw

个人开源项目,非 DeepSeek 官方产品。

回到顶部