dsh-showcase 0.1.2 → 0.1.4
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/CHANGELOG.md +35 -0
- package/README.md +83 -21
- package/README.zh-CN.md +3 -1
- package/package.json +17 -14
- package/plugin/client.js +39 -34
- package/plugin/dijiang-layout.js +161 -0
- package/plugin/dijiang-motion.js +101 -0
- package/plugin/dijiang-style.js +37 -0
- package/plugin/index.d.ts +20 -7
- package/plugin/index.js +72 -68
- package/plugin/layout-summary.d.ts +1 -0
- package/plugin/layout-summary.js +111 -23
- package/plugin/poster-html.js +117 -24
- package/plugin/project-io.d.ts +5 -0
- package/plugin/project-io.js +82 -0
- package/plugin/redaction.js +26 -0
- package/plugin/report-content.js +67 -0
- package/plugin/report-schema.js +18 -8
package/CHANGELOG.md
CHANGED
|
@@ -4,8 +4,36 @@
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
后续变更将在下一版本发布前继续记录在这里。
|
|
8
|
+
|
|
9
|
+
## [0.1.4] - 2026-10-04
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- 迁移到 DSH `0.2.0-rc.2` 的 SettingsForms 与 Plugins 配置槽位:主题和海报开关改用 `.volatile()` 配置及官方行配置页,保留现有 profile 选择并支持修订号冲突保护。
|
|
14
|
+
- 适配 DSH `0.2` 的严格工具输出 JSON Schema,移除旧版属性级 `required` 写法;插件不再抢占 Connection 的私有 RPC 通道,避免 Web/API Gateway 冲突。
|
|
15
|
+
- 将客户端入口从旧 Settings 列表迁移到 `plugins.row.config`,在 summary/page 两种视图下均保持单一、可用的配置卡。
|
|
16
|
+
- Markdown-only 摘要遇到项目外部 symlink 时静默跳过越界记录,不再把外部视口标签写入文档;海报生成仍严格拒绝越界路径。
|
|
17
|
+
- GitHub Actions 改用兼容 Node 24 的官方 Action 版本,避免旧运行时弃用提醒。
|
|
18
|
+
- 浏览器拒绝本地存储或偏好 JSON 损坏时,离线报告保留导出时的明暗、强调色和动效设置;无效设置不会覆盖有效值。
|
|
19
|
+
- 手机端显示设置的操作区域至少为 44px,并保留矮屏滚动边界。
|
|
20
|
+
- 两套主题统一保留测试回执的具体输出;蓝色大肥鱼主题新增可展开的命令输出与截断提示,不再只显示命令摘要。
|
|
21
|
+
|
|
22
|
+
- CLI 与插件共享报告校验和脱敏,覆盖命令、任务说明及多种凭据格式;损坏的旧报告不再被静默覆盖。
|
|
23
|
+
- 使用项目级跨进程写锁与真实路径检查,防止并发产物混写及 junction 越界写入;保留回滚失败时的备份。
|
|
24
|
+
- 修复 Git 重命名、monorepo 子目录、历史比较和 detached HEAD;记录提交 SHA 与工作区指纹,测试后的变更不再遗漏。
|
|
25
|
+
- 状态以实际回执为准;校验截图尺寸、时效、Before/After 和 DPR,并在 HTML 中展示复核警告。
|
|
26
|
+
- 长文本海报与矮屏布局改为内容自适应;HTML 内嵌主题素材,数据与 Markdown 导出实际下载文件。
|
|
27
|
+
- 设置连接失败后可以重试;测试输出保留头尾并标注截断,支持 UTF-8 BOM 配置与混合技术栈检测。
|
|
28
|
+
- 移除未使用的 jsdom,约束 Zod 主版本,更新 Vitest 安全补丁,并扩展 Windows/Linux CI 矩阵。
|
|
29
|
+
|
|
7
30
|
### Added
|
|
8
31
|
|
|
32
|
+
- 依据终末地官网实际样式校正社区主题:白色 / 中性灰 / 硬黑分区、`#fffa00` 信号黄、局部地形等高线、灰色导航选中态;加载页使用 `#141414` 深底、旋转仪表与黄色横向扫幕,保留可持久化的明暗和动效设置。
|
|
33
|
+
- 复核信息收紧到报告顶部,变更与测试前置,单张 / 双张截图按记录数量适配;保留鱼主题与旧版终末地。
|
|
34
|
+
|
|
35
|
+
- 终末地补齐任务摘要、可切换逐行 Diff、同页同视口前后截图对比、脱敏分类及 JSON / Markdown 下载;演示截图独立采集,不复用鱼主题图片。
|
|
36
|
+
- CLI 可保留经过脱敏的有限文本补丁;旧报告继续兼容,二进制、未跟踪、超限和缺失补丁均有明确说明。
|
|
9
37
|
- 终末地帝江号与蓝色大肥鱼两套独立海报主题。
|
|
10
38
|
- DSH 插件设置、Markdown 摘要和可选的自包含 HTML 海报。
|
|
11
39
|
- 跨项目源码发现、证据时效检查、路径约束和极端输入保护。
|
|
@@ -14,6 +42,13 @@
|
|
|
14
42
|
|
|
15
43
|
### Changed
|
|
16
44
|
|
|
45
|
+
- 更新 README 的鸽子中转站介绍,补充当前模型覆盖、订阅方式与不定期抽奖赠 Token 福利说明。
|
|
46
|
+
- 加强终末地首屏主视觉:扩大公告式标题、提高等高线存在感,加入黑色结构面与斜切信号黄带,让工业编辑风格形成明确视觉峰值。
|
|
47
|
+
- 终末地交付报告收敛状态色为黑 / 灰 / 信号黄,减少红绿仪表盘噪音;桌面标题、摘要和分区增加留白,移动端阶段导航改为文档流内的吸顶栏,避免遮挡 Diff 与回执。
|
|
48
|
+
- 加强终末地主屏层次:将交付中继融入黑灰标题带,局部复用等高线素材,使用深色命令输出与浅色文件清单,并补充导航、回执和按钮的交互反馈。
|
|
49
|
+
- 终末地演示与插件 HTML 共用交付工作台:单条阶段导航、实际界面证据、变更档案、可展开回执和交付中继;无截图时显示证据缺口,不再展示装饰性拓扑。
|
|
50
|
+
- 增加路径复制、原图下载与自包含 HTML 下载;保留旧版终末地对照入口,不改变蓝色大肥鱼的视觉布局。
|
|
51
|
+
- 修复加载仪表旋转中心和进度编号重叠,保留厚进度条与黄色斜切扫幕;主题纹理加载失败不再阻断演示报告。
|
|
17
52
|
- 重写 GitHub 首页,明确安装、使用、隐私、素材和发布边界。
|
|
18
53
|
- 强化终末地帝江号加载器的机械校准环、厚进度轨和黄色切换幕。
|
|
19
54
|
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/DoveLi-Gu/dsh-showcase/actions/workflows/ci.yml)
|
|
4
4
|
[](LICENSE)
|
|
5
|
-
[](https://nodejs.org/)
|
|
6
6
|
|
|
7
7
|
**把编程 Agent 的改动和测试结果,整理成可核验的中文交付报告。**
|
|
8
8
|
|
|
@@ -21,8 +21,10 @@ dsh-showcase 是一个本地运行的 DSH 插件。它读取目标项目的 Git
|
|
|
21
21
|
<details>
|
|
22
22
|
<summary>终末地帝江号(机械工业 / 等高线 / 黄黑校准)</summary>
|
|
23
23
|
|
|
24
|
-
<p><img src="docs/assets/dijiang-desktop-latest.png" alt="
|
|
25
|
-
<p><img src="docs/assets/dijiang-mobile-latest.png" alt="
|
|
24
|
+
<p><img src="docs/assets/dijiang-desktop-latest.png" alt="终末地帝江号当前桌面首屏,1000 x 900" width="680"></p>
|
|
25
|
+
<p><img src="docs/assets/dijiang-mobile-latest.png" alt="终末地帝江号当前移动端首屏,455 x 1024" width="220"></p>
|
|
26
|
+
|
|
27
|
+
终末地主题采用白、浅灰与硬黑分区,搭配信号黄、局部等高线和细分隔线。左侧阶段导航在手机上收至底部;变更档案与验证回执前置,截图保留完整画面。深色加载页以旋转仪表和信号色横向扫幕进入报告。右上角可切换明暗、谷地黄 / 武陵青、动效及背景帧率上限。这些是社区主题设计,预览中的演示数据不代表目标项目已通过验证。
|
|
26
28
|
</details>
|
|
27
29
|
|
|
28
30
|
<details>
|
|
@@ -34,8 +36,8 @@ dsh-showcase 是一个本地运行的 DSH 插件。它读取目标项目的 Git
|
|
|
34
36
|
|
|
35
37
|
## 你需要什么
|
|
36
38
|
|
|
37
|
-
- **必须**:已经可以运行的 DSH Web
|
|
38
|
-
- **必须**:Node.js
|
|
39
|
+
- **必须**:已经可以运行的 DSH Web 环境(当前插件兼容 DSH `0.2.0-rc.2` 及同一 0.2 系列);
|
|
40
|
+
- **必须**:Node.js `22.19+` 或 `24+` 和 npm,用于安装本仓库及运行采集 CLI;
|
|
39
41
|
- **可选**:Git。没有 Git 时仍会生成报告,但状态会明确标为 `partial`;
|
|
40
42
|
- **可选**:Playwright 或其他浏览器验收工具。截图不是后端、CLI、库项目的必需项。
|
|
41
43
|
|
|
@@ -45,7 +47,7 @@ dsh-showcase 是一个本地运行的 DSH 插件。它读取目标项目的 Git
|
|
|
45
47
|
|
|
46
48
|
| 你现在要做的事 | dsh-showcase 的输出 |
|
|
47
49
|
| --- | --- |
|
|
48
|
-
| 向别人说明这次改了什么 | Git
|
|
50
|
+
| 向别人说明这次改了什么 | Git 文件清单、增删行统计、当前引用;终末地报告可切换文件查看保留的逐行 Diff |
|
|
49
51
|
| 证明测试确实运行过 | 测试命令、退出码、耗时和脱敏后的输出 |
|
|
50
52
|
| 检查桌面和移动端界面 | 最多 3 张经过路径、时间和主题校验的截图 |
|
|
51
53
|
| 给交付结果做归档 | Markdown 摘要和可独立打开的 HTML 海报 |
|
|
@@ -53,6 +55,10 @@ dsh-showcase 是一个本地运行的 DSH 插件。它读取目标项目的 Git
|
|
|
53
55
|
|
|
54
56
|
支持前端、后端、CLI、Node.js、Python、Rust、Go、Java、库和静态 HTML 项目。
|
|
55
57
|
|
|
58
|
+
终末地 HTML 还包含任务耗时、增删总量、脱敏分类明细,以及 HTML / JSON / Markdown 下载。同页同视口的 Before / After 截图可用滑块对比。JSON 是脱敏后的报告数据,不包含图片二进制;HTML 内嵌图片,可以离线查看和操作。
|
|
59
|
+
|
|
60
|
+
`capture` 会为前 20 个变更文件尝试采集文本 Diff,每份最多保留 16,000 个字符并标注截断。二进制、未跟踪、超大或无法读取的文件只保留明确的缺失说明;旧报告没有 Diff 时不会生成假差异。补丁仍需人工复核后再对外分享。
|
|
61
|
+
|
|
56
62
|
工作流只有一条:
|
|
57
63
|
|
|
58
64
|
```text
|
|
@@ -82,7 +88,7 @@ dsh plugin --profile web add "C:\tools\dsh-showcase"
|
|
|
82
88
|
|
|
83
89
|
然后重启 `dsh web`,再新建一个会话。若命令提示 `dsh` 不存在,先安装并确认 DSH CLI 已加入 `PATH`;这不是本插件自身的安装错误。
|
|
84
90
|
|
|
85
|
-
打开 DSH
|
|
91
|
+
打开 DSH 侧栏的 **插件**,进入 `dsh-showcase`,点击组件 `dsh-showcase/plugin` 的 **配置**,找到 **布局证据产物**。这里可以选择:
|
|
86
92
|
|
|
87
93
|
- **终末地帝江号**:机械工业、密集等高线和黄黑校准色;
|
|
88
94
|
- **蓝色大肥鱼**:浅蓝背景、角色主视觉和钴蓝强调;
|
|
@@ -183,6 +189,20 @@ $showcaseRepo = "C:\tools\dsh-showcase"
|
|
|
183
189
|
|
|
184
190
|
</details>
|
|
185
191
|
|
|
192
|
+
## 在 DSH 生态中被发现
|
|
193
|
+
|
|
194
|
+
DeepSeek Harness 官方目前没有单独的插件提交审核页面;官方仓库建议插件作者给 GitHub 仓库添加 `dsh-plugin` Topic,用于社区发现。本仓库已经配置 `dsh-plugin`、`deepseek-harness`、`dsh` 和 `cordis` 等主题标签。
|
|
195
|
+
|
|
196
|
+
部分社区插件目录会定期扫描 `dsh-plugin` Topic,并根据公开仓库的 `package.json`、`dsh.bundle.patch`、入口文件和版本信息生成卡片。收录通常存在延迟,目录属于社区项目,不代表 DeepSeek 官方背书;用户仍可直接使用 DSH 官方命令安装:
|
|
197
|
+
|
|
198
|
+
~~~powershell
|
|
199
|
+
dsh plugin --profile web add dsh-showcase
|
|
200
|
+
~~~
|
|
201
|
+
|
|
202
|
+
- 官方生态说明:[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)
|
|
203
|
+
- 社区目录示例:[DSH Plugins Marketplace](https://github.com/bradeGithub/DSH-Plugins-Marketplace)
|
|
204
|
+
- 社区展示与反馈:DeepSeek Harness 仓库的 **Show Your Plugins** Discussions
|
|
205
|
+
|
|
186
206
|
## 赞助商
|
|
187
207
|
|
|
188
208
|
<div align="center">
|
|
@@ -194,12 +214,14 @@ $showcaseRepo = "C:\tools\dsh-showcase"
|
|
|
194
214
|
<p><strong>稳定、透明、易接入的 AI API 中转服务</strong></p>
|
|
195
215
|
</div>
|
|
196
216
|
|
|
197
|
-
鸽子中转站(Pigeon API Relay)兼容 OpenAI API
|
|
217
|
+
鸽子中转站(Pigeon API Relay)兼容 OpenAI API 格式,持续跟进主流模型与可用线路。当前重点覆盖 GPT-6.1 Sol、GPT-6 Astra / Sol / Luna、GPT-5.6 全系列、GPT-5.5 / 5.4,Claude Opus 5、Fable 5、Sonnet 5,DeepSeek V4 Pro / Flash、Gemini、Grok,以及 Qwen、Kimi、GLM 等国产模型,适用于 AI 编程、Agent 工具调用、客户端接入、日常对话、内容创作和图像生成等场景。
|
|
218
|
+
|
|
219
|
+
平台支持余额按量与订阅套餐两种方式,提供灵活的日卡、月卡方案;你可以在一个控制台中统一管理 API Key、模型调用、余额、用量和订阅权益,并查看模型价格、服务状态与详细接入文档。模型列表、可用线路、价格和套餐权益会随站内运营持续更新,最终以鸽子中转站实时信息为准。
|
|
198
220
|
|
|
199
|
-
|
|
221
|
+
站长也会不定期组织抽奖和用户福利,赠送 Token、体验额度或其他使用权益。活动时间、参与方式与发放规则以鸽子中转站公告为准,欢迎关注站内动态。
|
|
200
222
|
|
|
201
223
|
<p align="center">
|
|
202
|
-
<code>兼容 OpenAI API</code> · <code>GPT-5.6
|
|
224
|
+
<code>兼容 OpenAI API</code> · <code>GPT-6 / GPT-5.6</code> · <code>DeepSeek V4</code> · <code>余额按量</code> · <code>日卡/月卡订阅</code> · <code>不定期抽奖送 Token</code>
|
|
203
225
|
</p>
|
|
204
226
|
|
|
205
227
|
<p align="center">
|
|
@@ -227,8 +249,9 @@ $showcaseRepo = "C:\tools\dsh-showcase"
|
|
|
227
249
|
</td>
|
|
228
250
|
<td>
|
|
229
251
|
<p><strong>稳定、透明、易接入的 AI API 中转服务,兼容 OpenAI API 格式。</strong></p>
|
|
230
|
-
<p
|
|
231
|
-
<p
|
|
252
|
+
<p>当前重点覆盖 GPT-6.1 Sol、GPT-6 Astra / Sol / Luna、GPT-5.6 全系列、GPT-5.5 / 5.4,Claude Opus 5、Fable 5、Sonnet 5,DeepSeek V4 Pro / Flash、Gemini、Grok,以及 Qwen、Kimi、GLM 等国产模型,适用于 AI 编程、Agent 工具调用、客户端接入、日常对话、内容创作和图像生成等场景。</p>
|
|
253
|
+
<p>平台支持余额按量与订阅套餐,提供日卡、月卡等灵活方案;用户可以统一管理 API Key、模型调用、余额、用量和订阅权益,并查看模型价格、服务状态与详细接入文档。模型列表、线路、价格和套餐权益会持续更新,最终以站内实时信息为准。</p>
|
|
254
|
+
<p><strong>不定期福利:</strong>站长会组织抽奖并赠送 Token、体验额度或其他使用权益,活动时间和参与规则以站内公告为准。</p>
|
|
232
255
|
</td>
|
|
233
256
|
</tr>
|
|
234
257
|
</tbody>
|
|
@@ -264,12 +287,15 @@ $showcaseRepo = "C:\tools\dsh-showcase"
|
|
|
264
287
|
|
|
265
288
|
| 检测到的文件 | 默认测试 |
|
|
266
289
|
| --- | --- |
|
|
267
|
-
| `package.json` 中存在 `scripts.test` | `npm test` |
|
|
290
|
+
| `package.json` 中存在 `scripts.test` | 按锁文件选择 `pnpm test`、`yarn test`、`bun run test`,否则 `npm test` |
|
|
268
291
|
| `pyproject.toml`、`pytest.ini`、`setup.cfg` 或 `requirements.txt` | `pytest -q` |
|
|
269
292
|
| `Cargo.toml` | `cargo test` |
|
|
270
293
|
| `go.mod` | `go test ./...` |
|
|
271
294
|
| `pom.xml` | `mvn test` |
|
|
272
295
|
| `gradlew.bat` | `gradlew.bat test` |
|
|
296
|
+
| POSIX 系统的 `gradlew` | `./gradlew test` |
|
|
297
|
+
|
|
298
|
+
混合技术栈会保留各语言的默认命令。自动检测只是初始建议,运行前请检查 `.showcase/config.json`,使用项目实际支持的、非 watch 模式的测试命令。
|
|
273
299
|
|
|
274
300
|
测试也可以单独设置超时:
|
|
275
301
|
|
|
@@ -289,7 +315,7 @@ $showcaseRepo = "C:\tools\dsh-showcase"
|
|
|
289
315
|
|
|
290
316
|
## 截图证据
|
|
291
317
|
|
|
292
|
-
CLI 会保留 `report.json`
|
|
318
|
+
CLI 会保留 `report.json` 中已经存在的截图记录,但不会自动启动浏览器截图,也不会把旧截图时间更新成当前时间。建议先保存代码,再截图,最后运行 `capture` 并生成摘要。
|
|
293
319
|
|
|
294
320
|
前端项目可以用 Playwright、浏览器验收工具或自己的截图脚本,把图片保存在目标项目内,再把记录加入 `report.json.screenshots`:
|
|
295
321
|
|
|
@@ -297,7 +323,6 @@ CLI 会保留 `report.json` 中已经存在的截图记录,但不会自动启
|
|
|
297
323
|
{
|
|
298
324
|
"id": "desktop-after",
|
|
299
325
|
"label": "桌面完成态",
|
|
300
|
-
"theme": "frontier-signal",
|
|
301
326
|
"viewport": {
|
|
302
327
|
"name": "desktop",
|
|
303
328
|
"width": 1440,
|
|
@@ -306,6 +331,8 @@ CLI 会保留 `report.json` 中已经存在的截图记录,但不会自动启
|
|
|
306
331
|
"imagePath": "evidence/desktop-after.png",
|
|
307
332
|
"capturedAt": "2026-08-20T10:00:00.000Z",
|
|
308
333
|
"kind": "after",
|
|
334
|
+
"deviceScaleFactor": 1,
|
|
335
|
+
"captureMode": "viewport",
|
|
309
336
|
"url": "http://localhost:4173/"
|
|
310
337
|
}
|
|
311
338
|
~~~
|
|
@@ -313,22 +340,43 @@ CLI 会保留 `report.json` 中已经存在的截图记录,但不会自动启
|
|
|
313
340
|
截图规则:
|
|
314
341
|
|
|
315
342
|
- `imagePath` 必须位于目标项目内部;
|
|
316
|
-
- `theme
|
|
317
|
-
-
|
|
343
|
+
- 普通项目无需填写 `theme`,同一份证据可使用任意海报主题展示;
|
|
344
|
+
- 只有明确区分本项目两套视觉版本时才填写 `theme`,跨主题记录会被隔离;
|
|
318
345
|
- 缺失、过期、跨主题或不可读的截图不会被当成有效证据;
|
|
346
|
+
- `capturedAt` 应为真实采集时间,不能晚于报告,也不能早于截图文件或已发现源码的修改时间(容差 2 秒);
|
|
347
|
+
- `viewport` 是浏览器 CSS 像素,`deviceScaleFactor` 是截图设备像素比;整屏用 `viewport`、整页用 `full-page`、局部裁剪用 `region`;
|
|
348
|
+
- 实际图片尺寸必须与视口、像素比匹配。局部裁剪和 `before` 图片会单独标注,不能代替改版后整屏验收;
|
|
349
|
+
- 可选 `sourceFingerprint` 记录截图时的 Git 工作区指纹,汇总时会与采集报告比对;
|
|
319
350
|
- 没有可视界面的项目可以不提供截图。
|
|
320
351
|
|
|
321
|
-
|
|
352
|
+
截图不是“随便放一张图片”:路径、格式、像素尺寸和时间都需要通过检查。缺少截图的视觉项目会标为待复核;检查说明同时出现在 Markdown 与 HTML。插件生成的海报最多嵌入 3 张有效截图,优先保留可配对的 Before / After,再补其他视口。
|
|
353
|
+
|
|
354
|
+
前后对比要求页面 URL、视口尺寸、采集模式及图片比例一致,不能使用局部裁剪。当旧版与新版地址不同但确实是同一页面时,可以给两条记录设置相同的 `comparisonId`。没有可用配对就显示缺失状态。仓库终末地演示页附带 3 张当前视口截图和 1 张本轮修改前截图,不占用目标项目的采集记录。
|
|
322
355
|
|
|
323
356
|
`frontier-signal` 是“终末地帝江号”的内部兼容键,不是第三套主题;普通用户只需要在 DSH 设置中选择中文主题名。
|
|
324
357
|
|
|
325
358
|
## 工具参数
|
|
326
359
|
|
|
360
|
+
### 换到其他项目
|
|
361
|
+
|
|
362
|
+
主题只改变交付报告,不会改写目标项目的界面,也不会把本仓库的示例截图、文件名或测试结果带过去。项目名、任务、Diff、测试回执和截图都来自目标项目自己的 `.showcase/report.json`。
|
|
363
|
+
|
|
364
|
+
| 目标项目 | 报告如何展示 |
|
|
365
|
+
| --- | --- |
|
|
366
|
+
| 有界面的前端或静态站点 | 展示该项目的截图、文件改动与命令结果;缺少有效截图时提示复核 |
|
|
367
|
+
| 后端、CLI 或库 | 保留变更与验证回执,明确说明截图非必需 |
|
|
368
|
+
| 没有 Git 的目录 | 使用本地文件模式,不编造提交范围或 Diff,状态保留待复核 |
|
|
369
|
+
| 测试失败或证据缺失 | 展示失败日志或缺失原因,不沿用演示页的成功结果 |
|
|
370
|
+
|
|
371
|
+
在每个目标项目中分别执行 `init`,检查 `.showcase/config.json` 的任务和验证命令,再执行 `capture`;DSH 工具的 `projectPath` 指向这个目标项目。CLI 会根据常见项目标记提供默认命令,但测试环境和依赖需要在本机可运行;自定义构建系统、单体仓库子项目应填写自己的命令。插件不会自动证明任意项目已通过测试,也不会自动拍摄截图。
|
|
372
|
+
|
|
373
|
+
### 调用参数
|
|
374
|
+
|
|
327
375
|
工具名:`showcase_layout_summary`
|
|
328
376
|
|
|
329
377
|
| 参数 | 必填 | 默认值或用途 |
|
|
330
378
|
| --- | --- | --- |
|
|
331
|
-
| `projectPath` | 是 |
|
|
379
|
+
| `projectPath` | 是 | 目标项目根目录;相对路径基于 DSH 当前会话工作目录,无法获知会话目录时须传绝对路径 |
|
|
332
380
|
| `reportPath` | 否 | `.showcase/report.json` |
|
|
333
381
|
| `outputPath` | 否 | `.showcase/layout-summary.md` |
|
|
334
382
|
| `posterPath` | 否 | `.showcase/layout-poster.html` |
|
|
@@ -363,6 +411,14 @@ CLI 会保留 `report.json` 中已经存在的截图记录,但不会自动启
|
|
|
363
411
|
|
|
364
412
|
检查文件是否存在、路径是否位于目标项目内、`capturedAt` 是否早于图片修改时间,以及截图主题是否匹配。
|
|
365
413
|
|
|
414
|
+
### 测试失败了,为什么原报告写着 completed?
|
|
415
|
+
|
|
416
|
+
汇总会重新核对回执:非零退出码或失败测试优先标记失败;跳过测试、缺失视觉证据、时效警告会降为待复核。测试执行期间产生的新文件或修改会进入最终 Git 清单,并提示重新验证。
|
|
417
|
+
|
|
418
|
+
### 提示输出被锁定怎么办?
|
|
419
|
+
|
|
420
|
+
采集与产物生成使用 `.showcase/.write.lock` 串行写入,避免多个会话互相覆盖。正常完成或取消会释放锁;等待超过 30 秒会报错,不会抢占正在工作的进程。只有确认锁内记录的进程已经退出、没有其他采集任务时,才手动删除遗留锁再重试。损坏的既有 `report.json` 也不会被自动覆盖,应先备份并修正它。
|
|
421
|
+
|
|
366
422
|
### 可以用于非前端项目吗?
|
|
367
423
|
|
|
368
424
|
可以。后端、CLI 和库项目不要求截图,仍可生成 Git 与测试回执。
|
|
@@ -371,19 +427,25 @@ CLI 会保留 `report.json` 中已经存在的截图记录,但不会自动启
|
|
|
371
427
|
|
|
372
428
|
- 所有默认产物只写入目标项目的 `.showcase/`;
|
|
373
429
|
- 没有远程上传步骤;
|
|
374
|
-
-
|
|
430
|
+
- 测试输出、命令和任务文案会尝试脱敏,包括常见 API Key、Basic/Bearer Authorization、Cookie 与 JSON Token;
|
|
375
431
|
- 报告最大 2 MiB,单张截图最大 8 MiB、尺寸不超过 16384 px;
|
|
376
432
|
- 每张海报最多嵌入 3 张有效截图;
|
|
377
433
|
- 脱敏不是绝对保证,公开分享前仍需人工检查。
|
|
434
|
+
- 路径限制会检查真实路径,拒绝通过符号链接或 Windows junction 写出项目边界;这不是执行任意测试命令的安全沙箱,只运行你信任的项目和配置。
|
|
435
|
+
- 证据检查不是数字签名或完整浏览器渲染验证。源码自动发现最多 4000 个文件、8 层目录,不能替代完整依赖图分析;截图和人工验收仍由使用者负责。
|
|
378
436
|
|
|
379
437
|
## 从源码开发
|
|
380
438
|
|
|
439
|
+
构建工具和 DSH `0.2` 插件运行时要求 Node.js `22.19+` 或 `24+`;建议使用 Node.js 24。DSH `0.1` 旧版运行时不再作为本版本的兼容目标。
|
|
440
|
+
|
|
381
441
|
~~~powershell
|
|
382
442
|
npm ci
|
|
383
443
|
npm run check
|
|
384
444
|
npm run dev
|
|
385
445
|
~~~
|
|
386
446
|
|
|
447
|
+
本地预览:`/?theme=dijiang` 为当前终末地主题,`/?theme=fish` 为蓝色大肥鱼。终末地演示页与插件导出共用渲染器;旧版保留在 `/?theme=dijiang&legacy=1` 供视觉对照,不用于新报告导出。
|
|
448
|
+
|
|
387
449
|
主要目录:
|
|
388
450
|
|
|
389
451
|
~~~text
|
|
@@ -391,7 +453,7 @@ src/ CLI、报告 schema、Git、命令和脱敏逻辑
|
|
|
391
453
|
plugin/ DSH 插件、设置面板、摘要和海报生成器
|
|
392
454
|
tests/ 单元、跨项目、极端输入和产物测试
|
|
393
455
|
docs/ 使用、上传、发布和预览素材
|
|
394
|
-
.github/workflows/ Node 20/22 CI
|
|
456
|
+
.github/workflows/ Windows/Linux,Node 20/22/24 CI
|
|
395
457
|
~~~
|
|
396
458
|
|
|
397
459
|
维护文档:
|
package/README.zh-CN.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
[打开 README.md](README.md)
|
|
8
8
|
|
|
9
|
-
赞助商:**鸽子中转站(Pigeon API Relay)**。它兼容 OpenAI API
|
|
9
|
+
赞助商:**鸽子中转站(Pigeon API Relay)**。它兼容 OpenAI API 格式,当前重点覆盖 GPT-6、GPT-5.6、Claude Opus/Fable/Sonnet 5、DeepSeek V4、Gemini、Grok 及多种国产模型,并支持余额按量、日卡/月卡订阅及统一权益管理。站长还会不定期组织抽奖,赠送 Token、体验额度等福利;模型与活动详情以站内实时信息为准,完整介绍见主 README 快速开始后的赞助商区域。
|
|
10
10
|
|
|
11
11
|
本项目提供两套主题:
|
|
12
12
|
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
|
|
16
16
|
主题只在 DSH 插件设置里选择,目标项目不需要增加 `theme` 字段。
|
|
17
17
|
|
|
18
|
+
当前兼容 DSH `0.2.0-rc.2` 及同一 0.2 系列。安装后从 DSH 侧栏进入 **插件**,打开 `dsh-showcase`,在 `dsh-showcase/plugin` 行点击 **配置**;Node.js 使用 `22.19+` 或 `24+`。旧版 DSH 0.1 不属于本版本的兼容目标。
|
|
19
|
+
|
|
18
20
|
维护与发布相关文档:
|
|
19
21
|
|
|
20
22
|
- [GitHub 上传与维护指南](docs/GITHUB_UPLOAD_GUIDE_ZH.md)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-showcase",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Local, verifiable delivery evidence reports for coding-agent work.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./plugin/client-host.js",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"developer-tools"
|
|
24
24
|
],
|
|
25
25
|
"engines": {
|
|
26
|
-
"node": ">=
|
|
26
|
+
"node": "^22.19.0 || >=24.0.0"
|
|
27
27
|
},
|
|
28
28
|
"packageManager": "npm@11.15.0",
|
|
29
29
|
"publishConfig": {
|
|
@@ -41,11 +41,9 @@
|
|
|
41
41
|
},
|
|
42
42
|
"client": {
|
|
43
43
|
"inject": [
|
|
44
|
-
"@deepseek-ai/dsh-client-connection",
|
|
45
44
|
"@deepseek-ai/dsh-client-locale",
|
|
46
45
|
"@deepseek-ai/dsh-client-runtime",
|
|
47
|
-
"@deepseek-ai/dsh-client-ui-
|
|
48
|
-
"@deepseek-ai/dsh-client-ui-settings-plugins"
|
|
46
|
+
"@deepseek-ai/dsh-client-ui-plugin-manager"
|
|
49
47
|
],
|
|
50
48
|
"platform": "web"
|
|
51
49
|
}
|
|
@@ -58,7 +56,14 @@
|
|
|
58
56
|
"plugin/layout-summary.d.ts",
|
|
59
57
|
"plugin/layout-summary.js",
|
|
60
58
|
"plugin/poster-html.js",
|
|
59
|
+
"plugin/dijiang-layout.js",
|
|
60
|
+
"plugin/dijiang-style.js",
|
|
61
|
+
"plugin/dijiang-motion.js",
|
|
62
|
+
"plugin/report-content.js",
|
|
61
63
|
"plugin/report-schema.js",
|
|
64
|
+
"plugin/project-io.js",
|
|
65
|
+
"plugin/project-io.d.ts",
|
|
66
|
+
"plugin/redaction.js",
|
|
62
67
|
"plugin/assets/dijiang-survey-surface.webp",
|
|
63
68
|
"plugin/assets/whale-girl-keyvisual.webp",
|
|
64
69
|
"cordis.patch.yml",
|
|
@@ -82,28 +87,26 @@
|
|
|
82
87
|
"capture": "tsx src/cli/index.ts capture"
|
|
83
88
|
},
|
|
84
89
|
"dependencies": {
|
|
85
|
-
"@deepseek-ai/
|
|
86
|
-
"
|
|
87
|
-
"zod": "latest"
|
|
90
|
+
"@deepseek-ai/schemastery": "^3.18.4",
|
|
91
|
+
"zod": "^4.4.3"
|
|
88
92
|
},
|
|
89
93
|
"peerDependencies": {
|
|
90
|
-
"@deepseek-ai/dsh-tools": "^0.
|
|
91
|
-
"@deepseek-ai/cordis": "^4.0.
|
|
94
|
+
"@deepseek-ai/dsh-tools": "^0.2.0-rc.2",
|
|
95
|
+
"@deepseek-ai/cordis": "^4.0.4"
|
|
92
96
|
},
|
|
93
97
|
"devDependencies": {
|
|
94
|
-
"@deepseek-ai/cordis": "^4.0.
|
|
95
|
-
"@deepseek-ai/dsh-tools": "^0.
|
|
98
|
+
"@deepseek-ai/cordis": "^4.0.4",
|
|
99
|
+
"@deepseek-ai/dsh-tools": "^0.2.0-rc.2",
|
|
96
100
|
"@types/node": "latest",
|
|
97
101
|
"@types/react": "latest",
|
|
98
102
|
"@types/react-dom": "latest",
|
|
99
103
|
"@vitejs/plugin-react": "latest",
|
|
100
|
-
"jsdom": "latest",
|
|
101
104
|
"lucide-react": "latest",
|
|
102
105
|
"react": "latest",
|
|
103
106
|
"react-dom": "latest",
|
|
104
107
|
"tsx": "latest",
|
|
105
108
|
"typescript": "latest",
|
|
106
109
|
"vite": "latest",
|
|
107
|
-
"vitest": "
|
|
110
|
+
"vitest": "^4.1.11"
|
|
108
111
|
}
|
|
109
112
|
}
|
package/plugin/client.js
CHANGED
|
@@ -6,9 +6,7 @@ window.__ModuleLoader__.load({
|
|
|
6
6
|
const React = require("react");
|
|
7
7
|
const { useEffect, useRef, useState } = React;
|
|
8
8
|
|
|
9
|
-
const inject = ["slots", "locale"
|
|
10
|
-
|
|
11
|
-
const RPC_CHANNEL = "/showcase-layout-summary";
|
|
9
|
+
const inject = ["slots", "locale"];
|
|
12
10
|
const LOCALE_NAMESPACE = "showcase.layoutSummary.settings";
|
|
13
11
|
const STYLE_ID = "dsh-showcase-settings-style";
|
|
14
12
|
const THEME_VALUES = ["frontier-signal", "blue-big-fish"];
|
|
@@ -16,6 +14,7 @@ const THEME_VALUES = ["frontier-signal", "blue-big-fish"];
|
|
|
16
14
|
const messages = {
|
|
17
15
|
zh: {
|
|
18
16
|
title: "布局证据产物",
|
|
17
|
+
summary: "配置布局证据产物的海报主题与生成策略。",
|
|
19
18
|
description: "先完成采集与测试,再在交付或视觉审核节点生成摘要;海报是可选的重产物。",
|
|
20
19
|
legend: "海报风格",
|
|
21
20
|
dijiang: "终末地帝江号",
|
|
@@ -32,9 +31,11 @@ const messages = {
|
|
|
32
31
|
failed: "保存失败,请重试。",
|
|
33
32
|
loading: "正在读取插件设置…",
|
|
34
33
|
unavailable: "插件设置服务当前不可用。",
|
|
34
|
+
retry: "重新连接",
|
|
35
35
|
},
|
|
36
36
|
en: {
|
|
37
37
|
title: "Layout evidence artifacts",
|
|
38
|
+
summary: "Configure the poster theme and generation policy for layout evidence.",
|
|
38
39
|
description: "Capture and test first, then generate at the delivery or visual-review checkpoint. The poster is optional and heavier.",
|
|
39
40
|
legend: "Poster theme",
|
|
40
41
|
dijiang: "Dijiang",
|
|
@@ -51,6 +52,7 @@ const messages = {
|
|
|
51
52
|
failed: "Could not save the setting. Try again.",
|
|
52
53
|
loading: "Loading plugin settings…",
|
|
53
54
|
unavailable: "Plugin settings are currently unavailable.",
|
|
55
|
+
retry: "Reconnect",
|
|
54
56
|
},
|
|
55
57
|
};
|
|
56
58
|
|
|
@@ -122,42 +124,48 @@ function installStyles() {
|
|
|
122
124
|
document.head.append(tag);
|
|
123
125
|
}
|
|
124
126
|
|
|
125
|
-
function createThemeCard(
|
|
126
|
-
return function ThemeCard({ t }) {
|
|
127
|
+
function createThemeCard() {
|
|
128
|
+
return function ThemeCard({ t, form, view }) {
|
|
129
|
+
if (view === "summary") return React.createElement("span", { className: "dsh-showcase-settings__summary" }, t("summary"));
|
|
127
130
|
const [theme, setTheme] = useState();
|
|
128
131
|
const [generatePoster, setGeneratePoster] = useState(false);
|
|
129
132
|
const [loadState, setLoadState] = useState("loading");
|
|
130
133
|
const [saveState, setSaveState] = useState("idle");
|
|
134
|
+
const [loadAttempt, setLoadAttempt] = useState(0);
|
|
135
|
+
const [writable, setWritable] = useState(false);
|
|
131
136
|
const mountedRef = useRef(true);
|
|
132
137
|
const savingRef = useRef(false);
|
|
133
138
|
const choiceRefs = useRef({});
|
|
134
139
|
useEffect(() => {
|
|
135
140
|
let active = true;
|
|
136
141
|
mountedRef.current = true;
|
|
137
|
-
|
|
142
|
+
setLoadState("loading");
|
|
143
|
+
const sync = () => {
|
|
138
144
|
if (!active) return;
|
|
139
|
-
const
|
|
145
|
+
const snapshot = form?.state;
|
|
146
|
+
const value = snapshot?.value;
|
|
140
147
|
const validTheme = value?.theme === "frontier-signal" || value?.theme === "blue-big-fish";
|
|
141
148
|
const validPosterSetting = value?.generatePoster === undefined || typeof value?.generatePoster === "boolean";
|
|
142
149
|
if (validTheme && validPosterSetting) {
|
|
143
150
|
setTheme(value.theme);
|
|
144
151
|
if (typeof value.generatePoster === "boolean") setGeneratePoster(value.generatePoster);
|
|
145
|
-
|
|
152
|
+
setWritable(snapshot.writable === true);
|
|
153
|
+
setLoadState(snapshot.status === "ready" ? "ready" : "unavailable");
|
|
146
154
|
} else {
|
|
155
|
+
setWritable(false);
|
|
147
156
|
setLoadState("unavailable");
|
|
148
157
|
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
});
|
|
158
|
+
};
|
|
159
|
+
sync();
|
|
152
160
|
return () => {
|
|
153
161
|
active = false;
|
|
154
162
|
mountedRef.current = false;
|
|
155
163
|
};
|
|
156
|
-
}, []);
|
|
164
|
+
}, [form, form?.state, loadAttempt]);
|
|
157
165
|
|
|
158
166
|
if (loadState !== "ready") {
|
|
159
167
|
const loading = loadState === "loading";
|
|
160
|
-
return React.createElement("
|
|
168
|
+
return React.createElement("div", {
|
|
161
169
|
className: "dsh-showcase-settings",
|
|
162
170
|
"data-load-state": loadState,
|
|
163
171
|
"aria-busy": loading,
|
|
@@ -168,7 +176,12 @@ function createThemeCard(rpc) {
|
|
|
168
176
|
className: "dsh-showcase-settings__description",
|
|
169
177
|
role: "status",
|
|
170
178
|
"aria-live": "polite",
|
|
171
|
-
}, t(loadState))
|
|
179
|
+
}, t(loadState)),
|
|
180
|
+
!loading && React.createElement("button", {
|
|
181
|
+
type: "button",
|
|
182
|
+
className: "dsh-showcase-settings__choice",
|
|
183
|
+
onClick: () => setLoadAttempt((attempt) => attempt + 1),
|
|
184
|
+
}, t("retry"))),
|
|
172
185
|
loading && React.createElement("div", { className: "dsh-showcase-settings__body", "aria-hidden": true },
|
|
173
186
|
React.createElement("div", { className: "dsh-showcase-settings__loading-choices" },
|
|
174
187
|
...THEME_VALUES.map((value) => React.createElement("div", {
|
|
@@ -184,25 +197,18 @@ function createThemeCard(rpc) {
|
|
|
184
197
|
React.createElement("div", { className: "dsh-showcase-settings__loading-switch" }))));
|
|
185
198
|
}
|
|
186
199
|
|
|
187
|
-
const disabled = saveState === "saving";
|
|
200
|
+
const disabled = saveState === "saving" || !writable;
|
|
188
201
|
const save = async (patch, rollback = () => {}) => {
|
|
189
|
-
if (savingRef.current) return;
|
|
202
|
+
if (savingRef.current || !form?.mutate) return;
|
|
190
203
|
savingRef.current = true;
|
|
191
204
|
setSaveState("saving");
|
|
192
205
|
try {
|
|
193
|
-
const
|
|
206
|
+
const snapshot = form.state;
|
|
207
|
+
const operations = Object.entries(patch).map(([path, value]) => ({ op: "set", path: [path], value }));
|
|
208
|
+
const accepted = await form.mutate(operations, snapshot.revision);
|
|
194
209
|
if (!mountedRef.current) return;
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const validPosterSetting = value?.generatePoster === undefined || typeof value?.generatePoster === "boolean";
|
|
198
|
-
if (validTheme && validPosterSetting) {
|
|
199
|
-
setTheme(value.theme);
|
|
200
|
-
if (typeof value.generatePoster === "boolean") setGeneratePoster(value.generatePoster);
|
|
201
|
-
setSaveState("saved");
|
|
202
|
-
} else {
|
|
203
|
-
rollback();
|
|
204
|
-
setSaveState("failed");
|
|
205
|
-
}
|
|
210
|
+
if (!accepted) throw new Error("The configuration was rejected.");
|
|
211
|
+
setSaveState("saved");
|
|
206
212
|
} catch {
|
|
207
213
|
if (mountedRef.current) {
|
|
208
214
|
rollback();
|
|
@@ -262,7 +268,7 @@ function createThemeCard(rpc) {
|
|
|
262
268
|
? t("failed")
|
|
263
269
|
: "";
|
|
264
270
|
|
|
265
|
-
return React.createElement("
|
|
271
|
+
return React.createElement("div", {
|
|
266
272
|
className: "dsh-showcase-settings",
|
|
267
273
|
"data-save-state": saveState,
|
|
268
274
|
"aria-busy": disabled,
|
|
@@ -312,11 +318,10 @@ function createThemeCard(rpc) {
|
|
|
312
318
|
function apply(ctx) {
|
|
313
319
|
installStyles();
|
|
314
320
|
ctx.effect(() => ctx.locale.register(LOCALE_NAMESPACE, messages), "dsh-showcase: settings locale");
|
|
315
|
-
const ThemeCard = createThemeCard(
|
|
316
|
-
ctx.slots.inject("
|
|
317
|
-
name: "
|
|
318
|
-
|
|
319
|
-
order: 30,
|
|
321
|
+
const ThemeCard = createThemeCard();
|
|
322
|
+
ctx.slots.inject("plugins.row.config", () => ctx.slots.register({
|
|
323
|
+
name: "plugins.row.config",
|
|
324
|
+
key: "dsh-showcase#showcase-layout-summary",
|
|
320
325
|
locale: LOCALE_NAMESPACE,
|
|
321
326
|
}, ThemeCard));
|
|
322
327
|
}
|