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

工程脚手架 Eru07734/dsh-workspace-scaffolds

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

按工程关联脚手架插件,休眠时停用、恢复时重装

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

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

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

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:待复验
是什么
dsh 原生插件 · dev
装得上吗
曾在 dsh 0.2.0-rc.2 下真实安装成功,但当前 dsh 已更新至 0.2.1-rc.5,本站尚未在新版下复验
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 19 天前
档位由哪些信号合成

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

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

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

读写/删除本地文件发起外部网络请求
查看扫描证据(共 46 处,展示前 45 条)
  • 发起网络请求
    client.js:255
    const response = await fetch(`${API}${path}`, {
  • 发起网络请求
    src/api.js:40
    async fetch(request) {
  • 读取本地文件
    src/operations.js:193
    const manifest = JSON.parse(await readFile(join(this.host.profileDir, 'package.json'), 'utf8'));
  • 读取本地文件
    src/operations.js:609
    names = await readdir(this.store.archiveDir);
  • 读取本地文件
    src/operations.js:617
    const info = await stat(join(this.store.archiveDir, name)).catch(() => null);
  • 读取本地文件
    src/operations.js:720
    const info = await stat(args.path).catch(() => null);
  • 读取本地文件
    src/operations.js:913
    const buffer = await readFile(archivePath(this.store, archiveSha256));
  • 删除本地文件递归
    src/operations.js:925
    await rm(staging, { recursive: true, force: true }).catch(() => {});
  • 读取本地文件
    src/operations.js:1577
    const buffer = await readFile(target);
  • 删除本地文件
    src/operations.js:1586
    await rm(target, { force: true });
  • 写入本地文件
    src/store.js:49
    await mkdir(this.directory, { recursive: true });
  • 写入本地文件
    src/store.js:50
    await mkdir(this.archiveDir, { recursive: true });
  • 写入本地文件
    src/store.js:51
    await mkdir(this.operationDir, { recursive: true });
  • 写入本地文件
    src/store.js:52
    await mkdir(this.stagingDir, { recursive: true });
  • 读取本地文件
    src/util.js:32
    await stat(filePath);
  • 读取本地文件
    src/util.js:48
    return await realpath(absolute);
  • 读取本地文件
    src/util.js:113
    await lstat(candidate);
  • 读取本地文件
    src/util.js:156
    const realRoot = await realpath(resolve(root)).catch(() => null);
  • 读取本地文件
    src/util.js:163
    const realAncestor = await realpath(ancestor).catch(() => null);
  • 读取本地文件
    src/util.js:179
    text = await readFile(filePath, 'utf8');
  • 写入本地文件
    src/util.js:198
    await mkdir(dirname(filePath), { recursive: true });
  • 写入本地文件
    src/util.js:200
    await writeFile(temporary, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
  • 写入本地文件
    src/util.js:202
    await rename(temporary, filePath);
  • 删除本地文件
    src/util.js:204
    await unlink(temporary).catch(() => {});
  • 写入本地文件
    src/util.js:219
    await mkdir(dirname(filePath), { recursive: true });
  • 写入本地文件
    src/util.js:222
    await writeFile(temporary, bytes);
  • 写入本地文件
    src/util.js:224
    await rename(temporary, filePath);
  • 删除本地文件
    src/util.js:226
    await unlink(temporary).catch(() => {});
  • 读取本地文件
    src/archive.js:107
    const buffer = await readFile(filePath);
  • 读取本地文件
    src/archive.js:127
    const manifest = JSON.parse(await readFile(join(sourcePath, 'package.json'), 'utf8').catch(() => {
  • 读取本地文件
    src/archive.js:136
    const buffer = await readFile(sourcePath);
  • 读取本地文件
    src/scaffold.js:27
    manifest = JSON.parse(await readFile(join(packageDir, 'package.json'), 'utf8'));
  • 读取本地文件
    src/scaffold.js:39
    raw = JSON.parse(await readFile(descriptorPath, 'utf8'));
  • 读取本地文件
    src/templates.js:102
    const source = await readFile(file.source).catch(() => {
  • 读取本地文件
    src/templates.js:133
    const info = await stat(filePath);
  • 读取本地文件
    src/templates.js:161
    const existing = await readFile(absolute);
  • 读取本地文件
    src/templates.js:221
    const current = await readFile(file).catch(() => null);
  • 删除本地文件
    src/templates.js:227
    await unlink(file);
  • 删除本地文件
    src/templates.js:236
    await rmdir(directory);
  • 读取本地文件
    src/templates.js:307
    const existing = await readFile(absolute);
  • 读取本地文件
    src/version.js:28
    const manifest = JSON.parse(readFileSync(manifestUrl, 'utf8'));
  • 读取本地文件
    src/tar.js:151
    const entries = await readdir(absolute, { withFileTypes: true });
  • 读取本地文件
    src/tar.js:158
    const info = await lstat(child);
  • 读取本地文件
    src/tar.js:193
    const rootInfo = await stat(directory);
  • 读取本地文件
    src/tar.js:209
    const bytes = await readFile(entry.path);
扫描于 2026/11/1(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

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

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

功能亮点

  • 工程关联脚手架插件
  • 休眠时停用
  • 恢复时重装

把 DSH 工作区绑定到各自的脚手架插件包:开工前准备,工作中添加,空闲时存到磁盘,回来时恢复。已在真实的 DSH 0.2.0-rc2 实例上验证;独立评审提出的 14 项问题已在 v0.1.12 全部修复。

README

由 DeepSeek 最新模型翻译生成
工程脚手架 · dsh-workspace-scaffolds ✅ 评审 14 项已全部修复 · ALL 14 REVIEW FINDINGS FIXED 一次独立代码评审发现 14 项可复现缺陷(5 项 P1、9 项 P2),我已逐条对照源码确认全部成立,并已全部修复。 修复过程中又发现并修复了 1 项评审之外的缺陷(F15:splitName 静默截断超长路径,产出连自己的读取器都拒绝的归档)。 逐条状态、修法与仍未关闭的残余风险见 docs/review-response-2026-10-12.md。 已在真实 DSH 0.2.0-rc2 隔离实例上验证(D:\dsh-verify-020rc2,独立 home / profile / 端口,不触碰日常工作 profile): - 完整工作流:注册工程 → 导入脚手架包 → 关联 → 预览 → 生成文件 → 启用 → 休眠 → 恢复; - 插件的安装与热载入(application: "applied",无需重启); - 休眠真正在原生侧停用 bundle,恢复后重新启用;休眠不误停用别的工程仍在使用的包; - 重启后的状态对账:关联、版本、原生状态与归档保持一致,且对账不会误钉; - HTTP 进度:导入运行期间可轮询到中间步骤;
展开完整文档(README 剩余 1 节)
工程脚手架 · dsh-workspace-scaffolds

✅ 评审 14 项已全部修复 · ALL 14 REVIEW FINDINGS FIXED

一次独立代码评审发现 14 项可复现缺陷(5 项 P1、9 项 P2),我已逐条对照源码确认全部成立,并已全部修复。
修复过程中又发现并修复了 1 项评审之外的缺陷(F15:splitName 静默截断超长路径,产出连自己的读取器都拒绝的归档)。
逐条状态、修法与仍未关闭的残余风险见 docs/review-response-2026-10-12.md。

已在真实 DSH 0.2.0-rc2 隔离实例上验证(D:\dsh-verify-020rc2,独立 home / profile / 端口,不触碰日常工作 profile):

- 完整工作流:注册工程 → 导入脚手架包 → 关联 → 预览 → 生成文件 → 启用 → 休眠 → 恢复;
- 插件的安装与热载入(application: "applied",无需重启);
- 休眠真正在原生侧停用 bundle,恢复后重新启用;休眠不误停用别的工程仍在使用的包;
- 重启后的状态对账:关联、版本、原生状态与归档保持一致,且对账不会误钉;
- HTTP 进度:导入运行期间可轮询到中间步骤;
- 脚手架注册的工具在真实 agent 回合中被提供、被调用,其返回载荷出现在消息记录里;
- 评审 P1 的现场复核:解绑只释放被移除的那个关联;自动恢复登记共享持有者;
- 评审 P2(第二批)的现场复核:未满足的声明依赖被拒且 requires 跨重启存活;重复导入不改写归属;部分绑定更新被接受;必需脚手架关闭时 ready=false;
- 评审 P2(第三批)的现场复核:原生安装失败会让导入失败且不留下包记录(用真实失败的安装造出来,不是 mock);预览之后的冲突零写入。

未验证:浏览器面板的视觉渲染。逻辑与状态有测试覆盖,但真实浏览器里的画面始终没有人眼确认——这一项自始至终未变。

详细证据、缺陷记录与验证方法见 docs/verification.md。

把 DSH 工程(Workspace)与工程使用的脚手架插件关联起来的插件。

- 开工前:选择工程需要的脚手架,预览并生成初始文件,然后恢复插件。
- 工作中:随时给工程追加脚手架;新增能力从下一次模型请求开始生效。
- 不用时:休眠工程,插件被停用并保留在硬盘上;工程文件、安装包和配置都不动。
- 再次使用时:恢复工程,按记录的版本和关联把插件重新装回运行状态。

目录

- 核心概念
- 安装
- 使用流程
- 面板说明
- agent 工具
- HTTP 接口
- 数据与状态
- 能力边界
- 验证
- 脚手架包格式

核心概念

| 术语 | 含义 |
| 工程 | DSH 原生 workspaceRegistry 中的 Workspace,用原生 workspaceId 标识 |
| 脚手架包 | 声明了 dsh.bundle 的原生 DSH 插件包,可以另外携带文件模板 |
| 关联 | 把某个精确版本的包记入工程清单;关联本身不加载任何东西 |
| 准备 / 恢复 | 通过原生插件管理器启用插件能力;不生成模板文件 |
| 生成 | 依据模板向工程写入新文件;必须单独执行,永不覆盖已有文件 |
| 休眠 | 释放工程对插件的占用;没有其他工程需要时才真正停用,磁盘文件全部保留 |
| 解除关联 | 从工程清单移除记录;已生成的文件保留 |
| 全局常驻 | 标记某个包始终启用,任何工程休眠都不会关闭它 |

租约(lease)是推导出来的,不是存下来的。 一个工程持有某个包的租约,当且仅当它处于「使用中」且该关联处于启用状态。这样就不会出现「存的租约和实际关联不一致」这类问题。

安装

本插件是一个原生 DSH bundle。开发目录没有第三方依赖,Host 代码和浏览器代码都是普通 JavaScript。

在 DSH 中通过插件管理器安装本目录或发行包
dsh plugin add /absolute/path/to/dsh-workspace-scaffolds
或安装打包好的发行包
dsh plugin add ./dsh-workspace-scaffolds-0.1.9.tgz

安装后需要为本插件启用 bundle(默认 cordis.patch.yml 已声明)。面板出现在 插件页 → 本插件卡片,使用 plugins.bundle.config 插槽。

使用流程

1. 注册工程

在面板「注册工程」中填写项目目录的绝对路径。插件会在原生工程注册表中登记它,并建立自己的管理记录——此时不关联任何脚手架、不启用任何插件、不写任何文件。

已注册的目录再次注册不会报错,也不会产生第二个工程:原生注册表按路径去重,插件会接管既有的那个,并保留它已有的关联。

2. 导入脚手架包

在面板「导入脚手架包」中填写绝对路径,可以是:

- 一个包含 package.json(且声明了 dsh.bundle)的目录;
- 一个 .tgz 包。

导入会依次完成:校验原生 bundle 声明 → 校验可选的 scaffold.json → 打包并计算 SHA-256 → 存入本地归档 → 通过原生插件管理器安装但不启用。

3. 关联到工程

在「已关联脚手架」区域选择包并点击「添加到该工程」。关联只写配置,不加载插件、不写工程文件。

4. 生成初始文件(可选)

对声明了模板的包点击「生成预览」:

- 预览会列出每个目标文件的 create / identical / conflict 状态;
- 预览阶段发现任何 conflict 时整批阻止,此时不会写入任何文件;
- 确认后点击「生成文件」。已存在且内容相同的文件被跳过,内容不同的文件不会被覆盖。
- 应用前会再次检查全部目标:预览之后才出现的冲突(文件被他人改写、目标变成目录)同样整批中止,一个文件都不会写入。
- 写入过程中若发生 I/O 失败,会回滚本次已创建的文件与目录——只删空目录,且只删内容摘要仍是本次写入的那些,避免误删用户在窗口期内的改动。若回滚自身失败(例如文件被别的进程占用),错误详情会如实报告 rolledBack / leftBehind / partial,不会假装干净。进程被硬杀或断电时不存在回滚路径,会留下部分文件。

5. 恢复工程

点击「恢复」。所有必需的包都会依次启用;失败时不会把工程标成「已就绪」,并且会回滚本次新启用、且没有其他工程需要的包。

6. 休眠

点击「休眠并保留」:

- 有任务正在执行时,休眠会排队,等环境空闲后自动完成,不会打断正在运行的任务;
- 其他工程仍在使用的包保持不变,面板会说明保留原因;
- 标记为「全局常驻」或原本就由外部启用的包不会被关闭;
- 只调用原生「停用」,不会删除安装、归档或工程文件。

面板说明

面板分为四块:

1. 导入脚手架包 — 路径输入与导入。
2. 工程 — 选择工程;显示期望状态、是否就绪、待处理项;提供「恢复」与「休眠并保留」。
3. 已关联脚手架 — 每个关联的版本、原生状态、归档状态、是否多工程共享;提供生成预览与解除关联。声明了模板变量的包会在行内给出变量输入框。
4. 本地仓库与已装插件 — 本地仓库中的包、是否已安装、归档是否存在、当前有哪些工程在用它;提供全局常驻开关与删除归档。

所有写操作都携带当前 revision;版本冲突时面板会重新读取状态并提示,不会盲目重放。

面板标题行显示三个标签:配置版本、profile 名称、以及当前运行的构建版本(pluginVersion)。当 profile 声明的构建与内存中运行的不是同一个时,面板会额外显示一行提示和所声明的 spec —— 也就是「更新已写盘,但需要重启才生效」这个状态,不必再靠行为反推。

agent 工具

工具名 workspace_scaffolds,动作与 HTTP 接口一致。默认工程取自当前会话的工作目录(通过原生工程注册表按规范化路径精确匹配,不做前缀猜测)。

读操作:

- list — 完整状态,包含 revision、工程、关联、包和阻塞项。
- operation-status — 按 operationId 查询进度与结果。
- scaffolds — 读取某个包的模板描述。

写操作(必须携带 list 返回的 expectedRevision 与一个新的 UUID operationId):

- workspace-register — 把一个已存在的目录注册为受管工程(path,可选 title)
- import、bind、unbind、update-binding、set-pin
- wake、sleep
- template-preview、template-apply
- delete-archive

operationId 与参数一起构成幂等键:同参数重试会返回记录过的结果而不重复执行;同 ID 换参数会被拒绝(operation-id-reused)。

wake 返回 effectiveFrom: "next-model-request" —— 这是准确语义:当前已经发给模型的工具列表不会改变,新增能力在下一次请求生效。

HTTP 接口

GET /api/workspace-scaffolds/state
GET /api/workspace-scaffolds/progress # 只读进度,适合高频轮询 GET /api/workspace-scaffolds/progress?operationId=<id> POST /api/workspace-scaffolds/execute

成功:{ "ok": true, "value": ... };失败:{ "ok": false, "code": "...", "details": { ... } }。

请求体上限 1 MiB。配置、版本、模板冲突返回 409,输入错误 400,找不到 404。

进度

import 会真的跑包管理器,wake 要逐个原生启用 bundle;这些请求在完成前如果不返回任何中间信息,调用方就只看到一个卡住的连接。因此耗时的动作会被登记成一条进度记录,可以在它还在跑的时候查询:

// POST /execute { "action": "import", ..., "background": true }
{ "ok": true, "value": {
"operationId": "…", "action": "import", "status": "running", "background": true,
"progress": { "phase": "validate package", "steps": [ /* … / ] } } }

// GET /progress (或包含在 GET /state 的 progress 字段里,一次轮询即可) { "ok": true, "value": {
"running": [ {
"operationId": "…", "action": "import", "status": "running", "phase": "install without enabling",
"steps": [
{ "label": "validate package", "status": "done", "detail": "dsh-scaffold-notes@0.1.0" },
{ "label": "install without enabling", "status": "active" },
{ "label": "record in warehouse", "status": "pending" }
] } ],
"recent": [ / 最近完成的,保留 20 条 / ] } }

实际轮询效果(真实输出,install 被注入 1.2s 延迟以便观察):

tick 2
import running phase=install without enabling
[x] validate package (dsh-scaffold-notes@0.1.0)
[x] hash and archive (8700a0a14de3)text
[x] 读取脚手架描述符(1 个模板) [>] 安装但不启用 [ ] 记录到仓库

要点:

- background: true 让耗时动作立刻返回 operationId,而不是把连接挂到跑完为止;配合 /progress 轮询即可。适用于 import、wake、sleep、template-apply。
- 步骤状态为 pending / active / done / failed / skipped;wake 与 sleep 会按包动态追加步骤(每个包一行),因为这些步骤在计划时就已确定但数量取决于关联。
- 进度只在内存中,刻意不持久化:它描述的是一个活着的进程,重启后读到过期记录比读不到更糟。持久的结果仍在操作日志里(operation-status)。
- operation-status 对进行中的操作同样可用(读实时进度),不必等它写入操作日志。
- 面板在动作执行期间轮询 /progress 并逐步渲染,而不是只显示一个转圈。

构建标识

list(以及 GET /state)的返回值里带有三个诊断字段,用来回答「现在到底是哪个构建在跑」:

| 字段 | 含义 |
| pluginVersion | 正在内存中运行的构建版本,读自该模块自己的 package.json |
| profileSpec | profile manifest 为该插件声明的依赖 spec(即「请求的是哪个」),读不到时为 null |
| restartPending | 前者与后者不一致,需要重启 DSH 才会生效 |

pluginVersion 取自运行中的模块自身,而不是 profile 声明——后者恰恰是会在「更新已写盘、进程仍持旧代码」时说谎的那个。

restartPending 是保守启发式:只对 file: / link: 这类把具体产物写进字符串的本地 spec 判定;^0.1.0 这类注册表范围描述的是一个可接受集合,不是另一个构建,因此永不报告为待重启。读不到版本时一律返回 false,不会把「未知」伪装成任何结论。

错误码

invalid-request、workspace-not-found、workspace-unavailable、revision-conflict、operation-id-reused、package-content-conflict、version-conflict、dependency-missing、dependency-cycle、protected-bundle、restart-required、native-overridden、native-operation-failed、template-conflict、preview-expired、preview-stale、path-outside-workspace、archive-in-use、state-corrupt、unsupported-host、not-a-bundle、package-unknown、scaffold-invalid、archive-invalid。

sleep 在有空闲问题时返回 status: "pending-idle" —— 这是正常的异步状态,不是错误。

数据与状态

全部状态位于当前 profile 目录下:

<profileDir>/workspace-scaffolds/
state.json 权威状态(含 revision、工程、包、预览、操作日志) state.json.bak 上一次成功的状态,用于损坏恢复 archives/<sha>.tgz 内容寻址的脚手架包快照 operations/ 预留的操作目录 staging/ 临时解包目录(用完即删)

规则:

- 所有写操作串行化,写前校验 revision,写入使用「临时文件 + 原子改名」。
- state.json 损坏时先从 .bak 恢复;没有可用备份就报错停止,绝不把损坏状态当成空状态。
- 存储的 schemaVersion 高于本插件支持的版本时只读报错,不做降级。
- 操作日志保留最近 200 条,用于幂等重放。
- 预览记录带 10 分钟有效期,template-apply 必须引用预览 ID。

工程目录里只有你显式生成的模板文件;本插件不写隐藏清单、不改 .gitignore。

能力边界

这些是已知且有意的限制,请按此预期使用:

1. 原生插件是全 profile 共享的。 关联到工程不等于运行隔离。本插件用「工程使用记录 + 全局常驻保护」来避免误停用,但一个启用的 bundle 会向该 DSH 环境中的所有会话提供它的能力。
2. 不做工程级配置隔离,也不支持同一包的多版本并行。 两个工程要求同包不同版本时会明确报 version-conflict,不会替换正在运行的版本。
3. agent/created 自动恢复只走快路径:只对已安装的包做启用,绝不在创建 agent 时运行包管理器。需要安装时,面板会显示待处理项,由「恢复」显式完成。自动恢复有 15 秒预算;超时会记录并标记为 degraded,不会挂起启动。
4. 原生侧边栏单纯切换到一个已存在的会话不会触发恢复。 请用面板的「恢复」,或在新建/恢复 agent 时依赖自动恢复。
5. 休眠时如果环境中有任务在执行会排队,不会打断。
6. 停用不保证卸载模块内存。 Node 的模块缓存不保证回收,所以本插件只说「停用并保留」,不承诺完全释放内存。
7. 离线恢复分两级:休眠后再恢复不需要网络;如果包被从 profile 里移除,则只有归档存在、且重新安装成功后才能恢复(第三方依赖是否可离线重装未经验证)。
8. 模板没有覆盖更新、三方合并或升级迁移。 用户改过的文件永远保留。
9. 本插件自身被停用时不会去关闭第三方插件(此时宿主服务可能正在释放),只释放自己注册的路由、工具和监听器;下次启动重新对账。

验证

验证分两层,两层都要看: bash
node --test test/.test.mjs # 171 项单元测试(假宿主)
第一层:单元测试(内存假宿主,但执行的是真实的 src/host.js 适配层):

| 验证了什么 | 没验证什么 |
| 171 项 node:test 用例全部通过 | 浏览器面板的真实渲染与交互 |
| Linux(Node 22 / 24)与 Windows 上均通过 | — 真实环境由第二层覆盖 |
| 真实适配层被实际执行(非桩替换):installBundle(..., {enabled:false}) 等契约在测试范围内 | |

第二层:隔离 DSH 0.2.0-rc2 实例上的端到端验证(主流程 + 评审 P1/P2 复核共 66/66、重启对账 9/9、agent 层 12/12):

| 验证了什么 | 没验证什么 |
| 完整工作流:注册 → 导入 → 关联 → 预览 → 生成 → 启用 → 休眠 → 恢复 | 浏览器面板的视觉渲染(布局与样式) |
| 休眠真的在原生侧停用 bundle;恢复真的重新启用 | 与 0.2.0-rc2 以外版本的兼容性 |
| 两个工程共享同一 bundle 时,休眠不误停用别人仍在用的包 | |
| 重启后的状态对账(关联、版本、原生状态、归档一致,且不会误钉) | |
| HTTP 进度可在长操作运行期间轮询到中间步骤 | |
| 真实 agent 回合中脚手架注册的工具被提供、被调用,且其返回载荷出现在消息记录里 | |

验证环境:独立 home D:\dsh-verify-020rc2、独立 profile verify、独立端口 —— 与日常工作 profile 完全隔离,验证产物也留在隔离区内。

测试覆盖的验收场景与结果见 docs/verification.md。

试用前请自行确认:本插件会在 <profileDir>/workspace-scaffolds/ 下写入状态,并会调用原生插件管理器启用/停用 bundle。请先在非关键 profile 或副本工程上验证。

脚手架包格式

一个可运行的脚手架包就是原生 DSH bundle,可以额外声明模板: json { "name": "dsh-scaffold-notes", "version": "0.1.0", "type": "module",
"exports": { ".": "./plugin.js" },
"dsh": { "bundle": { "patch": "./cordis.patch.yml" } },
"workspaceScaffold": "./scaffold.json"
}

scaffold.json: json { "schemaVersion": 1, "title": "工程笔记",
"variables": {
"projectName": { "type": "string", "required": true, "maxLength": 100 }
},
"templates": [
{
"id": "notes",
"files": [
{ "source": "templates/NOTES.md", "target": "docs/NOTES.md", "render": "text" }
]
}
]
}

- render: "text" 只支持 {{variableName}} 替换,不支持表达式、脚本或递归 include。
- render: "copy" 原样复制二进制资源。
- 目标是固定的相对路径,必须是相对路径且不能越出工程目录。
- requires 用于声明依赖其他脚手架包(精确版本),由本插件做依赖排序与环路检测。

examples/ 下有两个可直接导入的示例:dsh-scaffold-notes(只提供模板)与 dsh-scaffold-checks(提供 project_checklist 工具与模板)。

许可

MIT
预览分享卡片长什么样 ↓Eru07734/dsh-workspace-scaffolds
分享 · DeepSeek Harness Hub
Eru07734/dsh-workspace-scaffolds

按工程关联脚手架插件,休眠时停用、恢复时重装

回到顶部