dsh-embedded-workbench 0.8.12 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en-US.md +32 -9
- package/README.md +32 -9
- package/cordis.patch.yml +4 -0
- package/lib/client.js +214 -0
- package/lib/index.js +242 -211
- package/lib/types/index.d.ts +59 -51
- package/package.json +52 -33
- package/skills/embedded-workbench/SKILL.md +63 -78
- package/skills/embedded-workbench/references/platform-tool-mapping.md +59 -22
- package/skills/embedded-workbench/references/proactive-suggestions.md +27 -0
- package/src/client.js +214 -0
- package/src/index.ts +79 -35
package/README.en-US.md
CHANGED
|
@@ -8,7 +8,7 @@ Embedded C/C++ firmware toolbox — 4 agents, 8 skills covering FreeRTOS, ISR, N
|
|
|
8
8
|
storage, Keil MDK (AC5/AC6), ARMCLANG, HardFault triage, state machines,
|
|
9
9
|
architecture principles, LVGL patterns, and claim fact-checking.
|
|
10
10
|
|
|
11
|
-
**Cross-platform** — works with Claude Code, Codex CLI, Cursor, Kimi CLI, OpenCode, and
|
|
11
|
+
**Cross-platform** — works with Claude Code, Codex CLI, Cursor, Kimi CLI, OpenCode, ZCode, and DeepSeek Harness (dsh). Built on the [Agent Skills](https://agentskills.io) open standard.
|
|
12
12
|
|
|
13
13
|
## Components
|
|
14
14
|
|
|
@@ -32,8 +32,9 @@ architecture principles, LVGL patterns, and claim fact-checking.
|
|
|
32
32
|
| `c-cpp-dev` | Code generation, style, memory layout, refactoring for C/C++ |
|
|
33
33
|
| `state-machine-design` | State models, retries, timeouts, transition gates, implementation patterns |
|
|
34
34
|
| `hardfault-triage` | Processor exception triage — fault registers, stack frames, PC-to-source, root-cause classification |
|
|
35
|
+
| `fact-check` | Claim-check fallback: verifies API names, file paths, enum values, counts, and mechanism feasibility against the codebase; used by the Plan Verification Gate when logicprobe is not installed |
|
|
35
36
|
|
|
36
|
-
`logicprobe` (design-doc & plan claim verification) was **split out into its own plugin** — see [Other Plugins Recommended](#other-plugins-recommended).
|
|
37
|
+
`logicprobe` (design-doc & plan claim verification) was **split out into its own plugin** — see [Other Plugins Recommended](#other-plugins-recommended). When it is not installed, the Plan Verification Gate falls back to this plugin's built-in `fact-check` skill; only behavioral/model claims degrade to manual confirmation.
|
|
37
38
|
|
|
38
39
|
> The skill content is mostly distilled from the author's personal embedded/firmware engineering experience and code-cleanliness discipline, based on real-world pitfalls and engineering constraints.
|
|
39
40
|
|
|
@@ -84,7 +85,7 @@ Then enable in `~/.claude/settings.json`:
|
|
|
84
85
|
Native dsh support ships as a cordis plugin bundle at the repository root (the root `package.json` declares `dsh.bundle`):
|
|
85
86
|
|
|
86
87
|
- The skills are discovered as-is by dsh's `skill-filesystem` provider (Agent Skills open standard) — zero code.
|
|
87
|
-
- The bundle
|
|
88
|
+
- The bundle folds a **trimmed** first-model-step gate (the Plan Verification Gate plus a context-budget rule) into the first model step of every agent session — the dsh-native counterpart of the Claude `SessionStart` hook — and always registers the model-visible catalog entry (`cordis_inspect`). For why the 1% Rule and the Red Flags table left the payload, see [Design trade-offs and feedback](#design-trade-offs-and-feedback).
|
|
88
89
|
- The 4 custom agents are intentionally not ported — dsh's native subagent tooling covers parallel multi-agent work.
|
|
89
90
|
|
|
90
91
|
Install (native bundle, recommended):
|
|
@@ -104,13 +105,32 @@ Restart the profile, then run `dsh --profile web --dump-config`: the `id: embedd
|
|
|
104
105
|
|
|
105
106
|
## Usage
|
|
106
107
|
|
|
107
|
-
|
|
108
|
+
Skills load on demand and do not depend on injection:
|
|
108
109
|
|
|
109
|
-
-
|
|
110
|
+
- Invoke `Skill("embedded-workbench")` for the workflow and engineering policies — it picks a light or full path by risk, and does not force fixed stages
|
|
110
111
|
- Domain skills activate automatically when their `Use when` description matches your task — NOT clauses prevent false triggers (e.g., formatting-only won't load c-cpp-dev)
|
|
111
112
|
- The agent proactively suggests verification, adversarial probing, and parallel subagents when it detects state machines, behavioral claims, or multi-module tasks
|
|
112
113
|
- No manual CLAUDE.md configuration required
|
|
113
114
|
|
|
115
|
+
The plugin also folds a **trimmed** gate (about 400 tokens) into the first model step, carrying just two things: the Plan Verification Gate, and a context-budget rule (never guess a readout you cannot see; when a large step shows no signal, ask the user to decide). Set `enabled: false` to drop it entirely.
|
|
116
|
+
|
|
117
|
+
## Design trade-offs and feedback
|
|
118
|
+
|
|
119
|
+
This revision walks back an earlier decision on the evidence, and the reasoning is below — challenge it.
|
|
120
|
+
|
|
121
|
+
**Background.** We checked the official documentation for all 8 supported harnesses one by one (and read the source for Codex CLI). One assumption did not survive: **7 of the 8 expose no context-budget readout to the model at all** (Claude Code, Copilot CLI, Cursor, OpenCode, Kimi CLI, ZCode and dsh show token figures only in the user's interface; only Codex has a `get_context_remaining` tool, and it is off by default). Asking the model to judge "do I have budget to delegate?" therefore had nothing to stand on.
|
|
122
|
+
|
|
123
|
+
**So we changed two things.**
|
|
124
|
+
|
|
125
|
+
1. **Cost is now managed by trimming, not by switching injection off.** The first-step gate carries only two things: the **Plan Verification Gate** (verify, or tell the user you did not) and a **context-budget rule** (never guess a readout; when a large step shows no signal, ask the user to decide). The payload went from ~1,400 tokens to ~400 (Claude side −72%, dsh side −58%, measured) and it is on by default.
|
|
126
|
+
2. **The verification gate stays; the enforcement scaffolding goes.** The 1% Rule and the 9-row Red Flags table left the **injected payload** because they are enforcement, and reported experience shows capable models follow that kind of prompt pressure literally — producing rigid phases, unnecessary questions, and six or seven agents on a five-line task at 10–15× overhead (see [obra/superpowers#1120](https://github.com/obra/superpowers/issues/1120), [openai/codex#22005](https://github.com/openai/codex/issues/22005), [#20366](https://github.com/openai/codex/issues/20366)). The full table still lives in `Skill("embedded-workbench")`: the discipline is available on request rather than applied to everyone by default. Workflow selection likewise moved from a fixed agent chain to **risk-proportional** paths.
|
|
127
|
+
|
|
128
|
+
**Deliberately kept.** The Plan Verification Gate is intact (logicprobe → the built-in `fact-check` when it is not installed → tell the user if you used neither). Following [Superpowers Lite](https://github.com/BB-84C/superpowers-lite), safety, permission and **verification** gates are the kind to keep; process ceremony is the kind to scale back.
|
|
129
|
+
|
|
130
|
+
**Known uncertainty.** These budget interfaces change fast and we checked once, on 2026-09-25. Every cell a vendor does not document is marked `UNVERIFIED` in [`platform-tool-mapping.md`](skills/embedded-workbench/references/platform-tool-mapping.md) rather than filled in by analogy.
|
|
131
|
+
|
|
132
|
+
**Disagree?** These are judgement calls, not settled facts — especially "the Red Flags table leaves the payload" and "the gate is on by default". Open an [issue](https://github.com/AmethystLuna/embedded-workbench/issues) with the model tier, harness and counter-example you are working with; we would rather adjust on evidence.
|
|
133
|
+
|
|
114
134
|
## Codex CLI
|
|
115
135
|
|
|
116
136
|
This plugin also supports OpenAI Codex CLI. Skills follow the Agent Skills standard and work identically across both platforms. Agents are provided in Codex TOML format under `.codex/agents/`.
|
|
@@ -188,7 +208,8 @@ Skills are invoked with `$skill-name`. ZCode also auto-discovers from `.claude/s
|
|
|
188
208
|
## Requirements
|
|
189
209
|
|
|
190
210
|
- Claude Code v2.1+ / Codex CLI latest / Cursor 2.5+ / Kimi CLI latest / OpenCode latest / ZCode 3.0+
|
|
191
|
-
- DeepSeek Harness (dsh): dev preview —
|
|
211
|
+
- DeepSeek Harness (dsh): dev preview — supports `>= 0.1.0-rc.7` (the standing declaration; this round re-measured 0.1.5-rc.2 / 0.1.5-rc.3 / 0.1.6-alpha.2 / 0.1.7-alpha.1 / 0.1.7-alpha.2 / 0.1.7-rc.1 / 0.1.7-rc.2 / 0.2.0-rc.1 / 0.2.0-rc.2 — per-release evidence in [DSH-COMPATIBILITY.md](DSH-COMPATIBILITY.md))
|
|
212
|
+
- The Web Plugins-page "Gate injection" switch requires **dsh ≥ 0.1.7-alpha.1** — its settings service must project live fields. On older dsh the plugin and its 8 skills still load and still inject, with the switch simply absent and **no error**: below schemastery 3.18.3 the field degrades to an ordinary boolean, and a settings service without `whileServed` makes the client half register nothing.
|
|
192
213
|
- No external dependencies
|
|
193
214
|
|
|
194
215
|
## Configuration
|
|
@@ -197,10 +218,12 @@ In DeepSeek Harness, the bundle accepts a small configuration object:
|
|
|
197
218
|
|
|
198
219
|
| Key | Type | Default | Description |
|
|
199
220
|
|---|---|---|---|
|
|
200
|
-
| `enabled` | boolean | `true` | Set to `false` to
|
|
221
|
+
| `enabled` | boolean | `true` | Set to `false` to drop the first-step gate injection entirely; skill registration is unaffected. |
|
|
201
222
|
| `gateContent` | string | built-in gate text | Override the text injected into the first model step. |
|
|
202
223
|
|
|
203
|
-
|
|
224
|
+
The switch is editable live in the dsh Web GUI: sidebar **Plugins** → this plugin's card → "Gate injection". It takes effect without a profile restart and controls only the injected text — turning it off leaves all eight skills registered. The same card also carries a coarser row switch: turning that off unmounts the whole row (the skills and this switch go with it). Persistent overrides still go through the profile patch below.
|
|
225
|
+
|
|
226
|
+
To change it, override the row by id in your profile's `cordis.patch.yml` (the example below customises the gate text):
|
|
204
227
|
|
|
205
228
|
```yaml
|
|
206
229
|
- insert:
|
|
@@ -257,7 +280,7 @@ To report a security vulnerability, do **not** open a public issue. Use the priv
|
|
|
257
280
|
|
|
258
281
|
| Plugin | Description |
|
|
259
282
|
|--------|-------------|
|
|
260
|
-
| [logicprobe](https://github.com/AmethystLuna/logicprobe) | Claim-verification skill: checks every verifiable claim in design docs, architecture specs, and refactoring plans against the codebase, escalating behavioral claims to executable-model verification. Split out of this plugin; the Plan Verification Gate
|
|
283
|
+
| [logicprobe](https://github.com/AmethystLuna/logicprobe) | Claim-verification skill: checks every verifiable claim in design docs, architecture specs, and refactoring plans against the codebase, escalating behavioral claims to executable-model verification. Split out of this plugin; the Plan Verification Gate prefers it and falls back to the built-in `fact-check` skill when it is not installed. Install with `claude plugin install logicprobe@logicprobe` (on dsh: `dsh plugin --profile <name> add dsh-logicprobe`). |
|
|
261
284
|
| [superpowers](https://github.com/obra/superpowers) | The original agent discipline engine — skill loading enforcement, Red Flags, subagent-driven development. Many of this plugin's agent-compliance patterns (1% Rule, Red Flags, `<SUBAGENT-STOP>`, instruction priority) were adapted from Superpowers. |
|
|
262
285
|
|
|
263
286
|
## Acknowledgments
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
嵌入式 C/C++ 固件开发工具箱 — 4 个代理、8 个技能,覆盖 FreeRTOS、中断、NVM 存储、Keil
|
|
6
6
|
MDK(AC5/AC6)、ARMCLANG、HardFault 分析、状态机、架构原则、LVGL 陷阱。
|
|
7
7
|
|
|
8
|
-
**跨平台** — 支持 Claude Code、Codex CLI、Cursor、Kimi CLI、OpenCode、ZCode。基于 [Agent Skills](https://agentskills.io) 开放标准构建。
|
|
8
|
+
**跨平台** — 支持 Claude Code、Codex CLI、Cursor、Kimi CLI、OpenCode、ZCode、DeepSeek Harness (dsh)。基于 [Agent Skills](https://agentskills.io) 开放标准构建。
|
|
9
9
|
|
|
10
10
|
## 组件
|
|
11
11
|
|
|
@@ -29,8 +29,9 @@ MDK(AC5/AC6)、ARMCLANG、HardFault 分析、状态机、架构原则、LVGL
|
|
|
29
29
|
| `c-cpp-dev` | C/C++ 代码生成、风格、内存布局、重构 |
|
|
30
30
|
| `state-machine-design` | 状态模型、重试、超时、转换门控、实现模式 |
|
|
31
31
|
| `hardfault-triage` | 处理器异常分类 — 故障寄存器、栈帧、PC 定位源码、根因分类 |
|
|
32
|
+
| `fact-check` | 声称核查回退:逐条对照代码库核实 API 名、文件路径、枚举值、数量与机制可行性;logicprobe 未安装时由 Plan Verification Gate 使用 |
|
|
32
33
|
|
|
33
|
-
`logicprobe`(文档与计划声称核查技能)**已拆分为独立插件** — 见下方[其他插件推荐](#其他插件推荐)
|
|
34
|
+
`logicprobe`(文档与计划声称核查技能)**已拆分为独立插件** — 见下方[其他插件推荐](#其他插件推荐)。未安装时,Plan Verification Gate 回退到本插件自带的 `fact-check` 技能,只有行为/模型类声称降级为人工确认。
|
|
34
35
|
|
|
35
36
|
> 技能内容大多来自作者个人嵌入式/固件开发工作经验和代码洁癖,按实际工程踩坑与约束沉淀,而非泛泛的模型生成内容。
|
|
36
37
|
|
|
@@ -81,7 +82,7 @@ git clone https://github.com/AmethystLuna/embedded-workbench.git ~/.claude/plugi
|
|
|
81
82
|
原生 dsh 支持以 cordis 插件 bundle 的形式提供,位于**仓库根**(根 `package.json` 声明了 `dsh.bundle`):
|
|
82
83
|
|
|
83
84
|
- 技能遵循 Agent Skills 开放标准,被 dsh 的 `skill-filesystem` provider 原样发现——零代码。
|
|
84
|
-
- bundle
|
|
85
|
+
- bundle 把一段**精简后**的首步门禁(Plan Verification Gate + 上下文预算规则)注入每个 agent 会话的第一个模型步骤(`enabled`,默认开启)——是 Claude `SessionStart` hook 在 dsh 的原生对应物;模型可见的目录条目(`cordis_inspect`)始终注册。为什么载荷里不再有 1% Rule / Red Flags,见[设计取舍与反馈](#设计取舍与反馈)。
|
|
85
86
|
- 4 个自定义 agent 有意不移植——dsh 原生 subagent 工具已覆盖并行多 agent 工作。
|
|
86
87
|
|
|
87
88
|
安装(原生 bundle,推荐):
|
|
@@ -101,13 +102,32 @@ npx -p @deepseek-ai/dsh dsh plugin --profile web add dsh-embedded-workbench
|
|
|
101
102
|
|
|
102
103
|
## 使用
|
|
103
104
|
|
|
104
|
-
|
|
105
|
+
技能按需加载,不依赖注入:
|
|
105
106
|
|
|
106
|
-
-
|
|
107
|
+
- 调用 `Skill("embedded-workbench")` 加载工作流与工程策略——技能内部按风险比例选择轻量或完整路径,不强制固定阶段
|
|
107
108
|
- 领域技能在任务匹配其 `Use when` 描述时自动激活——NOT 子句防止误触发(如纯格式化不会加载 c-cpp-dev)
|
|
108
109
|
- Agent 在检测到状态机、行为声称或多模块任务时,主动建议验证、对抗探测和并行子代理
|
|
109
110
|
- 无需手动配置 CLAUDE.md
|
|
110
111
|
|
|
112
|
+
插件还会在会话首个模型步骤注入一段**精简**门禁(约 400 token),只含两件事:Plan Verification Gate,以及上下文预算规则(看不到读数就不要猜;工作量大且无信号时问用户,由用户决断)。设 `enabled: false` 可完全关闭。
|
|
113
|
+
|
|
114
|
+
## 设计取舍与反馈
|
|
115
|
+
|
|
116
|
+
这一版做了一次**基于证据的回退**,理由写在下面,欢迎质疑。
|
|
117
|
+
|
|
118
|
+
**背景**:我们逐个核对了 8 个受支持 harness 的官方文档(Codex 还对照了源码),发现一个此前想当然的前提是错的——**8 家里有 7 家根本不向模型暴露任何上下文预算读数**(Claude Code、Copilot CLI、Cursor、OpenCode、Kimi CLI、ZCode、dsh 都只把 token 数给用户界面;只有 Codex 有一个 `get_context_remaining` 工具,且默认关闭)。也就是说,让模型"按预算自行判断要不要委派/切窗口",本身没有依据。
|
|
119
|
+
|
|
120
|
+
**因此分两步处理**:
|
|
121
|
+
|
|
122
|
+
1. **不再用"关掉注入"控制成本,改为"瘦身"**。首步门禁现在只保留两块:**Plan Verification Gate**(未核查就必须告诉用户,不许静默跳过)和**上下文预算规则**(看不到读数就不要猜;工作量大且无信号时问用户)。载荷从约 1,400 token 降到约 400 token(Claude 侧 −72%,dsh 侧 −58%,实测值),并且默认开启。
|
|
123
|
+
2. **验证门禁保留,强制执行脚手架退场**。原来的 1% Rule 与 9 行 Red Flags 表从**注入载荷**中移除:它们属于"强制纪律",而社区实证显示这类提示会被能力较强的模型字面执行,产生僵硬阶段、多余提问,以及五行任务拉起六七个 agent 的 10–15× 开销(见 [obra/superpowers#1120](https://github.com/obra/superpowers/issues/1120)、[openai/codex#22005](https://github.com/openai/codex/issues/22005)、[#20366](https://github.com/openai/codex/issues/20366))。完整表格仍保留在 `Skill("embedded-workbench")` 正文里——需要纪律时纪律还在,只是不再对所有人默认施压。工作流选择也从固定 agent 串场改为**按风险比例**。
|
|
124
|
+
|
|
125
|
+
**有意保留的**:Plan Verification Gate 的语义没有削弱(logicprobe → 未安装则内置 `fact-check` → 两者都没用就必须告知用户)。按 [Superpowers Lite](https://github.com/BB-84C/superpowers-lite) 的原则,安全、权限与**验证**门禁是应当保留的一类,按比例裁掉的应该是流程仪式。
|
|
126
|
+
|
|
127
|
+
**已知的不确定**:各 harness 的预算接口变动很快,我们只在 2026-09-25 核对过一次;[`platform-tool-mapping.md`](skills/embedded-workbench/references/platform-tool-mapping.md) 里凡厂商未公开的格子都明确标为 `UNVERIFIED`,没有靠类比填空。
|
|
128
|
+
|
|
129
|
+
**有不同意见?** 这些取舍(尤其"Red Flags 从载荷退场"和"门禁默认开")是可讨论的判断,不是定论。欢迎到 [Issues](https://github.com/AmethystLuna/embedded-workbench/issues) 提出——写清你用的模型档位、harness 和反例,我们倾向按证据调整。
|
|
130
|
+
|
|
111
131
|
## Codex CLI
|
|
112
132
|
|
|
113
133
|
本插件同样支持 OpenAI Codex CLI。技能遵循 Agent Skills 标准,跨平台行为一致。代理以 Codex TOML 格式提供于 `.codex/agents/`。
|
|
@@ -185,7 +205,8 @@ cp -r embedded-workbench/skills/* .zcode/skills/
|
|
|
185
205
|
## 依赖
|
|
186
206
|
|
|
187
207
|
- Claude Code v2.1+ / Codex CLI 最新版 / Cursor 2.5+ / Kimi CLI 最新版 / OpenCode 最新版 / ZCode 3.0+
|
|
188
|
-
- DeepSeek Harness (dsh): dev preview —
|
|
208
|
+
- DeepSeek Harness (dsh): dev preview — 支持 `>= 0.1.0-rc.7`(沿用既有声明;本轮实测覆盖 0.1.5-rc.2 / 0.1.5-rc.3 / 0.1.6-alpha.2 / 0.1.7-alpha.1 / 0.1.7-alpha.2 / 0.1.7-rc.1 / 0.1.7-rc.2 / 0.2.0-rc.1 / 0.2.0-rc.2,逐版本证据见 [DSH-COMPATIBILITY.md](DSH-COMPATIBILITY.md))
|
|
209
|
+
- Web 端的「Gate 注入」开关需要 **dsh ≥ 0.1.7-alpha.1**(设置服务必须能投影即时字段)。更早的 dsh 上插件与 8 个 skill 照常加载、照常注入,只是开关不出现、**也不报错**:schemastery 早于 3.18.3 时该字段退化为普通布尔值;设置服务没有 `whileServed` 时客户端半侧不注册任何东西。
|
|
189
210
|
- 无外部依赖
|
|
190
211
|
|
|
191
212
|
## 配置
|
|
@@ -194,10 +215,12 @@ cp -r embedded-workbench/skills/* .zcode/skills/
|
|
|
194
215
|
|
|
195
216
|
| 键 | 类型 | 默认值 | 说明 |
|
|
196
217
|
|---|---|---|---|
|
|
197
|
-
| `enabled` | boolean | `true` | 设为 `false`
|
|
218
|
+
| `enabled` | boolean | `true` | 设为 `false` 可完全关闭首步 Gate 注入;技能注册不受影响。 |
|
|
198
219
|
| `gateContent` | string | 内置 gate 文本 | 覆盖注入到首轮模型上下文中的文本。 |
|
|
199
220
|
|
|
200
|
-
在 profile
|
|
221
|
+
在 dsh Web GUI 里可以直接改这个开关:侧边栏 **插件** → 本插件卡片 → 「Gate 注入」。它实时生效,不必重启 profile,而且只管注入的那段文本——关掉后 8 个技能照常注册。同一张卡片上还有一个更粗粒度的行开关:关掉它会整行卸载插件(技能和这个开关一起消失)。要持久化覆盖,仍按下面的 profile patch 写。
|
|
222
|
+
|
|
223
|
+
在 profile 的 `cordis.patch.yml` 中按 row id 覆盖(下面的例子自定义 Gate 文本):
|
|
201
224
|
|
|
202
225
|
```yaml
|
|
203
226
|
- insert:
|
|
@@ -254,7 +277,7 @@ bash tests/skill-triggering/run-all.sh
|
|
|
254
277
|
|
|
255
278
|
| 插件 | 简介 |
|
|
256
279
|
|------|------|
|
|
257
|
-
| [logicprobe](https://github.com/AmethystLuna/logicprobe) | 声称核查技能:逐条核验设计文档、架构规格、重构计划中的可验证声称与代码库是否一致,行为类声称升级为可执行模型验证。自本插件拆分;Plan Verification Gate
|
|
280
|
+
| [logicprobe](https://github.com/AmethystLuna/logicprobe) | 声称核查技能:逐条核验设计文档、架构规格、重构计划中的可验证声称与代码库是否一致,行为类声称升级为可执行模型验证。自本插件拆分;Plan Verification Gate 优先使用它,未安装时回退到内置 `fact-check` 技能。安装:`claude plugin install logicprobe@logicprobe`(dsh:`dsh plugin --profile <name> add dsh-logicprobe`)。 |
|
|
258
281
|
| [superpowers](https://github.com/obra/superpowers) | 原始 agent 纪律引擎——技能加载强制、Red Flags、子代理驱动开发。本插件的多项 agent 合规模式(1% Rule、Red Flags、`<SUBAGENT-STOP>`、指令优先级)均借鉴自 Superpowers。 |
|
|
259
282
|
|
|
260
283
|
## 致谢
|
package/cordis.patch.yml
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
# Row ids are stable identity in the config tree; later layers (the user's
|
|
4
4
|
# profile cordis.patch.yml, $DSH_HOME/cordis.patch.yml, --patch overlays)
|
|
5
5
|
# override a row by id, replacing the whole `config` (no deep merge).
|
|
6
|
+
#
|
|
7
|
+
# The first-model-step gate is ON by default and deliberately small — it carries
|
|
8
|
+
# the Plan Verification Gate and the context-budget rule, not the 1% Rule /
|
|
9
|
+
# Red Flags enforcement scaffolding. Set `enabled: false` per profile to drop it.
|
|
6
10
|
|
|
7
11
|
- insert:
|
|
8
12
|
- id: embedded-workbench
|
package/lib/client.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* embedded-workbench — browser half: the gate-injection switch on the dsh Web
|
|
3
|
+
* client's Plugins page.
|
|
4
|
+
*
|
|
5
|
+
* The Plugins page (`@deepseek-ai/dsh-client-ui-plugin-manager`) owns the
|
|
6
|
+
* sidebar **Plugins** entry and declares the slots a bundle's own configuration
|
|
7
|
+
* registers into. This module contributes one `plugins.bundle.config` entry,
|
|
8
|
+
* keyed by this package's npm name, so the switch renders on
|
|
9
|
+
* embedded-workbench's own page between its description and its rows.
|
|
10
|
+
*
|
|
11
|
+
* Why the switch writes through `configForms` rather than reaching for the
|
|
12
|
+
* profile file: dsh's settings service exposes only the Config fields declared
|
|
13
|
+
* `.volatile()`, and it rejects a write to any other path. `enabled` is such a
|
|
14
|
+
* field (see `src/index.ts`), so flipping the switch is an ordinary
|
|
15
|
+
* revision-fenced settings write that the running Host picks up in place — the
|
|
16
|
+
* injection there re-reads the reference on every model step.
|
|
17
|
+
*
|
|
18
|
+
* Shape: this is a prebuilt module-system bundle, not a source module. It calls
|
|
19
|
+
* `window.__ModuleLoader__.load({ id, factory })` with this package's resolved
|
|
20
|
+
* npm name, and `factory` returns the cordis plugin face. Only the client
|
|
21
|
+
* baseline is requested (`react` and
|
|
22
|
+
* `@deepseek-ai/dsh-client-ui-primitives`); every other capability arrives
|
|
23
|
+
* through cordis `inject`. `scripts/build-client.mjs` publishes this file
|
|
24
|
+
* verbatim as `lib/client.js`.
|
|
25
|
+
*
|
|
26
|
+
* @module dsh-embedded-workbench/client
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
window.__ModuleLoader__.load({
|
|
30
|
+
id: 'dsh-embedded-workbench',
|
|
31
|
+
factory: (require) => {
|
|
32
|
+
const React = require('react')
|
|
33
|
+
const { Button, Switch } = require('@deepseek-ai/dsh-client-ui-primitives')
|
|
34
|
+
|
|
35
|
+
/** Settings namespace: the Loader entry id this bundle's patch declares. */
|
|
36
|
+
const NS = 'embedded-workbench'
|
|
37
|
+
/** `plugins.bundle.config` key: the bundle's npm package name. */
|
|
38
|
+
const PACKAGE = 'dsh-embedded-workbench'
|
|
39
|
+
/** This page's dictionary namespace. */
|
|
40
|
+
const LOCALE_NS = 'embedded-workbench.plugins'
|
|
41
|
+
/** The Config field the switch writes inside the namespace's section. */
|
|
42
|
+
const FIELD = 'enabled'
|
|
43
|
+
|
|
44
|
+
/** English copy. */
|
|
45
|
+
const en = {
|
|
46
|
+
title: 'Gate injection',
|
|
47
|
+
label: 'Inject the gate text',
|
|
48
|
+
hint: 'Folds the Plan Verification Gate and the context-budget rule into the first model step of every session. Turning it off leaves all eight skills registered — only the injected text is dropped.',
|
|
49
|
+
overridden: 'Overridden',
|
|
50
|
+
reset: 'Reset to default',
|
|
51
|
+
readOnly: 'This deployment stores settings read-only.',
|
|
52
|
+
unavailable: 'This plugin is not loaded, so it cannot be configured right now.',
|
|
53
|
+
saveFailed: 'The deployment did not accept that value; the switch shows what is stored.',
|
|
54
|
+
}
|
|
55
|
+
/** Simplified Chinese copy. */
|
|
56
|
+
const zh = {
|
|
57
|
+
title: 'Gate 注入',
|
|
58
|
+
label: '注入 gate 文本',
|
|
59
|
+
hint: '把 Plan Verification Gate 与上下文预算规则折进每个会话的第一个模型步。关掉后 8 个技能仍然注册,只是不再注入那段提示文本。',
|
|
60
|
+
overridden: '已覆盖',
|
|
61
|
+
reset: '恢复默认',
|
|
62
|
+
readOnly: '本部署的设置为只读。',
|
|
63
|
+
unavailable: '该插件当前未加载,暂时无法配置。',
|
|
64
|
+
saveFailed: '本部署没有接受这个值,开关显示的是已存下的状态。',
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Required cordis services. */
|
|
68
|
+
const inject = ['slots', 'locale', 'configForms']
|
|
69
|
+
|
|
70
|
+
const GROUP = { display: 'flex', flexDirection: 'column', gap: '8px' }
|
|
71
|
+
const TITLE = { margin: 0, fontSize: '14px', fontWeight: '500', lineHeight: '22px' }
|
|
72
|
+
const ROW = { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '16px' }
|
|
73
|
+
const LABEL = { fontSize: '13px', lineHeight: '20px' }
|
|
74
|
+
const NOTE = { margin: 0, fontSize: '12px', lineHeight: '18px', color: 'var(--dsw-alias-label-tertiary)' }
|
|
75
|
+
const FAILED = { margin: 0, fontSize: '12px', lineHeight: '18px', color: 'var(--dsw-alias-state-error-primary)' }
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Whether a settings-layer value carries this field, which is what marks it
|
|
79
|
+
* overridden: an override equal to the default is still an override.
|
|
80
|
+
* @param layer - the raw user layer the form snapshot carries.
|
|
81
|
+
* @returns whether the layer holds the field.
|
|
82
|
+
*/
|
|
83
|
+
function carries(layer) {
|
|
84
|
+
return layer !== null && typeof layer === 'object' && Object.prototype.hasOwnProperty.call(layer, FIELD)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Render the gate-injection switch, or the note saying why it cannot render.
|
|
89
|
+
* @param props - the page's `t` seat, the bound form snapshot hook, and the write actions.
|
|
90
|
+
* @returns the body of this bundle's configuration section.
|
|
91
|
+
*/
|
|
92
|
+
function InjectionCard(props) {
|
|
93
|
+
const t = props.t
|
|
94
|
+
const state = props.useInjectionForm((snapshot) => snapshot)
|
|
95
|
+
const [pending, setPending] = React.useState(false)
|
|
96
|
+
const [failed, setFailed] = React.useState(false)
|
|
97
|
+
|
|
98
|
+
/** Run one settings write and report a refusal or a transport failure. */
|
|
99
|
+
const write = (run) => {
|
|
100
|
+
setPending(true)
|
|
101
|
+
setFailed(false)
|
|
102
|
+
Promise.resolve(run()).then(
|
|
103
|
+
(accepted) => {
|
|
104
|
+
setPending(false)
|
|
105
|
+
setFailed(accepted === false)
|
|
106
|
+
},
|
|
107
|
+
() => {
|
|
108
|
+
setPending(false)
|
|
109
|
+
setFailed(true)
|
|
110
|
+
},
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (state.status !== 'ready') {
|
|
115
|
+
return React.createElement('p', { style: NOTE }, t('unavailable'))
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const section = state.value !== null && typeof state.value === 'object' ? state.value : {}
|
|
119
|
+
// The schema default is `true`; only an explicit false means off.
|
|
120
|
+
const checked = section[FIELD] !== false
|
|
121
|
+
const overridden = carries(state.user)
|
|
122
|
+
const locked = state.writable !== true || pending
|
|
123
|
+
|
|
124
|
+
const children = [
|
|
125
|
+
React.createElement('h4', { key: 'title', style: TITLE }, t('title')),
|
|
126
|
+
React.createElement('div', { key: 'row', style: ROW }, [
|
|
127
|
+
React.createElement('span', { key: 'label', style: LABEL }, t('label')),
|
|
128
|
+
React.createElement(Switch, {
|
|
129
|
+
key: 'switch',
|
|
130
|
+
checked,
|
|
131
|
+
disabled: locked,
|
|
132
|
+
label: t('label'),
|
|
133
|
+
onChange: (next) => write(() => props.setEnabled(next)),
|
|
134
|
+
}),
|
|
135
|
+
]),
|
|
136
|
+
React.createElement('p', { key: 'hint', style: NOTE }, state.writable === true ? t('hint') : t('readOnly')),
|
|
137
|
+
]
|
|
138
|
+
|
|
139
|
+
if (overridden) {
|
|
140
|
+
children.push(
|
|
141
|
+
React.createElement('div', { key: 'overridden', style: ROW }, [
|
|
142
|
+
React.createElement('span', { key: 'badge', style: NOTE }, t('overridden')),
|
|
143
|
+
React.createElement(
|
|
144
|
+
Button,
|
|
145
|
+
{
|
|
146
|
+
key: 'reset',
|
|
147
|
+
variant: 'outline',
|
|
148
|
+
size: 'sm',
|
|
149
|
+
disabled: locked,
|
|
150
|
+
onClick: () => write(() => props.resetEnabled()),
|
|
151
|
+
},
|
|
152
|
+
t('reset'),
|
|
153
|
+
),
|
|
154
|
+
]),
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (failed) {
|
|
159
|
+
children.push(React.createElement('p', { key: 'failed', style: FAILED, role: 'alert' }, t('saveFailed')))
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return React.createElement('div', { style: GROUP }, children)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Mount the switch while the Host serves embedded-workbench's settings
|
|
167
|
+
* namespace.
|
|
168
|
+
* @param ctx - the browser plugin context.
|
|
169
|
+
*/
|
|
170
|
+
function apply(ctx) {
|
|
171
|
+
ctx.effect(() => ctx.locale.register(LOCALE_NS, { zh, en }), 'dsh-embedded-workbench: dictionaries')
|
|
172
|
+
// `whileServed` is the registration barrier that keeps this page alive only
|
|
173
|
+
// while the Host serves the namespace. Hosts predating it (measured: dsh
|
|
174
|
+
// 0.1.5-rc.3 and 0.1.6-alpha.2) have no live settings field to offer at all,
|
|
175
|
+
// so there is nothing to register — and calling it there would throw during
|
|
176
|
+
// this plugin's own activation, which the Web boot audit then reports as a
|
|
177
|
+
// failed client entry. Degrade to no page instead.
|
|
178
|
+
if (typeof ctx.configForms.whileServed !== 'function') return
|
|
179
|
+
// The page renders the section only for a bundle whose package name is in
|
|
180
|
+
// its configuration ledger, and the ledger follows this registration. The
|
|
181
|
+
// registration in turn waits for the namespace to be served, so a profile
|
|
182
|
+
// whose embedded-workbench row is switched off shows no trace of the
|
|
183
|
+
// switch.
|
|
184
|
+
ctx.effect(
|
|
185
|
+
() =>
|
|
186
|
+
ctx.configForms.whileServed([NS], () => {
|
|
187
|
+
const form = ctx.configForms.get(NS)
|
|
188
|
+
const source = {
|
|
189
|
+
getSnapshot: () => form.getSnapshot(),
|
|
190
|
+
subscribe: (listener) => form.subscribe(listener),
|
|
191
|
+
}
|
|
192
|
+
return ctx.slots.inject('plugins.bundle.config', () =>
|
|
193
|
+
ctx.slots.register(
|
|
194
|
+
{
|
|
195
|
+
name: 'plugins.bundle.config',
|
|
196
|
+
key: PACKAGE,
|
|
197
|
+
locale: LOCALE_NS,
|
|
198
|
+
inject: () => ({
|
|
199
|
+
hooks: { injectionForm: source },
|
|
200
|
+
setEnabled: (next) => form.set(FIELD, next),
|
|
201
|
+
resetEnabled: () => form.unset(FIELD),
|
|
202
|
+
}),
|
|
203
|
+
},
|
|
204
|
+
InjectionCard,
|
|
205
|
+
),
|
|
206
|
+
)
|
|
207
|
+
}),
|
|
208
|
+
'dsh-embedded-workbench: gate-injection switch',
|
|
209
|
+
)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return { inject, apply }
|
|
213
|
+
},
|
|
214
|
+
})
|