dsh-md-studio 1.3.2 → 1.3.3

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/lib/index.js CHANGED
@@ -1,19 +1,27 @@
1
- // dsh-md-studio host half (source of truth; build script copies to lib/index.js).
1
+ // dsh-md-studio host half.
2
2
  //
3
3
  // 1. Serves an optional vendored mermaid runtime from ./runtime (offline mode).
4
- // 2. Registers a system-prompt section teaching the model how to emit
5
- // ```mds-diagram blocks — model-authored SVG widgets rendered by the
6
- // browser half into themed cards (the WorkBuddy "show_widget" pattern).
4
+ // 2. Registers a system-prompt section teaching the model the mds-diagram
5
+ // fence and the theme-variable text rule (the full drawing spec ships as
6
+ // the mds-diagram-design skill, installed below).
7
+ // 3. Installs the bundled drawing-spec skill into the user skills root
8
+ // (~/.agents/skills/mds-diagram-design) so any model can load it on demand;
9
+ // refresh on version change, and uninstall only if the content is still
10
+ // ours (never delete user edits).
7
11
 
8
- import { readFile } from "node:fs/promises";
12
+ import { readFile, writeFile, mkdir, rm } from "node:fs/promises";
9
13
  import { fileURLToPath } from "node:url";
10
- import { join, normalize, sep } from "node:path";
14
+ import { join, normalize, sep, dirname } from "node:path";
15
+ import { homedir } from "node:os";
11
16
 
12
17
  const name = "dsh-md-studio";
13
18
  const inject = ["webServer", "systemPrompt"];
14
19
 
15
20
  const RUNTIME_ROUTE = "/dsh-md-studio/runtime";
16
21
  const runtimeDir = fileURLToPath(new URL("./runtime", import.meta.url));
22
+ const SKILL_NAME = "mds-diagram-design";
23
+ const skillSrcDir = fileURLToPath(new URL("../skills/mds-diagram-design", import.meta.url));
24
+ const skillDstDir = join(homedir(), ".agents", "skills", SKILL_NAME);
17
25
 
