Repository navigation
Expand file tree
/
Copy pathcontext-map-example.html
More file actions
524 lines (496 loc) · 40 KB
/
Copy pathcontext-map-example.html
File metadata and controls
524 lines (496 loc) · 40 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
<!DOCTYPE html>
<html lang="zh-CN" data-theme="auto">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="generator" content="dsh-context-map 0.3.0">
<title>把 DSH 插件做成三个渠道都能上架的产品 · 上下文信息架构图</title>
<style>
:root{--bg:#f8fafc;--surface:#fff;--surface-alt:#f1f5f9;--ink:#0f172a;--muted:#64748b;--faint:#94a3b8;--line:#e2e8f0;--accent:#2563eb;--shadow:0 1px 2px rgba(15,23,42,.06),0 8px 24px rgba(15,23,42,.06);--radius:14px}
html[data-theme="dark"]{--bg:#0b1220;--surface:#0f172a;--surface-alt:#111c31;--ink:#e2e8f0;--muted:#94a3b8;--faint:#64748b;--line:#1e293b;--accent:#60a5fa;--shadow:0 1px 2px rgba(2,6,23,.5),0 12px 32px rgba(2,6,23,.45)}
@media (prefers-color-scheme:dark){html[data-theme="auto"]{--bg:#0b1220;--surface:#0f172a;--surface-alt:#111c31;--ink:#e2e8f0;--muted:#94a3b8;--faint:#64748b;--line:#1e293b;--accent:#60a5fa;--shadow:0 1px 2px rgba(2,6,23,.5),0 12px 32px rgba(2,6,23,.45)}}
*{box-sizing:border-box}
html,body{margin:0;height:100%}
body{background:var(--bg);color:var(--ink);font:14px/1.5 'Inter','Segoe UI','PingFang SC','Hiragino Sans GB','Microsoft YaHei',system-ui,-apple-system,sans-serif;-webkit-font-smoothing:antialiased;display:flex;flex-direction:column}
.dot{display:inline-block;width:8px;height:8px;border-radius:3px;background:var(--kind,#94a3b8);margin-right:8px;flex:none}
.cm-n-goal{--kind:#2563eb}
.cm-n-context{--kind:#64748b}
.cm-n-decision{--kind:#7c3aed}
.cm-n-action{--kind:#059669}
.cm-n-artifact{--kind:#d97706}
.cm-n-risk{--kind:#e11d48}
.cm-n-question{--kind:#0891b2}
.cm-n-note{--kind:#475569}
html[data-theme="dark"] .cm-n-goal{--kind:#60a5fa} html[data-theme="dark"] .cm-n-context{--kind:#94a3b8} html[data-theme="dark"] .cm-n-decision{--kind:#a78bfa} html[data-theme="dark"] .cm-n-action{--kind:#34d399} html[data-theme="dark"] .cm-n-artifact{--kind:#fbbf24} html[data-theme="dark"] .cm-n-risk{--kind:#fb7185} html[data-theme="dark"] .cm-n-question{--kind:#22d3ee} html[data-theme="dark"] .cm-n-note{--kind:#94a3b8}
.bar{position:sticky;top:0;z-index:20;display:flex;align-items:center;gap:10px;padding:10px 16px;background:color-mix(in srgb,var(--surface) 88%,transparent);backdrop-filter:blur(10px);border-bottom:1px solid var(--line)}
.bar .name{font-weight:650;letter-spacing:-.01em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:34vw}
.bar .tag{font-size:10px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--accent);border:1px solid color-mix(in srgb,var(--accent) 35%,transparent);border-radius:999px;padding:2px 8px}
.bar .spacer{flex:1}
.search{position:relative}
.search input{width:min(260px,34vw);padding:7px 10px 7px 30px;border:1px solid var(--line);border-radius:9px;background:var(--surface);color:var(--ink);font:inherit;font-size:13px}
.search input:focus{outline:2px solid color-mix(in srgb,var(--accent) 40%,transparent);outline-offset:1px}
.search svg{position:absolute;left:9px;top:50%;transform:translateY(-50%);opacity:.5}
.group{display:flex;align-items:center;gap:2px;padding:2px;border:1px solid var(--line);border-radius:10px;background:var(--surface)}
.group button{border:0;background:transparent;color:var(--ink);font:inherit;font-size:13px;min-width:30px;height:28px;border-radius:7px;cursor:pointer;padding:0 8px}
.group button:hover{background:var(--surface-alt)}
.group .zoom{min-width:52px;font-variant-numeric:tabular-nums;color:var(--muted)}
.wrap{flex:1;display:flex;min-height:0}
.side{width:264px;flex:none;border-right:1px solid var(--line);background:var(--surface);overflow:auto;padding:14px 12px 40px}
.side h2{margin:2px 0 10px;font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--faint);font-weight:700}
.side .stats{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 14px;padding:0;list-style:none;font-size:11px;color:var(--muted)}
.side .stats li{display:flex;align-items:center;gap:4px;padding:3px 7px;border:1px solid var(--line);border-radius:999px}
.side .stats b{font-weight:650;color:var(--ink)}
ul.branch{list-style:none;margin:0;padding:0}
ul.branch ul.branch{padding-left:12px;border-left:1px dashed var(--line);margin-left:5px}
li.leaf{position:relative}
button.jump{display:flex;align-items:flex-start;gap:0;width:100%;text-align:left;border:0;background:transparent;color:var(--ink);font:inherit;font-size:12.5px;line-height:1.45;padding:5px 6px;border-radius:8px;cursor:pointer}
button.jump:hover{background:var(--surface-alt)}
button.jump.active{background:color-mix(in srgb,var(--accent) 12%,transparent)}
button.jump .txt{overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
button.jump .dot{margin-top:4px}
.stage{flex:1;min-width:0;overflow:auto;position:relative;background-image:radial-gradient(var(--line) 1px,transparent 1px);background-size:22px 22px}
.canvas{transform-origin:0 0;width:max-content;padding:18px}
.canvas svg{display:block;border-radius:12px;box-shadow:var(--shadow);background:var(--bg)}
.cm-node{transition:opacity .18s ease,filter .18s ease}
.cm-node.hit{filter:drop-shadow(0 0 0.55rem color-mix(in srgb,var(--accent) 55%,transparent))}
.cm-node.dim{opacity:.18}
.cm-node.flash .cm-card{animation:flash 1.1s ease-out 2}
.cm-svg.only-diff .cm-node:not(.cm-node-new):not(.cm-node-changed){opacity:.15}
@keyframes flash{0%,100%{stroke-opacity:.42}30%{stroke-opacity:1;stroke-width:2.6px}}
.cm-legend-item{cursor:pointer}
.cm-legend-item.off{opacity:.35}
.empty{position:absolute;inset:0;display:none;place-items:center;color:var(--muted);font-size:13px}
.stage[data-empty="true"] .empty{display:grid}
@media (max-width:820px){.side{display:none}.bar .name{max-width:40vw}}
@media print{@page{size:A3 landscape;margin:8mm}.bar,.side,.empty{display:none}.wrap{display:block}.stage{overflow:visible;background:none}.canvas{transform:none!important;padding:0}.canvas svg{box-shadow:none}}
@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}
.cm-svg.hide-goal .cm-n-goal{display:none}
.cm-svg.hide-context .cm-n-context{display:none}
.cm-svg.hide-decision .cm-n-decision{display:none}
.cm-svg.hide-action .cm-n-action{display:none}
.cm-svg.hide-artifact .cm-n-artifact{display:none}
.cm-svg.hide-risk .cm-n-risk{display:none}
.cm-svg.hide-question .cm-n-question{display:none}
.cm-svg.hide-note .cm-n-note{display:none}
</style>
</head>
<body>
<header class="bar">
<span class="tag">上下文信息架构图</span>
<span class="name" title="把 DSH 插件做成三个渠道都能上架的产品">把 DSH 插件做成三个渠道都能上架的产品</span>
<span class="spacer"></span>
<label class="search" aria-label="搜索节点…">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.6-3.6"/></svg>
<input id="q" type="search" placeholder="搜索节点…" autocomplete="off" spellcheck="false">
</label>
<div class="group" role="group" aria-label="zoom">
<button type="button" id="zoom-out" title="缩小" aria-label="缩小">−</button>
<button type="button" class="zoom" id="zoom-reset" title="还原">100%</button>
<button type="button" id="zoom-in" title="放大" aria-label="放大">+</button>
<button type="button" id="fit" title="适配">适配</button>
</div>
<div class="group">
<button type="button" id="theme" title="主题" aria-label="主题">◐</button>
<button type="button" id="print" title="打印" aria-label="打印">⎙</button>
</div>
</header>
<div class="wrap">
<aside class="side">
<h2>结构</h2>
<ul class="stats"><li><span class="dot cm-n-goal"></span>goal<b>1</b></li><li><span class="dot cm-n-context"></span>context<b>4</b></li><li><span class="dot cm-n-decision"></span>decision<b>4</b></li><li><span class="dot cm-n-action"></span>action<b>4</b></li><li><span class="dot cm-n-artifact"></span>artifact<b>1</b></li><li><span class="dot cm-n-risk"></span>risk<b>3</b></li><li><span class="dot cm-n-question"></span>question<b>1</b></li></ul>
<ul class="branch root">
<li class="leaf lvl-0"><button type="button" class="jump" data-target="goal"><span class="dot cm-n-goal"></span><span class="txt">开发 DSH 插件并完成三渠道上架</span></button>
<ul class="branch">
<li class="leaf lvl-1"><button type="button" class="jump" data-target="b1"><span class="dot cm-n-context"></span><span class="txt">渠道调研</span></button>
<ul class="branch">
<li class="leaf lvl-2"><button type="button" class="jump" data-target="b1a"><span class="dot cm-n-context"></span><span class="txt">dsh.so 是验收清单制</span></button></li>
<li class="leaf lvl-2"><button type="button" class="jump" data-target="b1b"><span class="dot cm-n-context"></span><span class="txt">marketplace 靠 GitHub topic 自动同步</span></button></li>
<li class="leaf lvl-2"><button type="button" class="jump" data-target="b1c"><span class="dot cm-n-context"></span><span class="txt">curated 清单是一插件一 YAML</span></button></li></ul></li>
<li class="leaf lvl-1"><button type="button" class="jump" data-target="b2"><span class="dot cm-n-decision"></span><span class="txt">产品设计</span></button>
<ul class="branch">
<li class="leaf lvl-2"><button type="button" class="jump" data-target="b2a"><span class="dot cm-n-decision"></span><span class="txt">方向:对话上下文信息架构图</span></button></li>
<li class="leaf lvl-2"><button type="button" class="jump" data-target="b2b"><span class="dot cm-n-decision"></span><span class="txt">零运行时依赖</span></button></li>
<li class="leaf lvl-2"><button type="button" class="jump" data-target="b2c"><span class="dot cm-n-decision"></span><span class="txt">输出 SVG / HTML / Mermaid 三件套</span></button></li></ul></li>
<li class="leaf lvl-1"><button type="button" class="jump" data-target="b3"><span class="dot cm-n-action"></span><span class="txt">交付计划</span></button>
<ul class="branch">
<li class="leaf lvl-2"><button type="button" class="jump" data-target="b3a"><span class="dot cm-n-action"></span><span class="txt">确定性树布局与双主题渲染</span></button></li>
<li class="leaf lvl-2"><button type="button" class="jump" data-target="b3b"><span class="dot cm-n-action"></span><span class="txt">单元测试与真实启动冒烟</span></button></li>
<li class="leaf lvl-2"><button type="button" class="jump" data-target="b3c"><span class="dot cm-n-action"></span><span class="txt">三渠道提交物与 PR 文案</span></button></li>
<li class="leaf lvl-2"><button type="button" class="jump" data-target="b3d"><span class="dot cm-n-artifact"></span><span class="txt">dsh-context-map 仓库</span></button></li></ul></li>
<li class="leaf lvl-1"><button type="button" class="jump" data-target="b4"><span class="dot cm-n-risk"></span><span class="txt">风险与待办</span></button>
<ul class="branch">
<li class="leaf lvl-2"><button type="button" class="jump" data-target="b4a"><span class="dot cm-n-risk"></span><span class="txt">本机没有 GitHub / npm 登录态</span></button></li>
<li class="leaf lvl-2"><button type="button" class="jump" data-target="b4b"><span class="dot cm-n-risk"></span><span class="txt">插件进程 cwd ≠ 会话工作区</span></button></li>
<li class="leaf lvl-2"><button type="button" class="jump" data-target="b4c"><span class="dot cm-n-question"></span><span class="txt">GitHub 用户名与仓库归属未定</span></button></li></ul></li></ul></li></ul>
</aside>
<section class="stage" id="stage">
<div class="canvas" id="canvas">
<svg class="cm-svg" data-theme="auto" xmlns="http://www.w3.org/2000/svg" width="1207.27" height="1766" viewBox="0 0 1207.27 1766" role="img" aria-labelledby="cm-title cm-desc" font-family="'Inter', 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', system-ui, -apple-system, sans-serif">
<title id="cm-title">把 DSH 插件做成三个渠道都能上架的产品 — 上下文信息架构图</title>
<desc id="cm-desc">把 DSH 插件做成三个渠道都能上架的产品: 18 个节点, 3 层, 2 条关联.</desc>
<style>
.cm-svg{--bg:#f8fafc;--surface:#ffffff;--surface-alt:#f1f5f9;--ink:#0f172a;--ink-soft:#1e293b;--muted:#64748b;--faint:#94a3b8;--edge:#cbd5e1;--edge-strong:#94a3b8;--pill:#e2e8f0;--grid:rgba(15, 23, 42, 0.04)}
.cm-svg[data-theme="dark"]{--bg:#0b1220;--surface:#0f172a;--surface-alt:#111c31;--ink:#e2e8f0;--ink-soft:#cbd5e1;--muted:#94a3b8;--faint:#64748b;--edge:#334155;--edge-strong:#475569;--pill:#1e293b;--grid:rgba(148, 163, 184, 0.08)}
@media (prefers-color-scheme: dark){.cm-svg[data-theme="auto"]{--bg:#0b1220;--surface:#0f172a;--surface-alt:#111c31;--ink:#e2e8f0;--ink-soft:#cbd5e1;--muted:#94a3b8;--faint:#64748b;--edge:#334155;--edge-strong:#475569;--pill:#1e293b;--grid:rgba(148, 163, 184, 0.08)}}
.cm-n-goal{--kind:#2563eb;--card-tint:#eff6ff}
.cm-svg[data-theme="dark"] .cm-n-goal{--kind:#60a5fa;--card-tint:#12233f}
@media (prefers-color-scheme: dark){.cm-svg[data-theme="auto"] .cm-n-goal{--kind:#60a5fa;--card-tint:#12233f}}
.cm-n-context{--kind:#64748b;--card-tint:#f8fafc}
.cm-svg[data-theme="dark"] .cm-n-context{--kind:#94a3b8;--card-tint:#17203a}
@media (prefers-color-scheme: dark){.cm-svg[data-theme="auto"] .cm-n-context{--kind:#94a3b8;--card-tint:#17203a}}
.cm-n-decision{--kind:#7c3aed;--card-tint:#f5f3ff}
.cm-svg[data-theme="dark"] .cm-n-decision{--kind:#a78bfa;--card-tint:#1d1a3a}
@media (prefers-color-scheme: dark){.cm-svg[data-theme="auto"] .cm-n-decision{--kind:#a78bfa;--card-tint:#1d1a3a}}
.cm-n-action{--kind:#059669;--card-tint:#ecfdf5}
.cm-svg[data-theme="dark"] .cm-n-action{--kind:#34d399;--card-tint:#0d2a24}
@media (prefers-color-scheme: dark){.cm-svg[data-theme="auto"] .cm-n-action{--kind:#34d399;--card-tint:#0d2a24}}
.cm-n-artifact{--kind:#d97706;--card-tint:#fffbeb}
.cm-svg[data-theme="dark"] .cm-n-artifact{--kind:#fbbf24;--card-tint:#2b2110}
@media (prefers-color-scheme: dark){.cm-svg[data-theme="auto"] .cm-n-artifact{--kind:#fbbf24;--card-tint:#2b2110}}
.cm-n-risk{--kind:#e11d48;--card-tint:#fff1f2}
.cm-svg[data-theme="dark"] .cm-n-risk{--kind:#fb7185;--card-tint:#2e1420}
@media (prefers-color-scheme: dark){.cm-svg[data-theme="auto"] .cm-n-risk{--kind:#fb7185;--card-tint:#2e1420}}
.cm-n-question{--kind:#0891b2;--card-tint:#ecfeff}
.cm-svg[data-theme="dark"] .cm-n-question{--kind:#22d3ee;--card-tint:#0c2a33}
@media (prefers-color-scheme: dark){.cm-svg[data-theme="auto"] .cm-n-question{--kind:#22d3ee;--card-tint:#0c2a33}}
.cm-n-note{--kind:#475569;--card-tint:#f1f5f9}
.cm-svg[data-theme="dark"] .cm-n-note{--kind:#94a3b8;--card-tint:#1a2438}
@media (prefers-color-scheme: dark){.cm-svg[data-theme="auto"] .cm-n-note{--kind:#94a3b8;--card-tint:#1a2438}}
.cm-bg{fill:var(--bg)}
.cm-title{fill:var(--ink);font-size:24px;font-weight:650;letter-spacing:-0.2px}
.cm-subtitle{fill:var(--muted);font-size:12.5px}
.cm-meta{fill:var(--faint);font-size:11px;letter-spacing:0.4px}
.cm-card-halo{fill:var(--card-tint);opacity:.5}
.cm-card{fill:var(--surface);stroke:var(--kind);stroke-opacity:.42;stroke-width:1.2px}
.cm-accent{fill:var(--kind);opacity:.92}
.cm-pill{fill:var(--kind);font-size:9.5px;font-weight:700;letter-spacing:1.1px}
.cm-label{fill:var(--ink);font-size:13.5px;font-weight:600}
.cm-detail{fill:var(--muted);font-size:11.5px}
.cm-status{fill:var(--status, transparent)}
.cm-edge{fill:none;stroke:var(--edge-strong);stroke-width:1.5px;stroke-linecap:round;opacity:.85}
.cm-cross{fill:none;stroke:var(--edge-strong);stroke-width:1.3px;stroke-dasharray:5 4;opacity:.7}
.cm-cross-label{fill:var(--muted);font-size:9.5px;letter-spacing:.3px}
.cm-cross-chip{fill:var(--surface);stroke:var(--edge);stroke-width:1px}
.cm-legend-title{fill:var(--faint);font-size:9.5px;font-weight:700;letter-spacing:1.4px}
.cm-legend-text{fill:var(--muted);font-size:11px}
.cm-legend-dot{fill:var(--kind);stroke:none}
.cm-node-new .cm-card{stroke-dasharray:5 3}
.cm-node-changed .cm-card{stroke-width:2px}
.cm-diff-badge text{fill:#fff;font-size:9px;font-weight:700}
.cm-brand{fill:var(--faint);font-size:10px;letter-spacing:.3px}
.cm-hint{fill:var(--faint);font-size:10px}
</style>
<defs>
<marker id="cm-arrow" viewBox="0 0 10 10" refX="8.5" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 1 1.6 L 9 5 L 1 8.4 z" fill="var(--edge-strong)"/>
</marker>
</defs>
<rect class="cm-bg" x="0" y="0" width="1207.27" height="1766"/>
<g class="cm-header">
<text class="cm-meta" x="56" y="34">上下文信息架构图</text>
<text class="cm-meta" x="1151.27" y="34" text-anchor="end">18 个节点 · 3 层 · 2 条关联</text>
<text class="cm-meta" x="1151.27" y="52" text-anchor="end">生成于 2026-11-04</text>
<text class="cm-title" x="56" y="80">把 DSH 插件做成三个渠道都能上架的产品</text>
<text class="cm-subtitle" x="56" y="107">本次对话的上下文结构:调研、设计、交付与风险</text>
</g>
<g class="cm-links">
<path class="cm-edge" d="M 310.02 844 C 349.54 844, 346.5 311.5, 386.02 311.5"/>
<path class="cm-edge" d="M 310.02 844 C 349.54 844, 346.5 647.5, 386.02 647.5"/>
<path class="cm-edge" d="M 310.02 844 C 349.54 844, 346.5 1019.5, 386.02 1019.5"/>
<path class="cm-edge" d="M 310.02 844 C 349.54 844, 346.5 1391.5, 386.02 1391.5"/>
<path class="cm-edge" d="M 657.52 311.5 C 697.04 311.5, 694 194.5, 733.52 194.5"/>
<path class="cm-edge" d="M 657.52 311.5 C 697.04 311.5, 694 311.5, 733.52 311.5"/>
<path class="cm-edge" d="M 657.52 311.5 C 697.04 311.5, 694 428.5, 733.52 428.5"/>
<path class="cm-edge" d="M 657.52 647.5 C 697.04 647.5, 694 538, 733.52 538"/>
<path class="cm-edge" d="M 657.52 647.5 C 697.04 647.5, 694 647.5, 733.52 647.5"/>
<path class="cm-edge" d="M 657.52 647.5 C 697.04 647.5, 694 757, 733.52 757"/>
<path class="cm-edge" d="M 657.52 1019.5 C 697.04 1019.5, 694 859, 733.52 859"/>
<path class="cm-edge" d="M 657.52 1019.5 C 697.04 1019.5, 694 961, 733.52 961"/>
<path class="cm-edge" d="M 657.52 1019.5 C 697.04 1019.5, 694 1070.5, 733.52 1070.5"/>
<path class="cm-edge" d="M 657.52 1019.5 C 697.04 1019.5, 694 1180, 733.52 1180"/>
<path class="cm-edge" d="M 657.52 1391.5 C 697.04 1391.5, 694 1282, 733.52 1282"/>
<path class="cm-edge" d="M 657.52 1391.5 C 697.04 1391.5, 694 1391.5, 733.52 1391.5"/>
<path class="cm-edge" d="M 657.52 1391.5 C 697.04 1391.5, 694 1501, 733.52 1501"/>
</g>
<g class="cm-crosslinks">
<g class="cm-crosslink" data-from="b4a" data-to="b3c"><path class="cm-cross" d="M 1053.52 1282 C 1109.52 1282, 1109.52 1070.5, 1053.52 1070.5" marker-end="url(#cm-arrow)"/><rect class="cm-cross-chip" x="1102.02" y="1168.25" width="31" height="16" rx="8"/><text class="cm-cross-label" x="1117.52" y="1179.25" text-anchor="middle">阻塞</text></g>
<g class="cm-crosslink" data-from="b4b" data-to="b3a"><path class="cm-cross" d="M 1053.52 1391.5 C 1109.52 1391.5, 1109.52 859, 1053.52 859" marker-end="url(#cm-arrow)"/><rect class="cm-cross-chip" x="1087.77" y="1117.25" width="59.5" height="16" rx="8"/><text class="cm-cross-label" x="1117.52" y="1128.25" text-anchor="middle">影响默认值</text></g>
</g>
<g class="cm-nodes">
<g class="cm-node cm-n-goal" data-id="goal" data-kind="goal" data-search="开发 dsh 插件并完成三渠道上架 能装、能用、能过安全扫描,不是占位 demo goal">
<rect class="cm-card-halo" x="56" y="801" width="254.02" height="86" rx="12"/>
<rect class="cm-card" x="56" y="801" width="254.02" height="86" rx="12"/>
<rect class="cm-accent" x="57" y="811" width="3" height="66" rx="1.5"/>
<text class="cm-pill" x="83" y="824">目标</text>
<circle class="cm-status" cx="75" cy="820" r="3.1" style="--status:#2563eb"><title>状态: 进行中</title></circle>
<text class="cm-label" x="71" y="847.88">开发 DSH 插件并完成三渠道上架</text>
<text class="cm-detail" x="71" y="863.88">能装、能用、能过安全扫描,不是占位 demo</text>
</g>
<g class="cm-node cm-n-context" data-id="b1" data-kind="context" data-search="渠道调研 三个目录的收录机制各不相同,必须先摸清规则 context">
<rect class="cm-card-halo" x="386.02" y="268.5" width="271.5" height="86" rx="12"/>
<rect class="cm-card" x="386.02" y="268.5" width="271.5" height="86" rx="12"/>
<rect class="cm-accent" x="387.02" y="278.5" width="3" height="66" rx="1.5"/>
<text class="cm-pill" x="413.02" y="291.5">背景</text>
<circle class="cm-status" cx="405.02" cy="287.5" r="3.1" style="--status:#16a34a"><title>状态: 已完成</title></circle>
<text class="cm-label" x="401.02" y="315.38">渠道调研</text>
<text class="cm-detail" x="401.02" y="331.38">三个目录的收录机制各不相同,必须先摸清规则</text>
</g>
<g class="cm-node cm-n-context" data-id="b1a" data-kind="context" data-search="dsh.so 是验收清单制 dsh 字段 / cordis 清单 / dsh topic 三者有其一;readme 带安装说明;spdx 许可证;源码可扫描 context">
<rect class="cm-card-halo" x="733.52" y="144" width="320" height="101" rx="12"/>
<rect class="cm-card" x="733.52" y="144" width="320" height="101" rx="12"/>
<rect class="cm-accent" x="734.52" y="154" width="3" height="81" rx="1.5"/>
<text class="cm-pill" x="748.52" y="167">背景</text>
<text class="cm-label" x="748.52" y="190.88">dsh.so 是验收清单制</text>
<text class="cm-detail" x="748.52" y="206.88">dsh 字段 / cordis 清单 / DSH topic 三者有其一;</text>
<text class="cm-detail" x="748.52" y="221.88">README 带安装说明;SPDX 许可证;源码可扫描</text>
</g>
<g class="cm-node cm-n-context" data-id="b1b" data-kind="context" data-search="marketplace 靠 github topic 自动同步 仓库描述即卡片摘要,readme 即详情页,缺 license 会被标注为保留所有权利 context">
<rect class="cm-card-halo" x="733.52" y="261" width="320" height="101" rx="12"/>
<rect class="cm-card" x="733.52" y="261" width="320" height="101" rx="12"/>
<rect class="cm-accent" x="734.52" y="271" width="3" height="81" rx="1.5"/>
<text class="cm-pill" x="748.52" y="284">背景</text>
<text class="cm-label" x="748.52" y="307.88">marketplace 靠 GitHub topic 自动同步</text>
<text class="cm-detail" x="748.52" y="323.88">仓库描述即卡片摘要,README 即详情页,缺 LICENSE</text>
<text class="cm-detail" x="748.52" y="338.88">会被标注为保留所有权利</text>
</g>
<g class="cm-node cm-n-context" data-id="b1c" data-kind="context" data-search="curated 清单是一插件一 yaml data/plugins/<owner>__<repo>.yml,readme 由脚本生成,不要手改 context">
<rect class="cm-card-halo" x="733.52" y="378" width="320" height="101" rx="12"/>
<rect class="cm-card" x="733.52" y="378" width="320" height="101" rx="12"/>
<rect class="cm-accent" x="734.52" y="388" width="3" height="81" rx="1.5"/>
<text class="cm-pill" x="748.52" y="401">背景</text>
<text class="cm-label" x="748.52" y="424.88">curated 清单是一插件一 YAML</text>
<text class="cm-detail" x="748.52" y="440.88">data/plugins/<owner>__<repo>.yml,README 由脚本生</text>
<text class="cm-detail" x="748.52" y="455.88">成,不要手改</text>
</g>
<g class="cm-node cm-n-decision" data-id="b2" data-kind="decision" data-search="产品设计 四件事定下来,后面只是执行 decision">
<rect class="cm-card-halo" x="386.02" y="604.5" width="271.5" height="86" rx="12"/>
<rect class="cm-card" x="386.02" y="604.5" width="271.5" height="86" rx="12"/>
<rect class="cm-accent" x="387.02" y="614.5" width="3" height="66" rx="1.5"/>
<text class="cm-pill" x="413.02" y="627.5">决策</text>
<circle class="cm-status" cx="405.02" cy="623.5" r="3.1" style="--status:#16a34a"><title>状态: 已完成</title></circle>
<text class="cm-label" x="401.02" y="651.38">产品设计</text>
<text class="cm-detail" x="401.02" y="667.38">四件事定下来,后面只是执行</text>
</g>
<g class="cm-node cm-n-decision" data-id="b2a" data-kind="decision" data-search="方向:对话上下文信息架构图 目标、背景、决策、动作、产物、风险、待确认分组成图 decision">
<rect class="cm-card-halo" x="733.52" y="495" width="320" height="86" rx="12"/>
<rect class="cm-card" x="733.52" y="495" width="320" height="86" rx="12"/>
<rect class="cm-accent" x="734.52" y="505" width="3" height="66" rx="1.5"/>
<text class="cm-pill" x="760.52" y="518">决策</text>
<circle class="cm-status" cx="752.52" cy="514" r="3.1" style="--status:#16a34a"><title>状态: 已完成</title></circle>
<text class="cm-label" x="748.52" y="541.88">方向:对话上下文信息架构图</text>
<text class="cm-detail" x="748.52" y="557.88">目标、背景、决策、动作、产物、风险、待确认分组成图</text>
</g>
<g class="cm-node cm-n-decision" data-id="b2b" data-kind="decision" data-search="零运行时依赖 直接注册原始 tooldefinition,parameters 写 json schema,不跟随作者 dsl 漂移 decision">
<rect class="cm-card-halo" x="733.52" y="597" width="320" height="101" rx="12"/>
<rect class="cm-card" x="733.52" y="597" width="320" height="101" rx="12"/>
<rect class="cm-accent" x="734.52" y="607" width="3" height="81" rx="1.5"/>
<text class="cm-pill" x="760.52" y="620">决策</text>
<circle class="cm-status" cx="752.52" cy="616" r="3.1" style="--status:#16a34a"><title>状态: 已完成</title></circle>
<text class="cm-label" x="748.52" y="643.88">零运行时依赖</text>
<text class="cm-detail" x="748.52" y="659.88">直接注册原始 ToolDefinition,parameters 写 JSON</text>
<text class="cm-detail" x="748.52" y="674.88">Schema,不跟随作者 DSL 漂移</text>
</g>
<g class="cm-node cm-n-decision" data-id="b2c" data-kind="decision" data-search="输出 svg / html / mermaid 三件套 svg 进文档,html 给人看,markdown 进 pr 可审阅 decision">
<rect class="cm-card-halo" x="733.52" y="714" width="320" height="86" rx="12"/>
<rect class="cm-card" x="733.52" y="714" width="320" height="86" rx="12"/>
<rect class="cm-accent" x="734.52" y="724" width="3" height="66" rx="1.5"/>
<text class="cm-pill" x="760.52" y="737">决策</text>
<circle class="cm-status" cx="752.52" cy="733" r="3.1" style="--status:#16a34a"><title>状态: 已完成</title></circle>
<text class="cm-label" x="748.52" y="760.88">输出 SVG / HTML / Mermaid 三件套</text>
<text class="cm-detail" x="748.52" y="776.88">SVG 进文档,HTML 给人看,Markdown 进 PR 可审阅</text>
</g>
<g class="cm-node cm-n-action" data-id="b3" data-kind="action" data-search="交付计划 从渲染内核到三份提交物 action">
<rect class="cm-card-halo" x="386.02" y="976.5" width="271.5" height="86" rx="12"/>
<rect class="cm-card" x="386.02" y="976.5" width="271.5" height="86" rx="12"/>
<rect class="cm-accent" x="387.02" y="986.5" width="3" height="66" rx="1.5"/>
<text class="cm-pill" x="413.02" y="999.5">动作</text>
<circle class="cm-status" cx="405.02" cy="995.5" r="3.1" style="--status:#2563eb"><title>状态: 进行中</title></circle>
<text class="cm-label" x="401.02" y="1023.38">交付计划</text>
<text class="cm-detail" x="401.02" y="1039.38">从渲染内核到三份提交物</text>
</g>
<g class="cm-node cm-n-action" data-id="b3a" data-kind="action" data-search="确定性树布局与双主题渲染 无 canvas、无随机数,同输入永远得到同一张图 action">
<rect class="cm-card-halo" x="733.52" y="816" width="320" height="86" rx="12"/>
<rect class="cm-card" x="733.52" y="816" width="320" height="86" rx="12"/>
<rect class="cm-accent" x="734.52" y="826" width="3" height="66" rx="1.5"/>
<text class="cm-pill" x="760.52" y="839">动作</text>
<circle class="cm-status" cx="752.52" cy="835" r="3.1" style="--status:#2563eb"><title>状态: 进行中</title></circle>
<text class="cm-label" x="748.52" y="862.88">确定性树布局与双主题渲染</text>
<text class="cm-detail" x="748.52" y="878.88">无 canvas、无随机数,同输入永远得到同一张图</text>
</g>
<g class="cm-node cm-n-action" data-id="b3b" data-kind="action" data-search="单元测试与真实启动冒烟 覆盖规格校验、布局不重叠、转义、插件注册与写盘 action">
<rect class="cm-card-halo" x="733.52" y="918" width="320" height="86" rx="12"/>
<rect class="cm-card" x="733.52" y="918" width="320" height="86" rx="12"/>
<rect class="cm-accent" x="734.52" y="928" width="3" height="66" rx="1.5"/>
<text class="cm-pill" x="760.52" y="941">动作</text>
<circle class="cm-status" cx="752.52" cy="937" r="3.1" style="--status:#94a3b8"><title>状态: 计划中</title></circle>
<text class="cm-label" x="748.52" y="964.88">单元测试与真实启动冒烟</text>
<text class="cm-detail" x="748.52" y="980.88">覆盖规格校验、布局不重叠、转义、插件注册与写盘</text>
</g>
<g class="cm-node cm-n-action" data-id="b3c" data-kind="action" data-search="三渠道提交物与 pr 文案 dsh.so 提交串、marketplace 表单、两处 curated 清单补丁 action">
<rect class="cm-card-halo" x="733.52" y="1020" width="320" height="101" rx="12"/>
<rect class="cm-card" x="733.52" y="1020" width="320" height="101" rx="12"/>
<rect class="cm-accent" x="734.52" y="1030" width="3" height="81" rx="1.5"/>
<text class="cm-pill" x="760.52" y="1043">动作</text>
<circle class="cm-status" cx="752.52" cy="1039" r="3.1" style="--status:#94a3b8"><title>状态: 计划中</title></circle>
<text class="cm-label" x="748.52" y="1066.88">三渠道提交物与 PR 文案</text>
<text class="cm-detail" x="748.52" y="1082.88">dsh.so 提交串、marketplace 表单、两处 curated 清单</text>
<text class="cm-detail" x="748.52" y="1097.88">补丁</text>
</g>
<g class="cm-node cm-n-artifact" data-id="b3d" data-kind="artifact" data-search="dsh-context-map 仓库 lib/、bin/、docs/、examples/、license、ci artifact">
<rect class="cm-card-halo" x="733.52" y="1137" width="320" height="86" rx="12"/>
<rect class="cm-card" x="733.52" y="1137" width="320" height="86" rx="12"/>
<rect class="cm-accent" x="734.52" y="1147" width="3" height="66" rx="1.5"/>
<text class="cm-pill" x="760.52" y="1160">产物</text>
<circle class="cm-status" cx="752.52" cy="1156" r="3.1" style="--status:#2563eb"><title>状态: 进行中</title></circle>
<text class="cm-label" x="748.52" y="1183.88">dsh-context-map 仓库</text>
<text class="cm-detail" x="748.52" y="1199.88">lib/、bin/、docs/、examples/、LICENSE、CI</text>
</g>
<g class="cm-node cm-n-risk" data-id="b4" data-kind="risk" data-search="风险与待办 上架前必须解决的两件事 risk">
<rect class="cm-card-halo" x="386.02" y="1348.5" width="271.5" height="86" rx="12"/>
<rect class="cm-card" x="386.02" y="1348.5" width="271.5" height="86" rx="12"/>
<rect class="cm-accent" x="387.02" y="1358.5" width="3" height="66" rx="1.5"/>
<text class="cm-pill" x="413.02" y="1371.5">风险</text>
<circle class="cm-status" cx="405.02" cy="1367.5" r="3.1" style="--status:#2563eb"><title>状态: 进行中</title></circle>
<text class="cm-label" x="401.02" y="1395.38">风险与待办</text>
<text class="cm-detail" x="401.02" y="1411.38">上架前必须解决的两件事</text>
</g>
<g class="cm-node cm-n-risk" data-id="b4a" data-kind="risk" data-search="本机没有 github / npm 登录态 推仓库、发 npm 包、开 pr 都需要你完成一次授权 risk">
<rect class="cm-card-halo" x="733.52" y="1239" width="320" height="86" rx="12"/>
<rect class="cm-card" x="733.52" y="1239" width="320" height="86" rx="12"/>
<rect class="cm-accent" x="734.52" y="1249" width="3" height="66" rx="1.5"/>
<text class="cm-pill" x="760.52" y="1262">风险</text>
<circle class="cm-status" cx="752.52" cy="1258" r="3.1" style="--status:#e11d48"><title>状态: 受阻</title></circle>
<text class="cm-label" x="748.52" y="1285.88">本机没有 GitHub / npm 登录态</text>
<text class="cm-detail" x="748.52" y="1301.88">推仓库、发 npm 包、开 PR 都需要你完成一次授权</text>
</g>
<g class="cm-node cm-n-risk" data-id="b4b" data-kind="risk" data-search="插件进程 cwd ≠ 会话工作区 默认输出目录可能落在应用目录,模型应显式传绝对 outdir risk">
<rect class="cm-card-halo" x="733.52" y="1341" width="320" height="101" rx="12"/>
<rect class="cm-card" x="733.52" y="1341" width="320" height="101" rx="12"/>
<rect class="cm-accent" x="734.52" y="1351" width="3" height="81" rx="1.5"/>
<text class="cm-pill" x="760.52" y="1364">风险</text>
<circle class="cm-status" cx="752.52" cy="1360" r="3.1" style="--status:#2563eb"><title>状态: 进行中</title></circle>
<text class="cm-label" x="748.52" y="1387.88">插件进程 cwd ≠ 会话工作区</text>
<text class="cm-detail" x="748.52" y="1403.88">默认输出目录可能落在应用目录,模型应显式传绝对</text>
<text class="cm-detail" x="748.52" y="1418.88">outDir</text>
</g>
<g class="cm-node cm-n-question" data-id="b4c" data-kind="question" data-search="github 用户名与仓库归属未定 决定 curated 文件名与全部链接 question">
<rect class="cm-card-halo" x="733.52" y="1458" width="320" height="86" rx="12"/>
<rect class="cm-card" x="733.52" y="1458" width="320" height="86" rx="12"/>
<rect class="cm-accent" x="734.52" y="1468" width="3" height="66" rx="1.5"/>
<text class="cm-pill" x="748.52" y="1481">待确认</text>
<text class="cm-label" x="748.52" y="1504.88">GitHub 用户名与仓库归属未定</text>
<text class="cm-detail" x="748.52" y="1520.88">决定 curated 文件名与全部链接</text>
</g>
</g>
<g class="cm-legend">
<text class="cm-legend-title" x="56" y="1552">图例</text>
<g class="cm-legend-item cm-n-goal" data-kind="goal"><rect class="cm-legend-dot" x="56" y="1570" width="8" height="8" rx="2.5"/><text class="cm-legend-text" x="70" y="1578">目标 · 1</text></g>
<g class="cm-legend-item cm-n-context" data-kind="context"><rect class="cm-legend-dot" x="188" y="1570" width="8" height="8" rx="2.5"/><text class="cm-legend-text" x="202" y="1578">背景 · 4</text></g>
<g class="cm-legend-item cm-n-decision" data-kind="decision"><rect class="cm-legend-dot" x="320" y="1570" width="8" height="8" rx="2.5"/><text class="cm-legend-text" x="334" y="1578">决策 · 4</text></g>
<g class="cm-legend-item cm-n-action" data-kind="action"><rect class="cm-legend-dot" x="452" y="1570" width="8" height="8" rx="2.5"/><text class="cm-legend-text" x="466" y="1578">动作 · 4</text></g>
<g class="cm-legend-item cm-n-artifact" data-kind="artifact"><rect class="cm-legend-dot" x="584" y="1570" width="8" height="8" rx="2.5"/><text class="cm-legend-text" x="598" y="1578">产物 · 1</text></g>
<g class="cm-legend-item cm-n-risk" data-kind="risk"><rect class="cm-legend-dot" x="716" y="1570" width="8" height="8" rx="2.5"/><text class="cm-legend-text" x="730" y="1578">风险 · 3</text></g>
<g class="cm-legend-item cm-n-question" data-kind="question"><rect class="cm-legend-dot" x="56" y="1600" width="8" height="8" rx="2.5"/><text class="cm-legend-text" x="70" y="1608">待确认 · 1</text></g>
</g>
<text class="cm-brand" x="56" y="1740">dsh-context-map v0.3.0</text>
<text class="cm-hint" x="1151.27" y="1740" text-anchor="end">根据对话纲要生成</text>
</svg>
</div>
<p class="empty">没有匹配的节点。</p>
</section>
</div>
<script>
(function () {
var stage = document.getElementById('stage')
var canvas = document.getElementById('canvas')
var svg = canvas.querySelector('svg')
var zoomLabel = document.getElementById('zoom-reset')
var q = document.getElementById('q')
var scale = 1
var min = 0.2
var max = 4
function apply(next) {
scale = Math.min(max, Math.max(min, next))
canvas.style.transform = 'scale(' + scale + ')'
zoomLabel.textContent = Math.round(scale * 100) + '%'
}
function fit() {
var pad = 48
var sx = (stage.clientWidth - pad) / svg.width.baseVal.value
var sy = (stage.clientHeight - pad) / svg.height.baseVal.value
apply(Math.min(sx, sy, 1))
}
function themeToggle() {
var root = document.documentElement
var order = ['auto', 'light', 'dark']
var next = order[(order.indexOf(root.getAttribute('data-theme')) + 1) % order.length]
root.setAttribute('data-theme', next)
svg.setAttribute('data-theme', next)
}
function nodes() {
return Array.prototype.slice.call(svg.querySelectorAll('.cm-node'))
}
function search(value) {
var needle = value.trim().toLowerCase()
var hits = 0
nodes().forEach(function (node) {
var hit = needle !== '' && (node.getAttribute('data-search') || '').indexOf(needle) !== -1
node.classList.toggle('hit', hit)
node.classList.toggle('dim', needle !== '' && !hit)
if (hit) hits += 1
})
stage.setAttribute('data-empty', String(needle !== '' && hits === 0))
}
function focusNode(id) {
var target = nodes().filter(function (node) { return node.getAttribute('data-id') === id })[0]
if (!target) return
target.classList.add('flash')
window.setTimeout(function () { target.classList.remove('flash') }, 2400)
var box = target.getBoundingClientRect()
var view = stage.getBoundingClientRect()
stage.scrollBy({ left: box.left - view.left - view.width / 3, top: box.top - view.top - view.height / 3, behavior: 'smooth' })
Array.prototype.forEach.call(document.querySelectorAll('button.jump'), function (button) {
button.classList.toggle('active', button.getAttribute('data-target') === id)
})
}
document.getElementById('zoom-in').addEventListener('click', function () { apply(scale * 1.2) })
document.getElementById('zoom-out').addEventListener('click', function () { apply(scale / 1.2) })
zoomLabel.addEventListener('click', function () { apply(1) })
document.getElementById('fit').addEventListener('click', fit)
document.getElementById('theme').addEventListener('click', themeToggle)
document.getElementById('print').addEventListener('click', function () { window.print() })
var diffButton = document.getElementById('diff')
if (diffButton) diffButton.addEventListener('click', function () {
svg.classList.toggle('only-diff')
diffButton.classList.toggle('active')
})
q.addEventListener('input', function () { search(q.value) })
q.addEventListener('keydown', function (event) {
if (event.key === 'Escape') { q.value = ''; search(''); q.blur() }
})
svg.addEventListener('click', function (event) {
var legend = event.target.closest('.cm-legend-item')
if (!legend) return
var kind = legend.getAttribute('data-kind')
var off = !svg.classList.contains('hide-' + kind)
svg.classList.toggle('hide-' + kind, off)
legend.classList.toggle('off', off)
})
document.addEventListener('click', function (event) {
var jump = event.target.closest('button.jump')
if (jump) focusNode(jump.getAttribute('data-target'))
})
document.addEventListener('keydown', function (event) {
var typing = /^(INPUT|TEXTAREA|SELECT)$/.test(document.activeElement.tagName)
if (event.key === '/' && !typing) { event.preventDefault(); q.focus() }
if (typing) return
if (event.key === '+' || event.key === '=') { event.preventDefault(); apply(scale * 1.2) }
if (event.key === '-') { event.preventDefault(); apply(scale / 1.2) }
if (event.key === '0') { event.preventDefault(); apply(1) }
if (event.key === 'f' || event.key === 'F') { event.preventDefault(); fit() }
})
if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) fit()
})()
</script>
</body>
</html>