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

任务工作区 Zilong6666/dsh-task-workspace

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

为每个任务建立独立文件夹并维护进度文件

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

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

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Zilong6666/dsh-task-workspace
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

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

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

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

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

可执行外部命令读写/删除本地文件
查看扫描证据(共 72 处,展示前 36 条)
  • 读取本地文件
    src/index.mjs:64
    if (existsSync(file)) {
  • 读取本地文件
    src/index.mjs:66
    Object.assign(merged, JSON.parse(readFileSync(file, 'utf8')));
  • 写入本地文件
    src/index.mjs:84
    mkdirSync(join(file, '..'), { recursive: true });
  • 写入本地文件
    src/index.mjs:86
    writeFileSync(file, `${JSON.stringify({ ...current, ...patch }, null, 2)}\n`, 'utf8');
  • 读取本地文件
    src/index.mjs:303
    if (existsSync(file)) {
  • 读取本地文件
    src/index.mjs:304
    const body = readFileSync(file, 'utf8');
  • 读取本地文件
    src/index.mjs:359
    buckets = readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory());
  • 读取本地文件
    src/index.mjs:367
    if (!existsSync(file)) continue;
  • 写入本地文件
    src/index.mjs:587
    writeFileSync(progressFile, content, 'utf8');
  • 读取本地文件
    src/store.mjs:166
    if (!existsSync(path)) mkdirSync(path, { recursive: true });
  • 写入本地文件
    src/store.mjs:166
    if (!existsSync(path)) mkdirSync(path, { recursive: true });
  • 读取本地文件
    src/store.mjs:186
    return existsSync(path) && statSync(path).isDirectory();
  • 读取本地文件
    src/store.mjs:186
    return existsSync(path) && statSync(path).isDirectory();
  • 读取本地文件
    src/store.mjs:202
    if (existsSync(candidate) && statSync(candidate).isFile()) return candidate;
  • 读取本地文件
    src/store.mjs:202
    if (existsSync(candidate) && statSync(candidate).isFile()) return candidate;
  • 读取本地文件
    src/store.mjs:209
    if (!existsSync(taskDir) || !statSync(taskDir).isDirectory()) return undefined;
  • 写入本地文件
    src/store.mjs:268
    writeFileSync(file, `${JSON.stringify(index, null, 2)}\n`, 'utf8');
  • 写入本地文件
    src/store.mjs:307
    mkdirSync(info, { recursive: true });
  • 写入本地文件
    src/store.mjs:312
    writeFileSync(exclude, `${current}${tail}${SESSION_MARKER}\n`, 'utf8');
  • 写入本地文件
    src/store.mjs:336
    writeFileSync(file, `${JSON.stringify(body, null, 2)}\n`, 'utf8');
  • 写入本地文件
    src/store.mjs:413
    mkdirSync(tasksRoot, { recursive: true });
  • 执行外部命令固定命令
    src/store.mjs:685
    return execFileSync('git', args, { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
  • 删除本地文件
    src/store.mjs:717
    if (progress !== undefined) unlinkSync(progress);
  • 读取本地文件
    src/tidy.mjs:74
    entries = readdirSync(current, { withFileTypes: true });
  • 读取本地文件
    src/tidy.mjs:88
    bytes += statSync(join(current, entry.name)).size;
  • 读取本地文件
    src/tidy.mjs:112
    return README_NAMES.some((name) => existsSync(join(dir, name)));
  • 读取本地文件
    src/tidy.mjs:125
    names = readdirSync(dir, { withFileTypes: true });
  • 读取本地文件
    src/tidy.mjs:142
    const info = statSync(abs);
  • 读取本地文件
    src/tidy.mjs:150
    mtimeMs = mtimeMs || statSync(abs).mtimeMs;
  • 写入本地文件
    src/tidy.mjs:435
    mkdirSync(dirname(target), { recursive: true });
  • 写入本地文件
    src/tidy.mjs:436
    writeFileSync(target, markdown, 'utf8');
  • 删除本地文件递归
    src/tidy.mjs:460
    rmSync(item.path, { recursive: true, force: true });
  • 删除本地文件递归
    src/tidy.mjs:475
    rmSync(stray.path, { recursive: true, force: true });
  • 读取本地文件
    src/cli.mjs:90
    if (existsSync(direct)) return direct;
  • 读取本地文件
    src/cli.mjs:131
    let content = readFileSync(progressFile, 'utf8');
  • 写入本地文件
    src/cli.mjs:164
    writeFileSync(progressFile, content, 'utf8');
扫描于 2026/10/31(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

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

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

DSH 任务工作区约定:每个任务一个文件夹,每个任务一份 PROGRESS.md(每次更新覆盖),任务拖长后按任务单独用 git。

README

由 DeepSeek 最新模型翻译生成
dsh-task-workspace 给 DSH 加一条落得下地的工程约定:一个会话只用一个文件夹,一个任务一个进度文件(每次修改整体覆盖更新),任务过长就在任务目录里建 git 仓库。 - 英文文档:README.md - 中文文档:本文件 它做什么 | 组成 | 效果 | | 提示词段落 task-workspace | 每一轮对话都带着这条约定,任何工作区都生效 | | 技能 task-workspace-convention | 同一份约定,可通过技能目录被检索到 | | 工具 task_new | 建 <工作区根>/<任务名>-<YYYYMMDD>/PROGRESS.md(可选顺手 git init);本会话已有目录时直接复用(reused: true) | | 工具 task_progress | 对那唯一的进度文件做整体覆盖更新;长摘要自动压缩;可选自动提交 | | 工具 task_git | git init + .gitignore + 首次提交,或追加一次提交 | | 工具 task_list | 列出当前工作区已有的任务目录 | | 工具 task_tidy | 给每个顶层条目分类,重写工作区索引,并清理系统垃圾 / 缓存 / 过期备份 / 空目录 / 越界遗留任务目录(默认 dry run,apply: true 才删) |
展开完整文档(README 剩余 1 节)
dsh-task-workspace

给 DSH 加一条落得下地的工程约定:一个会话只用一个文件夹,一个任务一个进度文件(每次修改整体覆盖更新),任务过长就在任务目录里建 git 仓库。

- 英文文档:README.md
- 中文文档:本文件

它做什么

| 组成 | 效果 |
| 提示词段落 task-workspace | 每一轮对话都带着这条约定,任何工作区都生效 |
| 技能 task-workspace-convention | 同一份约定,可通过技能目录被检索到 |
| 工具 task_new | 建 <工作区根>/<任务名>-<YYYYMMDD>/PROGRESS.md(可选顺手 git init);本会话已有目录时直接复用(reused: true) |
| 工具 task_progress | 对那唯一的进度文件做整体覆盖更新;长摘要自动压缩;可选自动提交 |
| 工具 task_git | git init + .gitignore + 首次提交,或追加一次提交 |
| 工具 task_list | 列出当前工作区已有的任务目录 |
| 工具 task_tidy | 给每个顶层条目分类,重写工作区索引,并清理系统垃圾 / 缓存 / 过期备份 / 空目录 / 越界遗留任务目录(默认 dry run,apply: true 才删) |
| 命令行 dsh-task | 不用模型也能执行同样的操作 |

安装

dsh plugin --profile desktop add dsh-task-workspace

本地目录安装:

dsh plugin --profile desktop add /绝对路径/dsh-task-workspace

装好后重启该 profile(或开新会话),bundle 补丁才会被合成。

落盘形态

<工作区根>/ ├── .dsh-tasks.json # 轻量任务索引,写入时更新 ├── 竞品调研-20261002/ │ ├── PROGRESS.md # 这个任务唯一的进度文件 │ ├── .dsh-session.json # 记录这个目录属于哪个会话 │ ├── .git/ # 只有「任务过长」时才有 │ └── data/… # 任务产出 └── etl-refactor-20261003/ └── PROGRESS.md

一个会话在此工作区最多只有一个文件夹:.dsh-session.json 记录归属,同一会话再调 task_new 会复用该目录(reused: true,目录名不变),索引里的 sessionId 作为兜底。

PROGRESS.md 固定六段:目标 / 状态 / 当前进度 / 下一步 / 产出物 / 变更日志。

工具用法

task_new

{ "name": "竞品调研", "goal": "整理三家竞品的定价与功能差异", "init_git": true }

- 建 竞品调研-<当天日期>/ 及它的 PROGRESS.md;
- 同一天重复调用是幂等的,返回已有任务;
- 一个会话一个文件夹:本会话已有任务目录时直接复用(reused: true,保留原目录名),不再新建第二个;本会话的所有改动都落在该目录内;
- force: true 可接管同名但非空目录;
- slug 可覆盖目录名。

task_progress

{
"task_dir": "竞品调研-20261002", // 也可用 "task": "竞品" "summary": "已抓取 3 家官网定价页,A 家缺 API 价目", "changelog": "完成定价页抓取", "status": "进行中", "next": "补齐 A 家 API 价目\n输出对比表", "deliverables": "data/pricing.csv" }

- 覆盖「当前进度」而不是往里追加;摘要超过约 18 行会自动压成 ### 进度历史(压缩摘要) 加一个 折叠区保存原文,既不留垃圾也不丢历史;
- 「变更日志」只追加一行,不重写历史;
- 任务目录里已有仓库时自动提交(commit: false 可跳过,或把配置里的 autoCommit 设为 false);
- 什么都不传会报错,避免无意义的空写入。

task_git

{ "task_dir": "竞品调研-20261002", "message": "chore: 初始化任务仓库" }

初始化仓库并写入 .gitignore(.DS_Store、__pycache__/、node_modules/、.venv/、.tmp)后提交;再次调用就是提交当前状态。

task_list

列出当前工作区的任务目录,含状态、最后更新时间、是否已建仓库。

task_tidy

把工作区整理一遍:

- 给每个顶层条目归类:任务 / 产出 / 中间产物 / 工具 / 配置 / 散落文件;
- 覆盖重写索引文件(默认 工作区索引.md):按类别列出大小、文件数、最后修改、任务状态与目标;
- 单独报出大体积中间产物(超过 200 MB)但不动它们;
- 默认 dry run,apply: true 才真正删除,且只删可证明无用的东西:.DS_Store 一类系统垃圾、 __pycache__ / .pytest_cache、.pyc / .bak / .orig / .tmp / .tgz,以及落在工作区之外、里面只有自身 PROGRESS.md 的任务目录(cwd 出错留下的)——不碰任务内容,不碰产出;
- 空目录只列出、不删除(空的 parts/ 可能正是构建脚本期待的占位目录),要删得显式传 empty_dirs: true。

{ "workspace": "/path/to/workspace", "apply": true, "index": true, "empty_dirs": false }

索引每次运行都会整体重写,是给人读的,不要手工编辑。

命令行

dsh-task new "竞品调研" "整理定价差异" --git dsh-task progress 竞品调研 --summary "抓到 3 家" --changelog "完成抓取" dsh-task git 竞品调研 --message "chore: 初始化任务仓库" dsh-task list dsh-task config --root "/path/to/workspace"

退出码:0 正常,1 用法错误,2 操作失败。人读的信息走 stderr,结果路径走 stdout (所以 cd "$(dsh-task new …)" 可以直接用)。

配置

工作区根的解析顺序:工具参数 → 配置 workspaceRoot → $DSH_TASK_WORKSPACE_ROOT → $DSH_WORKSPACE_ROOT → 会话工作区目录 → $DSH_HOME。
显式指定的根目录不存在时会自动创建;node_modules/、/、临时目录、$HOME 本身会被拒绝。

配置文件位于 ${DSH_HOME}/dsh-task-workspace/config.json:

{
"enabled": true,
"workspaceRoot": "",
"defaultGit": false,
"autoCommit": true,
"sectionOrder": 61,
"promptEnabled": true,
"skillEnabled": true,
"template": "",
"gitAuthor": { "name": "", "email": "" }
}

- defaultGit: true:所有新任务默认建仓库;
- promptEnabled: false / skillEnabled: false:保留工具,但不注入提示词/技能;
- template:直接内联 PROGRESS.md 的 markdown 模板;
- gitAuthor:给没有全局 git 身份、也没有 ~/.gitconfig 的机器兜底(也可以用环境变量 $DSH_TASK_GIT_NAME / $DSH_TASK_GIT_EMAIL)。

profile 也可以在自己的补丁层覆盖同样的键:

- id: task-workspace
name: 'dsh-task-workspace'
config:
workspaceRoot: /Users/me/notes
defaultGit: true

什么时候该建仓库

约定给的触发条件很明确,满足任一即建:

- 预计超过 3 轮对话;
- 需要跨会话继续;
- 预计产出文件超过 10 个;
- 用户明确要求。

开发与自测

node test/run.mjs # 47 项:store、工具、真实 git、CLI、宿主 JSON Schema 子集、会话复用(一会话一文件夹)与 cwd 回退、内部目录护栏,不联网
node test/run.mjs --keep # 保留临时工作区便于检查

许可证

MIT

被应用独占的 profile

dsh plugin --profile desktop add … 会因为 desktop profile 归属 Electron 应用而拒绝执行。
scripts/install-into-profile.sh 只做那条命令本来会做的两件事:

bash scripts/install-into-profile.sh desktop --dry-run # 先看计划 bash scripts/install-into-profile.sh desktop # 建链接 + 写入 bundles

它把包链接进 <profile>/node_modules,并把包名追加到 dsh.profile.bundles;只就地修改这个数组,package.json 其余字节保持不变(这个文件由应用自己重写)。
首次改动前会备份 package.json.bak。装完重启该 profile。

两个只有真机启动才暴露的坑

(本插件已修好,这里记下来供二次开发参考)

- inject 必须挂在导出值上。 cordis-plugin-loader 用 exports.default ?? exports 归一化模块形状,所以只要模块有 default 导出,命名导出的 inject 就会被丢掉,报 Error: cannot get property "systemPrompt" without inject。正确写法是挂到函数属性: apply.inject = ['tools', 'systemPrompt']。
- required 是对象级关键字。 宿主会校验工具输出 schema 是否落在它自己的 JSON Schema 子集内(type/oneOf/properties/required/additionalProperties/items/enum/const 加注解),在标量属性上写 required: true 会报 JsonSchemaError: schema.properties.x.required is not supported on type "string"。
要写在对象上:{ type: 'object', required: ['dir'], properties: { dir: { type: 'string' } } }。
预览分享卡片长什么样 ↓Zilong6666/dsh-task-workspace
分享 · DeepSeek Harness Hub
Zilong6666/dsh-task-workspace

为每个任务建立独立文件夹并维护进度文件

回到顶部