18
26
  const MIME = {
19
27
  ".js": "text/javascript; charset=utf-8",
@@ -29,20 +37,31 @@ const MIME = {
29
37
 
30
38
  const GUIDELINE = `## 图表组件(mds-diagram)
31
39
 
32
- 当需要输出高质量示意图、流程图、架构分层图或对比图时,优先使用 \`\`\`mds-diagram 围栏(而非 mermaid),内容为一个完整的手写 SVG。渲染环境会自动套用主题卡片并净化内容。
40
+ 需要画架构图/流程图/示意图时,优先用 \`\`\`mds-diagram <可选标题> 围栏输出手写 SVG(简单流程继续用 mermaid 围栏)。完整绘图规范(色板/布局/关系表达/自查清单)请用 skill 工具加载 **mds-diagram-design** skill 后遵循。
33
41
 
34
- 设计规范(深浅主题通吃):
35
- - 根元素:<svg viewBox="0 0 W H" width="100%" font-family="system-ui,sans-serif">,不设背景色
36
- - 节点填充主色 #3B82F6(白字),强调/辅助 #8B5CF6,成功 #10B981,警告 #F59E0B,危险 #EF4444
37
- - 连接线 #94A3B8,文字 fill 白色(在实色节点上)或 #1F2937(在浅底上)
38
- - 圆角 rect rx=8~10,节点内边距 ≥12px,字号 13~15px
39
- - 分组/分层容器用半透明底色 rgba(59,130,246,.08) + 描边 rgba(59,130,246,.35)
40
- - 编号用圆形 badge(circle + 白色居中数字)
41
- - 箭头用 <marker> 定义,id 唯一
42
- - 在 <svg> 内放 <title> 描述图表用途(作为卡片标题)
43
- - 每个文本元素显式设 fill;不要依赖默认继承
42
+ 必须遵守的三条硬规则:
43
+ 1. 画布级文字(图例、分组标签)用主题变量:style="fill:var(--dsw-alias-label-primary,#1F2937)"——禁止硬编码深灰,深色模式下会不可见。
44
+ 2. 节点用浅色底+深色字(蓝 #B5D4F4/#0C447C,橙 #FAC775/#633806,绿 #9FE1CB/#085041,紫 #CECBF6/#3C3489),全图最多 4 种语义色,≥3 种时必须有图例。
45
+ 3. 根元素 <svg viewBox="0 0 W H" width="100%" font-family="system-ui,sans-serif">,内放 <title>(作为卡片标题),箭头 marker id 加随机后缀防冲突。`;
44
46
 
45
- 仅在图表有明确结构化表达价值时使用;简单流程继续用 mermaid 围栏。`;
47
+ async function installSkill() {
48
+ const srcFile = join(skillSrcDir, "SKILL.md");
49
+ const dstFile = join(skillDstDir, "SKILL.md");
50
+ let src;
51
+ try { src = await readFile(srcFile); } catch { return () => {}; } // skill not bundled — noop
52
+ let dst;
53
+ try { dst = await readFile(dstFile); } catch { /* not installed yet */ }
54
+ if (dst && dst.equals(src)) return () => {}; // already current
55
+ await mkdir(dirname(dstFile), { recursive: true });
56
+ await writeFile(dstFile, src);
57
+ return async () => {
58
+ // Uninstall only if the file is still exactly what we installed.
59
+ try {
60
+ const cur = await readFile(dstFile);
61
+ if (cur.equals(src)) await rm(skillDstDir, { recursive: true, force: true });
62
+ } catch { /* already gone */ }
63
+ };
64
+ }
46
65
 
47
66
  function apply(ctx) {
48
67
  ctx.effect(
@@ -103,6 +122,12 @@ function apply(ctx) {
103
122
  }),
104
123
  "dsh-md-studio: diagram design guidelines",
105
124
  );
125
+ let uninstall = () => {};
126
+ let disposed = false;
127
+ ctx.effect(() => {
128
+ installSkill().then((fn) => { if (disposed) fn(); else uninstall = fn; }).catch(() => {});
129
+ return () => { disposed = true; uninstall(); };
130
+ }, "dsh-md-studio: skill install");
106
131
  }
107
132
 
108
133
  export { apply, inject, name };
package/package.json CHANGED
@@ -1,51 +1,80 @@
1
- {
2
- "name": "dsh-md-studio",
3
- "version": "1.3.2",
4
- "description": "Markdown Studio:在 DSH 原生右侧文件预览与对话消息中渲染 Mermaid 图表、KaTeX 公式、GFM 表格、任务列表、脚注及代码高亮。渲染引擎随包内置,完全离线可用。 / Native DSH right-sidebar Markdown preview with Mermaid diagrams, KaTeX math, GFM tables and syntax highlighting — fully offline.",
5
- "keywords": [
6
- "deepseek-harness",
7
- "dsh",
8
- "dsh-plugin",
9
- "markdown",
10
- "mermaid",
11
- "katex",
12
- "syntax-highlighting",
13
- "preview"
14
- ],
15
- "homepage": "https://github.com/BioAIEvolu/dsh-md-studio#readme",
16
- "repository": {
17
- "type": "git",
18
- "url": "git+https://github.com/BioAIEvolu/dsh-md-studio.git"
19
- },
20
- "bugs": "https://github.com/BioAIEvolu/dsh-md-studio/issues",
21
- "license": "MIT",
22
- "author": "BioAIEvolu",
23
- "type": "module",
24
- "main": "./lib/index.js",
25
- "exports": {".": "./lib/index.js", "./client": "./lib/client.js", "./package.json": "./package.json"},
26
- "files": ["lib", "docs/images", "docs/demo.md", "cordis.patch.yml", "README.md", "README.en.md", "CHANGELOG.md", "THIRD_PARTY_NOTICES.md"],
27
- "scripts": {
28
- "build": "node scripts/build.mjs",
29
- "test": "node test/browser.mjs",
30
- "screenshots": "node test/screenshots.mjs"
31
- },
32
- "dsh": {
33
- "bundle": {"patch": "./cordis.patch.yml"},
34
- "client": {"platform": "web", "inject": ["@deepseek-ai/dsh-client-ui-sidebar-documentpreview"], "external": ["react"]}
35
- },
36
- "engines": {"node": ">=22.19.0", "dsh": ">=0.2.0-rc.2 <0.3.0-0"},
37
- "peerDependencies": {"react": "^18.2.0 || ^19"},
38
- "devDependencies": {
39
- "esbuild": "0.28.2",
40
- "mermaid": "11.17.0",
41
- "markdown-it": "15.0.2",
42
- "markdown-it-footnote": "4.0.0",
43
- "markdown-it-task-lists": "2.1.1",
44
- "dompurify": "3.4.16",
45
- "highlight.js": "11.12.0",
46
- "katex": "0.19.0",
47
- "react": "18.3.1",
48
- "react-dom": "18.3.1",
49
- "playwright-core": "1.64.0"
50
- }
51
- }
1
+ {
2
+ "name": "dsh-md-studio",
3
+ "version": "1.3.3",
4
+ "description": "Markdown Studio:在 DSH 原生右侧文件预览与对话消息中渲染 Mermaid 图表、KaTeX 公式、GFM 表格、任务列表、脚注及代码高亮。渲染引擎随包内置,完全离线可用。 / Native DSH right-sidebar Markdown preview with Mermaid diagrams, KaTeX math, GFM tables and syntax highlighting — fully offline.",
5
+ "keywords": [
6
+ "deepseek-harness",
7
+ "dsh",
8
+ "dsh-plugin",
9
+ "markdown",
10
+ "mermaid",
11
+ "katex",
12
+ "syntax-highlighting",
13
+ "preview"
14
+ ],
15
+ "homepage": "https://github.com/BioAIEvolu/dsh-md-studio#readme",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/BioAIEvolu/dsh-md-studio.git"
19
+ },
20
+ "bugs": "https://github.com/BioAIEvolu/dsh-md-studio/issues",
21
+ "license": "MIT",
22
+ "author": "BioAIEvolu",
23
+ "type": "module",
24
+ "main": "./lib/index.js",
25
+ "exports": {
26
+ ".": "./lib/index.js",
27
+ "./client": "./lib/client.js",
28
+ "./package.json": "./package.json"
29
+ },
30
+ "files": [
31
+ "skills",
32
+ "lib",
33
+ "docs/images",
34
+ "docs/demo.md",
35
+ "cordis.patch.yml",
36
+ "README.md",
37
+ "README.en.md",
38
+ "CHANGELOG.md",
39
+ "THIRD_PARTY_NOTICES.md"
40
+ ],
41
+ "scripts": {
42
+ "build": "node scripts/build.mjs",
43
+ "test": "node test/browser.mjs",
44
+ "screenshots": "node test/screenshots.mjs"
45
+ },
46
+ "dsh": {
47
+ "bundle": {
48
+ "patch": "./cordis.patch.yml"
49
+ },
50
+ "client": {
51
+ "platform": "web",
52
+ "inject": [
53
+ "@deepseek-ai/dsh-client-ui-sidebar-documentpreview"
54
+ ],
55
+ "external": [
56
+ "react"
57
+ ]
58
+ }
59
+ },
60
+ "engines": {
61
+ "node": "\u003e=22.19.0",
62
+ "dsh": "\u003e=0.2.0-rc.2 \u003c0.3.0-0"
63
+ },
64
+ "peerDependencies": {
65
+ "react": "^18.2.0 || ^19"
66
+ },
67
+ "devDependencies": {
68
+ "esbuild": "0.28.2",
69
+ "mermaid": "11.17.0",
70
+ "markdown-it": "15.0.2",
71
+ "markdown-it-footnote": "4.0.0",
72
+ "markdown-it-task-lists": "2.1.1",
73
+ "dompurify": "3.4.16",
74
+ "highlight.js": "11.12.0",
75
+ "katex": "0.19.0",
76
+ "react": "18.3.1",
77
+ "react-dom": "18.3.1",
78
+ "playwright-core": "1.64.0"
79
+ }
80
+ }
@@ -0,0 +1,97 @@
1
+ ---
2
+ name: mds-diagram-design
3
+ description: 绘制高质量 SVG 示意图(架构图、流程图、分层图、对比图)。当需要在 DSH 对话或 Markdown 文档中输出 mds-diagram 图表、手写 SVG 图形、或要求"画个架构图/流程图/示意图"时使用——保证配色协调、布局合理、关系明确、深浅主题都可读。
4
+ metadata:
5
+ vendor: dsh-md-studio
6
+ version: "1.0"
7
+ ---
8
+
9
+ # mds-diagram 绘图规范
10
+
11
+ 输出形式:```` ```mds-diagram <可选标题> ```` 围栏,内容为**一个完整的手写 SVG**。对话中也可直接输出裸 `<svg>` 代码块,渲染器同样识别。简单流程图继续用 mermaid 围栏。
12
+
13
+ ## 一、设计系统(色板)
14
+
15
+ 节点用**浅色底 + 深色字**的软芯片(chip)配色——主题无关,深浅模式下可读性一致:
16
+
17
+ | 语义 | 底色 fill | 文字 fill | 强调/描边 |
18
+ |---|---|---|---|
19
+ | 主流程/核心 | `#B5D4F4` | `#0C447C` | `#85B7EB` |
20
+ | 警示/人工 | `#FAC775` | `#633806` | `#EF9F27` |
21
+ | 成功/通过 | `#9FE1CB` | `#085041` | `#5DCAA5` |
22
+ | 辅助/外部 | `#CECBF6` | `#3C3489` | `#AFA9EC` |
23
+ | 中性容器 | `var(--dsw-alias-bg-layer-2,#F6F8FA)` | `var(--dsw-alias-label-primary,#1F2937)` | `var(--dsw-alias-border-l1,#D0D7DE)` |
24
+
25
+ 规则:
26
+ - 一个图**最多 4 种语义色**,超过时先合并语义而不是加颜色。
27
+ - 用了 ≥3 种颜色时,**必须有图例**(色块 12×12 rx=3 + 12px 文字,置于图顶部)。
28
+ - 实心节点上的主标题用白字 `#FFFFFF` 加粗;副标题用 `#FFFFFF` opacity `0.8`。
29
+
30
+ ## 二、画布级文字(深色模式的关键)
31
+
32
+ 直接画在透明底上的文字(图例、分组标签、注解),**必须**用主题变量,禁止硬编码深灰:
33
+
34
+ ```xml
35
+ <text style="fill:var(--dsw-alias-label-primary,#1F2937)" font-size="12">图例</text>
36
+ ```
37
+
38
+ 这样文字会随 DSH 深浅主题自动翻转。硬编码 `#1F2937` 在深色模式下会不可见。
39
+
40
+ ## 三、字体阶
41
+
42
+ | 层级 | 字号 | 字重 |
43
+ |---|---|---|
44
+ | 节点主标题 / 图标题 | 14–15 | 700 |
45
+ | 节点副标题 / 正文 | 13 | 400 |
46
+ | 图例 / 标签 / 注解 | 12 | 400 |
47
+
48
+ 字体族:`system-ui, sans-serif`(根元素统一设置,子元素继承)。每张图在 `<svg>` 内放一个 `<title>` 描述用途(渲染为卡片标题)。
49
+
50
+ ## 四、布局
51
+
52
+ - 根元素:`<svg viewBox="0 0 W H" width="100%" font-family="system-ui,sans-serif">`,不设背景色,不留多余的空白边。
53
+ - 画布边距 ≥24px;同类节点**等宽等高**、按网格对齐;节点间距 16–24px;层间距 ≥32px。
54
+ - 节点最小内边距 12px:文字到 rect 边缘 ≥12px;圆角 `rx=8`(小芯片)或 `rx=10`(大容器)。
55
+ - 一张图的节点数控制在 5–12 个;更多就拆成分组容器或拆成多张图。
56
+ - 长文本折行用多个 `<text>` 行(行高 = 字号 × 1.4),不要超出节点。
57
+
58
+ ## 五、关系表达(关系明确)
59
+
60
+ - 箭头:`<defs>` 里定义一次 `<marker>`(id 加随机后缀防冲突),所有指向性连线共用。
61
+ - 线型语义:**实线 = 同步/强依赖,虚线(stroke-dasharray="6 4")= 异步/可选,粗线 = 数据流,细线 = 控制流**。
62
+ - 每条语义不明显的连线加 12px 线上标签;纯结构连线可省。
63
+ - 分组/分层容器:themed 底色 + 1px 描边 + 左上角 12px 分组标签,组内成员缩进 ≥16px。
64
+ - 顺序步骤用编号圆徽:圆直径 24,底色用该节点语义色,白色居中数字。
65
+
66
+ ## 六、输出前自查清单
67
+
68
+ 1. viewBox 与实际内容贴合,没有大片空白?
69
+ 2. 画布级文字全部用 `var(--dsw-alias-label-primary,…)`?
70
+ 3. 节点主标题在底色上对比足够(深色字浅底 / 白字深底)?
71
+ 4. ≥3 种颜色时有图例?
72
+ 5. 连线都有箭头或明确语义?虚线/实线用法一致?
73
+ 6. 同类节点对齐、等宽?文字都没有溢出?
74
+ 7. `<title>` 已写?marker id 无冲突?
75
+ 8. 单图节点 ≤12,超出已拆分?
76
+
77
+ **示例骨架**:
78
+
79
+ ```xml
80
+ <svg viewBox="0 0 640 200" width="100%" font-family="system-ui,sans-serif">
81
+ <title>请求处理流程</title>
82
+ <defs>
83
+ <marker id="arr-a1" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
84
+ <path d="M0,0 L10,5 L0,10 Z" fill="#85B7EB"/>
85
+ </marker>
86
+ </defs>
87
+ <!-- 图例 -->
88
+ <rect x="24" y="16" width="12" height="12" rx="3" fill="#B5D4F4"/>
89
+ <text x="42" y="26" font-size="12" style="fill:var(--dsw-alias-label-primary,#1F2937)">核心流程</text>
90
+ <!-- 节点 -->
91
+ <rect x="24" y="60" width="150" height="56" rx="8" fill="#B5D4F4"/>
92
+ <text x="99" y="84" font-size="14" font-weight="700" text-anchor="middle" fill="#0C447C">接入层</text>
93
+ <text x="99" y="102" font-size="12" text-anchor="middle" fill="#0C447C" opacity="0.75">校验与路由</text>
94
+ <!-- 连线 -->
95
+ <line x1="174" y1="88" x2="226" y2="88" stroke="#85B7EB" stroke-width="2" marker-end="url(#arr-a1)"/>
96
+ </svg>
97
+ ```