dsh-virtuoso
Verifieddsh-virtuoso · v0.1.2 · MIT · Web UI
Cadence Virtuoso integration for the DeepSeek Harness — bundles the virtuoso-cli agent skills, manages the daemon / tunnel / sessions from the settings panel. · DSH 的 Virtuoso 集成插件,把 virtuoso-cli 的 agent skills 与 daemon / tunnel / session 管理一并打包到 DSH 设置面板
Install
dsh plugin add dsh-virtuoso Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Creators
Readme
dsh-virtuoso
English · 中文
dsh-virtuoso把 Cadence Virtuoso 的 EDA 集成带到 DeepSeek Harness: 把 virtuoso-cli 的 agent skills 全部打包, 让模型在 DSH 会话里就能直接驱动 SKILL、Maestro、Spectre、原理图、Verilog-A 与 SSH tunnel; 设置面板负责展示vcli健康度、tunnel 开关和 daemon 在读的VB_*配置。插件自身只是 DSH 对 virtuoso-cli 的一层薄壳 —— 所有执行路径都跑
vcli(老兼容也接受virtuoso)binary, agent 通过Bash调用;host half 不引入新远端、不引入新守护、不引入新进程, 只是把VB_*环境变量读出来展示。
0.1.0 更新要点
这是 dsh-virtuoso 首次发布到 npm。重点:
tunnel/start本地模式短路 ——vcli tunnel start在VB_REMOTE_HOST未设置时不再报ssh "Could not resolve hostname"。路由现在在本地模式 直接探测vcli session list,把解析后的会话数组作为存活证据返回。- 「已连接的 Virtuoso」面板段 ——
GET /dsh-virtuoso/sessions列出每个活动 Virtuoso 实例(id / port / host / user / 启动时间)。GET /dsh-virtuoso/session-current在匹配行打上● active标记,告诉操作员下次vcli skill exec会落到哪一台。 - 自动刷新开关 —— 状态 tab 上的可选 30s 轮询。默认关闭,面板安静; 留作打开等 daemon 重启时开启。
- 路径脱敏的 stderr —— 共享大屏场景下,
CallResult在展示前把/foo/bar/...形态的字符串洗掉。原始 stderr 仍在网线上,curl/devtools 可见。 - bundled-skill 信任门 ——
sync-skills.mjs现在为每一个缺失allowed-tools:行的 skill 插入标准门 (Bash(*/vcli *) Bash(*/virtuoso *) Read Write Edit)。原本未加门的 5 个 skill 已经在仓里直接补上。 - 测试 —— 117 个单元测试,跨 8 个文件。
npm test跑约 750 ms。 - npm 上架 ——
dsh plugin --profile web add dsh-virtuoso从注册表安装;不需要 build,不需要为prepare授权。 - 新增用户级 skill ——
POST /dsh-virtuoso/skills/add把 SKILL.md 写到$DSH_HOME/skills/<id>/,DSH 下次重启(或 inotify 监听器) 自动发现。allowed-tools:默认标准 vcli 门。文件归用户,归插件所在 的 npm 包。 (面板不暴露「禁用 bundled skill」入口:DSHSkillRegistry没有公开 的按名反注册 API。需要屏蔽某个 bundled skill 时,可编辑bundled-skill/<id>/SKILL.md加disable-model-invocation: true。)
安装
下面四种安装路径,任选一种。
A. 从 npm 发布的包(用户推荐)
dsh plugin --profile web add dsh-virtuoso
npm publish 发布的是预构建的 lib/ 和 client/,用户端不需要 build,
也不需要为 prepare 脚本授权。代价是发布产物与具体版本绑定,bug 修复需要
bump 版本号再发。
B. 从本仓库,用 helper(开发期推荐)
npm install
npm run install:local # = node scripts/install-locally.mjs
# 加 --profile <name> 装到非 web profile
# 加 --pack-only 只产 tarball,不 install —— 适用于运行在沙箱里、写到
# ~/.dsh/profiles/<name>/ 会被拒绝的场景
install:local 把 dsh plugin add 不替你做的两步合上:先 npm pack
产出 dsh-virtuoso-<version>.tgz,再 dsh plugin add 那个文件。
少了 pack,pnpm 看到 ./dsh-virtuoso-0.1.0.tgz 报 ENOENT 直接挂掉 (#1)。
如果 npm pack 成功但 dsh plugin add 报 EACCES 在 profile 目录,
说明你在沙箱里跑、~/.dsh/profiles/<name>/ 只读。用 --pack-only 把 tarball
保留下来,然后在普通 shell 里执行 dsh plugin add。
C. 从本仓库,手动(等价 B,两步走)
npm install
npm run build
npm pack # 产出 dsh-virtuoso-0.1.0.tgz
dsh plugin --profile web add ./dsh-virtuoso-0.1.0.tgz
D. 从 GitHub commit(不需要本地 checkout)
# `dsh plugin add` 能直接吃 git+https tarball,但 `github:owner/repo` 这种
# shorthand 是否可用取决于 dsh 版本。下面给一个稳的写法,引用你想要的 commit/tag:
DSH_VIRTUOSO_REF="$(git -C /home/user1/git/dsh-virtuoso rev-parse HEAD)"
dsh plugin --profile web add "https://codeload.github.com/deanyou/dsh-virtuoso/tar.gz/${DSH_VIRTUOSO_REF}"
无论走哪条路:
dsh web # 重启让新 bundle 生效
…然后打开 Settings → Virtuoso。
需要 dsh web 0.1.0-rc.7+。在更老的主机上,插件会静默退出而不渲染(避免在缺失的 primitives 上爆错): 如果 Settings → Virtuoso 菜单从未出现,通常是因为这个。
你拿到什么
- 打包的 agent skills —— 上游 virtuoso-cli
的每个 skill 都作为
bundled-skill/<id>/SKILL.md一起发布,DSH 的dsh-skill-filesystem会自动发现。共 18 个 skill:SKILL 执行、Maestro、仿真 setup/run/sweep/measure、 原理图生成、Verilog-A 设计、gm/Id 设计方法学、放大器 copilot、电路优化、 ocean netlist 重新生成、两个 gotchas(SKILL shell + Spectre netlist)、 spec-driven 设计流程、tunnel-connect 引导。每一个 bundled skill 都 自带allowed-tools:门,只能跑vcli(或历史别名virtuoso) 加 Read/Write/Edit,模型无法通过这些 skill 调用任意工具。 - 设置状态面板 ——
vcli是否在 PATH、host/port/session、远端主机 / 跳板主机 / 超时 / 缓存 / 日志目录(全部从VB_*环境变量读出,与 daemon 自己读的一致)。 面板顶部的提示会告诉你:这些值是 dsh web 进程 env 读的,改完要重启 dsh web 才生效。 - 已连接的 Virtuoso —— 独立的段列出每个活动 Virtuoso 实例
(id / port / host / user / 启动时间)。自动路由层选中的那个
(
vcli session current)会打上● active标记。下次vcli skill exec落到哪台,不用猜。 - Tunnel 控制 —— 面板里
Start tunnel/Stop tunnel/Ping daemon三个按钮,分别调用vcli tunnel start|stop和vcli session list(R1 修复:session show要要<ID>,本地模式会崩)。本地模式时 tunnel 按钮禁用并提示原因;Ping daemon仍可用,通过session list探活。 - 自动刷新 —— 状态 tab 上的可选 30s 轮询开关(
⏱ off/⏱ 30s), 并行拉取 status / sessions / session-current。默认关,面板安静; 留面板等 daemon 重启时开。 - Skill 清单 —— 面板的第三个 tab 镜像
bundled-skill/,带描述预览与字节数, 让模型侧的 skill 列表和 agent 实际能调的工具集保持一处可审计。 - 新增用户级 skill —— 同一个 tab 上有新增用户级 skill 表单,把
SKILL.md 写入
$DSH_HOME/skills/<id>/。DSH 的skill-filesystemprovider 在下次重启(或通过 inotify 监听器)时自动发现。allowed-tools:默认 为标准 vcli 门。卸载插件后用户的 skill 依然存在 —— 你的 skill,你的磁盘。 正文是 Markdown —— 放bash围栏代码块放 vcli 调用,agent 会把它们当成 标准范例跟着跑。预览按钮会渲染最终的 SKILL.md;路由在正文以---开头时自动补一个空行,避免 YAML frontmatter 解析器把后面当成第二个 fence。 (面板不提供禁用 bundled skill 的入口:DSH 的SkillRegistry没有公开 按名反注册的方法。若需要屏蔽某个 bundled skill,可编辑bundled-skill/<id>/SKILL.md加上disable-model-invocation: true。) - 批量导入 tar 包 —— 同一个 tab 上有 Import from tar 按钮,
上传一个
.tar.gz,里面放一个或多个<id>/SKILL.md目录。两阶段: 服务端先解析并校验,返回每条 skill 的计划(new/exists/invalid), 用户挑哪些导入、哪些已存在的覆盖。每条 skill 原子化 —— 一条抽 取失败不会留半个 skill 在磁盘上。安全护栏:5 MiB 上限、200 条 member 上限、不收 symlink、禁止..段、禁止绝对路径。scripts/等 同级资源目录会原样写入。 - 安装命令 —— 第四个 tab 把
cargo install virtuoso-cli与 SKILL bridge 的load(...)行送进剪贴板,字符与 virtuoso-cli'sramic_bridge.il完全一致。 - 插件配置卡片 —— dsh 0.1.0-rc.7+,在 Settings → Plugins → Plugin configuration
里管理插件自身:版本、
vcli是否检测到、打包 skill 个数。 把 Allow tunnel start 关掉以禁止在隔离环境创建 tunnel,把 Allow restart 关掉以让 systemd/launchd 接管重启。
工作原理
┌──────────────────────────────────────────────────────────────────────┐
│ DSH 会话 │
│ │
│ ┌──────────────────────┐ Bash(*/vcli *) ┌────────┐ │
│ │ agent (skill: │ ───────────────────────────▶│ vcli │ │
│ │ skill-exec, │ └────────┘ │
│ │ sim-run, ...) │ │ │
│ │ bundled-skill/) │ ▼ │
│ └──────────────────────┘ ┌────────────┐ │
│ │ vcli │ │
│ ┌──────────────────────┐ /dsh-virtuoso/{status, │ daemon │ │
│ │ 浏览器设置面板 │ sessions, session-current, │ (独立 │ │
│ │ (client.js) │ ping, tunnel/*, skills, │ 进程) │ │
│ │ │ loader} │ │ │
│ └──────────────────────┘◀─────────────→ host half └────────────┘ │
│ (本插件, 浏览器) (本插件, Node) │
└──────────────────────────────────────────────────────────────────────┘
- DSH 通过
dsh-skill-filesystem自动扫到bundled-skill/。 描述进入模型的上下文,跟其它 skill 没区别;正文指导 agent 跑vcli ...。 - agent 通过
Bash工具调vcli skill exec 'let(...)'之类。vcli是独立 Rust 进程;插件本身不派生子进程。 - 浏览器面板调以下路由:
GET /dsh-virtuoso/status— 版本、profile、完整VB_*配置GET /dsh-virtuoso/sessions— 解析后的vcli session listJSONGET /dsh-virtuoso/session-current— 解析后的vcli session currentJSONPOST /dsh-virtuoso/ping— 同vcli session list(证明 daemon 活)POST /dsh-virtuoso/tunnel/start— 调vcli tunnel start,本地模式短路为vcli session list探测POST /dsh-virtuoso/tunnel/stop— 调vcli tunnel stop,本地模式 no-opGET /dsh-virtuoso/skills— bundled-skill 元数据POST /dsh-virtuoso/skills/add— 写一个 SKILL.md 到$DSH_HOME/skills/<id>/POST /dsh-virtuoso/skills/import/preview— 解析上传的 tar.gz,返回计划POST /dsh-virtuoso/skills/import/apply— 用用户的选择执行计划GET /dsh-virtuoso/loader— DSH 插件栈 host half 每次点击调用vcli一次,返回统一形状{ ok, stdout, stderr, code, reason, durationMs, mode?, note? }。
- 插件直接从
process.env读VB_HOST/VB_PORT/VB_SESSION/VB_REMOTE_HOST/VB_JUMP_HOST/VB_TIMEOUT等。设置面板展示的值 与vcli自己读的一致 —— 没有第二份真值。
安全
- 插件用 数组形式
spawn调用vcli(不走 shell)。 agent 在 SKILL 里输入的命令保持参数形式,不会被 shell 改写。 - 每一个 bundled skill 都带
allowed-tools: Bash(*/vcli *) Bash(*/virtuoso *) Read Write Edit门。scripts/sync-skills.mjs在每次同步时强制插入这道门;模型无法 通过 bundled skill 调用任意工具。 - 所有 POST 路由只接受 same-origin —— 恶意源能看到渲染出来的环境,
但执行不了任何命令。
sameOrigin故意不区分 scheme(HTTPS / HTTP): 浏览器在网络层就拦掉了 mixed-content 请求,scheme 不匹配不是真实攻击面, 真要拒反而会把开发模式下的合法请求挡掉。 - host half 不直接读
~/.cache/virtuoso_bridge。 tunnel / session 文件属于vcli自己,暴露它们的时机在 vcli 上游。 - 设置面板不导入剪贴板内容、不上传任何状态。「复制」按钮只调用
navigator.clipboard.writeText,内容是 agent 原本会敲的vcli命令字面值。 CallResult在展示前对stderr做/foo/bar/...形态的路径脱敏, 共享大屏不会泄露操作员的主目录路径。原始 stderr 仍在网线上, curl / devtools 可见;只有面板渲染是脱敏的。- 列出 bundled skills ≠ 背书上游。skill 跟插件包一起发布,
更新前请先翻一下
bundled-skill/<id>/SKILL.md。
同步上游
node scripts/sync-skills.mjs ../virtuoso-cli
scripts/sync-skills.mjs 是唯一会改 bundled-skill/ 的入口。
它清空目录,完整复制上游 skill 树,把每条 frontmatter 的 allowed-tools:
重写为 Bash(*/vcli *) Bash(*/virtuoso *) Read Write Edit,这样打包的 skill
走 vcli 路径(virtuoso 作为历史别名也接受)。脚本会插入缺失的行
(原先只在行存在时才改),因此上游漏写门时会被自动补上。脚本是幂等的:
同一上游连跑两次会产生字节级相同的 bundled-skill/。
下限 14 个 skill —— 上游若缩水到这之下,脚本会中止。
开发
npm install
npm run typecheck # tsc 跑 host (tsconfig.json) + client (tsconfig.client.json)
npm run build # tsc → lib/,tsdown → client/client.js,做 banner 校验
npm test # vitest run(72 个测试,约 750 ms)
npm run check # 上面全部 + scripts/validate-skills.mjs + check-inject-boundary.mjs
host half 跑在 dsh-cordis-host-runner 沙箱(Node + vm 隔离);
client half 跑在 dsh web bundle loader(浏览器 + 闭包工厂)。
两端类型检查都依赖 DSH 在 @deepseek-ai/cordis /
@deepseek-ai/dsh-settings / @deepseek-ai/dsh-client-ui-primitives 暴露的运行时类型。
测试
npm test 跑 117 个单元测试,跨 8 个文件:
tests/config.test.ts(22) —isRemote派生、数值强转、二进制路径缓存tests/vcli.test.ts(9) —callVcli各分支(missing/timeout/exit/spawn-error)以及数组形式 spawntests/http.test.ts(15) —sameOrigin、sendJson、readJsonBodytests/routes.test.ts(6) — 本地模式 tunnel/start 短路(空 hostname SSH 错误的回归测试)tests/skills.test.ts(5) — bundled-skill 列表不变式tests/redact-paths.test.ts(15) — 路径脱敏 helpertests/user-skill.test.ts(26) —validateUserSkillDraft、buildSkillMarkdown、resolveDshSkillsRoot/resolveUserSkillPath、fence 防护tests/skill-import.test.ts(19) — tar 解析、plan builder、apply + overwrite、安全护栏(路径穿越、symlink、超限)
监听模式:npm run test:watch。
发布到 npm
# 干跑(preflight + check + 干跑,不发):
npm run publish:dry-run
# 真实发布(.npmrc 需要带「Bypass 2FA」的 granular access token):
npm run publish:npm
scripts/publish-npm.mjs 在 npm publish 外面套了:
npm run check预检- 先
--dry-run - token 缺 2FA 绕过授权(npm 返回 403)时给出明确提示
.npmrc 持有 token,被 .gitignore 忽略。新 token 从
https://www.npmjs.com/settings/tokens 生成,选 Granular Access Token,
勾上 Bypass 2FA。
许可
MIT。本插件是 virtuoso-cli 之上的薄翻译层, virtuoso-cli 本身是 deanyou 以 MIT 发布。