dsh-xray 0.4.0 → 0.4.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.md CHANGED
@@ -1,20 +1,39 @@
1
- # dsh-xray
1
+ <p align="center">
2
+ <img src="./assets/hero.svg" width="100%" alt="dsh-xray — X-ray for your DeepSeek Harness">
3
+ </p>
2
4
 
3
- [![npm](https://img.shields.io/npm/v/dsh-xray)](https://www.npmjs.com/package/dsh-xray)
4
- [![CI](https://github.com/alloevil/dsh-xray/actions/workflows/check.yml/badge.svg)](https://github.com/alloevil/dsh-xray/actions/workflows/check.yml)
5
- [![license](https://img.shields.io/npm/l/dsh-xray)](./LICENSE)
5
+ <p align="center">
6
+ <a href="https://www.npmjs.com/package/dsh-xray"><img src="https://img.shields.io/npm/v/dsh-xray?style=flat-square&color=00d4aa" alt="npm"></a>
7
+ <a href="https://github.com/alloevil/dsh-xray/actions/workflows/check.yml"><img src="https://img.shields.io/github/actions/workflow/status/alloevil/dsh-xray/check.yml?style=flat-square&label=CI" alt="CI"></a>
8
+ <a href="./LICENSE"><img src="https://img.shields.io/npm/l/dsh-xray?style=flat-square" alt="license"></a>
9
+ <img src="https://img.shields.io/badge/language-JavaScript-f7df1e?style=flat-square&logo=javascript&logoColor=black" alt="JavaScript">
10
+ </p>
6
11
 
7
- X-ray for your [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) — see what's actually loaded, why, and what it costs you.
12
+ <p align="center">
13
+ <strong>X-ray for your <a href="https://github.com/deepseek-ai/deepseek-harness">DeepSeek Harness</a></strong> — see what's actually loaded, why, and what it costs you.
14
+ </p>
15
+
16
+ <p align="center">
17
+ <a href="./README.zh.md">🇨🇳 中文文档</a>
18
+ </p>
8
19
 
9
20
  ![dsh-xray demo](./docs/demo.svg)
10
21
 
11
- [中文](./README.zh.md)
22
+ ---
23
+
24
+ ## The Problem
25
+
26
+ `dsh --dump-config` shows you the composed tree. The plugin panel shows you a flat list. Neither tells you **why** a plugin is there, **what breaks** if you disable it, or **what it silently costs you**.
12
27
 
13
- > **Status: 0.2.x — static + runtime imaging.** Static commands work even when dsh cannot boot; `deps`/`health` and the agent tool need the plugin mounted.
28
+ **dsh-xray does.**
14
29
 
15
- `dsh --dump-config` shows you the composed tree. The plugin panel shows you a flat list. Neither tells you *why* a plugin is there, *what breaks* if you disable it, or *what it silently costs you*. dsh-xray does.
30
+ > **Status: 0.4.x static + runtime imaging with context-cost attribution.** Static commands work even when dsh cannot boot; `deps`/`health`/`cost`/`shadow` and the agent tool need the plugin mounted.
16
31
 
17
- ## CLI
32
+ ---
33
+
34
+ <p align="center">
35
+ <img src="./assets/section-cli.svg" width="100%" alt="CLI Commands">
36
+ </p>
18
37
 
19
38
  ```sh
20
39
  npx dsh-xray attribute # which layer introduced each row, and who patched it since
@@ -23,47 +42,42 @@ npx dsh-xray diff # declared (static layers) vs actual (dump-config) tree
23
42
  npx dsh-xray snapshot # content-addressed lockfile of the effective composition
24
43
  npx dsh-xray deps [svc] # service dependency graph: providers, consumers, disable-cascade
25
44
  npx dsh-xray health # plugin lifecycle health: failed fibers, pending injects, transitions
26
- npx dsh-xray cost # estimated context-token cost per model-facing tool schema
45
+ npx dsh-xray cost # context cost: prompt sections + tool schemas, estimated tokens
27
46
  npx dsh-xray shadow # services provided by multiple plugins
28
47
  npx dsh-xray audit # static scan of out-of-tree plugins for sensitive touchpoints
29
48
  ```
30
49
 
31
- All commands take `--profile <name>` (default `web`) and `--json`. `diff` exits `1` when the trees disagree; `health` exits `1` when any plugin is unhealthy. `attribute`, `conflicts`, and `snapshot` are fully static: they work even when dsh cannot start. `deps` and `health` read the runtime snapshot the mounted plugin maintains at `$DSH_HOME/xray/runtime.json`.
50
+ <p align="center">
51
+ <img src="./assets/section-features.svg" width="100%" alt="Features">
52
+ </p>
32
53
 
33
- ## What it looks like
54
+ <table>
55
+ <tr>
56
+ <td width="50%">
34
57
 
35
- Every row of the booted tree, attributed to the layer that introduced it — and who patched it since:
58
+ ### 🔍 Layer Attribution
59
+ Which layer introduced each active plugin: kernel bundle, profile dependency, `cordis.patch.yml` insert, or repository source.
36
60
 
37
- ```console
38
- $ npx dsh-xray attribute
39
- # 130 rows in profile "web"
61
+ ### 📊 Declared vs. Actual Diff
62
+ Installed-but-inactive, uninstalled-but-lingering patch rows — all surfaced.
40
63
 
41
- timer @deepseek-ai/dsh-base
42
- hmr @deepseek-ai/dsh-base ← patched by @deepseek-ai/dsh-web-app [disabled]
43
- llm @deepseek-ai/dsh-base
44
- session-query-sqlite @deepseek-ai/dsh-base ← patched by @deepseek-ai/dsh-web-app
45
- ...
46
- ```
64
+ ### ⚡ Conflict Detection
65
+ Plugins patching the same config row, and which one silently wins.
47
66
 
48
- What breaks if you disable a provider — computed from the live service store, not guesses:
67
+ ### 📸 Composition Snapshot
68
+ Export the effective composition as a lockfile; reproduce it elsewhere.
49
69
 
50
- ```console
51
- $ npx dsh-xray deps
52
- # disable-cascade (transitive consumers of each provider):
53
- Loader → 5 plugin(s): AgentPresets, ClientModuleRegistry, Hmr, Include, PluginInventoryGateway
54
- TimerService → 1 plugin(s): Hmr
55
- SessionProjectionRegistry → 1 plugin(s): SessionProjectionCache
56
- ```
70
+ </td>
71
+ <td width="50%">
57
72
 
58
- Which fields have multiple writers, and who silently wins:
73
+ ### 🌐 Service Dependency Graph
74
+ Who provides and consumes each service; what cascades if you disable X.
59
75
 
60
- ```console
61
- $ npx dsh-xray conflicts
62
- session-query-sqlite
63
- .config: @deepseek-ai/dsh-base @deepseek-ai/dsh-web-app (winner: @deepseek-ai/dsh-web-app)
64
- tool-bash
65
- .disabled: @deepseek-ai/dsh-base → @deepseek-ai/dsh-web-app (winner: @deepseek-ai/dsh-web-app)
66
- ```
76
+ ### 💊 Runtime Health
77
+ Per-plugin fiber lifecycle state, startup failures, transition history.
78
+
79
+ ### 🤖 Agent Self-Introspection
80
+ The `xray_composition` tool lets agents inspect their own capability set.
67
81
 
68
82
  What every request actually carries — prompt sections observed at assembly, blended with tool schemas:
69
83
 
@@ -81,44 +95,78 @@ harness:source ~94 5.8% ███
81
95
 
82
96
  And when a patch row targets an id that doesn't exist (dsh skips it silently), `diff` catches it:
83
97
 
84
- ```console
85
- $ npx dsh-xray diff
86
- orphan overrides (silently skipped) (1)
87
- no-such-row in ~/.dsh/profiles/web/cordis.patch.yml
88
- ```
98
+ ### 🛡️ Capability Audit
99
+ Heuristic static scan: network egress, shell, filesystem, env, eval.
89
100
 
90
- ## Agent tool
101
+ </td>
102
+ </tr>
103
+ </table>
91
104
 
92
- Mounted in the tree, dsh-xray registers an `xray_composition` tool (`view: summary | deps | health | cost | shadow`), so an agent can answer "what capabilities do I have / what plugin provides X / why is Y unavailable" about itself.
105
+ <p align="center">
106
+ <img src="./assets/section-agent.svg" width="100%" alt="Agent Tool">
107
+ </p>
93
108
 
94
- ## Safety stance
109
+ Mounted in the tree, dsh-xray registers an `xray_composition` tool (`view: summary | deps | health | cost | shadow`), so an agent can answer:
95
110
 
96
- dsh-xray reads; it never runs. Loader `!!js` expressions in patch files are parsed as opaque markers and never evaluated, the CLI never executes plugin code (`audit` is a pattern scan over source text), and the mounted plugin writes only under `$DSH_HOME/xray/`. See [SECURITY.md](./SECURITY.md).
111
+ > *"What capabilities do I have?" / "What plugin provides X?" / "Why is Y unavailable?"*
97
112
 
98
- ## Capabilities
113
+ about itself.
99
114
 
100
- Diagnostic imaging for a running composition — complementary to [dsh-doctor](https://www.npmjs.com/package/dsh-doctor) (rescue & recovery).
115
+ ---
101
116
 
102
- Shipped in 0.3.x:
117
+ <p align="center">
118
+ <img src="./assets/section-safety.svg" width="100%" alt="Safety Stance">
119
+ </p>
103
120
 
104
- - **Layer attribution** which layer introduced each active plugin: kernel bundle, profile dependency, `cordis.patch.yml` insert, or repository source
105
- - **Declared vs. actual diff** — installed-but-inactive, uninstalled-but-lingering patch rows
106
- - **Conflict detection** — plugins patching the same config row, and which one silently wins
107
- - **Composition snapshot** — export the effective composition as a lockfile; reproduce it elsewhere
108
- - **Service dependency graph** — who provides and consumes each service; what cascades if you disable X (`deps`)
109
- - **Runtime health** — per-plugin fiber lifecycle state, startup failures, transition history (`health`)
110
- - **Agent self-introspection** — the `xray_composition` tool lets agents inspect their own capability set
121
+ **dsh-xray reads; it never runs.**
111
122
 
112
- - **Capability audit** heuristic static scan of out-of-tree plugins: network egress, shell, filesystem, env, eval (`audit`)
113
- - **Service shadowing** services claimed by multiple plugins, per-plugin tool/command registrations (`shadow`)
114
- - **Context cost** estimated tokens each model-facing tool schema occupies (`cost`)
123
+ - Loader `!!js` expressions in patch files are parsed as opaque markers and **never evaluated**
124
+ - The CLI **never executes** plugin code (`audit` is a pattern scan over source text)
125
+ - The mounted plugin writes only under `$DSH_HOME/xray/`
126
+ - See [SECURITY.md](./SECURITY.md)
115
127
 
116
- ## Install
128
+ ---
129
+
130
+ <p align="center">
131
+ <img src="./assets/section-install.svg" width="100%" alt="Install">
132
+ </p>
117
133
 
118
134
  ```sh
119
135
  dsh plugin --profile web add dsh-xray
120
136
  ```
121
137
 
138
+ All commands take `--profile <name>` (default `web`) and `--json`.
139
+
140
+ | Command | Behavior |
141
+ | --- | --- |
142
+ | `diff` | Exits `1` when the trees disagree |
143
+ | `health` | Exits `1` when any plugin is unhealthy |
144
+ | `attribute`, `conflicts`, `snapshot` | Fully static — work even when dsh cannot start |
145
+ | `deps`, `health` | Read runtime snapshot at `$DSH_HOME/xray/runtime.json` |
146
+
147
+ ---
148
+
149
+ <p align="center">
150
+ <img src="./assets/section-capabilities.svg" width="100%" alt="Capabilities">
151
+ </p>
152
+
153
+ Diagnostic imaging for a running composition — complementary to [dsh-doctor](https://www.npmjs.com/package/dsh-doctor) (rescue & recovery).
154
+
155
+ | Feature | Category |
156
+ | --- | --- |
157
+ | Layer attribution | 🔍 Inspection |
158
+ | Declared vs. actual diff | 🔍 Inspection |
159
+ | Conflict detection | 🔍 Inspection |
160
+ | Composition snapshot | 📦 Export |
161
+ | Service dependency graph | 🌐 Runtime |
162
+ | Runtime health | 🌐 Runtime |
163
+ | Agent self-introspection | 🤖 AI |
164
+ | Capability audit | 🛡️ Security |
165
+ | Service shadowing | 🌐 Runtime |
166
+ | Context cost | 💰 Optimization |
167
+
168
+ ---
169
+
122
170
  ## License
123
171
 
124
- MIT
172
+ [MIT](./LICENSE)
package/README.zh.md CHANGED
@@ -10,7 +10,7 @@
10
10
 
11
11
  [English](./README.md)
12
12
 
13
- > **状态:0.2.x — 静态 + 运行时成像。** 静态命令在 dsh 起不来时照样能用;`deps`/`health` 和 agent 工具需要插件已挂载。
13
+ > **状态:0.4.x — 静态 + 运行时成像,含上下文成本归因。** 静态命令在 dsh 起不来时照样能用;`deps`/`health`/`cost`/`shadow` 和 agent 工具需要插件已挂载。
14
14
 
15
15
  `dsh --dump-config` 只给你原始组合树,插件面板只给你平铺列表。它们都不回答:这个插件*为什么*在这、停用它会*连带瘫掉什么*、它在*悄悄消耗什么*。dsh-xray 回答这些。
16
16
 
@@ -23,7 +23,7 @@ npx dsh-xray diff # 声明(静态层)vs 实际(dump-config)组合树
23
23
  npx dsh-xray snapshot # 当前生效组合的内容寻址 lockfile
24
24
  npx dsh-xray deps [svc] # 服务依赖图:提供者、消费者、停用级联
25
25
  npx dsh-xray health # 插件生命周期健康:失败 fiber、等待中的注入、状态迁移史
26
- npx dsh-xray cost # 每个模型可见工具 schema 的估算 token 占用
26
+ npx dsh-xray cost # 上下文成本:prompt sections + 工具 schema 的估算 token 占用
27
27
  npx dsh-xray shadow # 被多个插件同时提供的服务
28
28
  npx dsh-xray audit # 对 out-of-tree 插件做敏感触点静态扫描
29
29
  ```
@@ -99,7 +99,7 @@ dsh-xray 只读不执行。patch 文件里的 loader `!!js` 表达式解析为
99
99
 
100
100
  对运行中组合树的诊断成像——与 [dsh-doctor](https://www.npmjs.com/package/dsh-doctor)(救援与恢复)互补。
101
101
 
102
- 0.3.x 已交付:
102
+ 0.4.x 已交付:
103
103
 
104
104
  - **来源归因** — 每个活跃插件来自哪一层:内核 bundle / profile 依赖 / `cordis.patch.yml` insert / repository 源
105
105
  - **声明 vs 实际 diff** — 装了但没生效、卸了但残留 patch 行
@@ -111,7 +111,7 @@ dsh-xray 只读不执行。patch 文件里的 loader `!!js` 表达式解析为
111
111
 
112
112
  - **能力审计** — 对 out-of-tree 插件的启发式静态扫描:网络外发、shell、文件系统、环境变量、动态求值(`audit`)
113
113
  - **服务重名检测** — 被多个插件同时提供的服务,及每插件工具/命令注册数(`shadow`)
114
- - **上下文成本** — 每个模型可见工具 schema 的估算 token 占用(`cost`)
114
+ - **上下文成本** — prompt sections(观测自 system-prompt/assemble)+ 工具 schema 的估算 token 占用(`cost`)
115
115
 
116
116
  ## 安装
117
117
 
@@ -0,0 +1,156 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="900" height="360" viewBox="0 0 900 360">
2
+ <defs>
3
+ <linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
4
+ <stop offset="0%" style="stop-color:#0a0e17"/>
5
+ <stop offset="100%" style="stop-color:#111827"/>
6
+ </linearGradient>
7
+ <linearGradient id="scanLine" x1="0%" y1="0%" x2="100%" y2="0%">
8
+ <stop offset="0%" style="stop-color:#00d4aa;stop-opacity:0"/>
9
+ <stop offset="50%" style="stop-color:#00d4aa;stop-opacity:0.6"/>
10
+ <stop offset="100%" style="stop-color:#00d4aa;stop-opacity:0"/>
11
+ </linearGradient>
12
+ <linearGradient id="glow" x1="0%" y1="0%" x2="0%" y2="100%">
13
+ <stop offset="0%" style="stop-color:#00d4aa;stop-opacity:0.15"/>
14
+ <stop offset="100%" style="stop-color:#00d4aa;stop-opacity:0"/>
15
+ </linearGradient>
16
+ <filter id="blur">
17
+ <feGaussianBlur in="SourceGraphic" stdDeviation="2"/>
18
+ </filter>
19
+ <filter id="glowFilter">
20
+ <feGaussianBlur in="SourceGraphic" stdDeviation="4"/>
21
+ <feComposite in="SourceGraphic"/>
22
+ </filter>
23
+ </defs>
24
+
25
+ <!-- Background -->
26
+ <rect width="900" height="360" fill="url(#bg)" rx="12"/>
27
+
28
+ <!-- Grid pattern -->
29
+ <g opacity="0.06" stroke="#00d4aa" stroke-width="0.5">
30
+ <line x1="0" y1="0" x2="0" y2="360"/><line x1="50" y1="0" x2="50" y2="360"/>
31
+ <line x1="100" y1="0" x2="100" y2="360"/><line x1="150" y1="0" x2="150" y2="360"/>
32
+ <line x1="200" y1="0" x2="200" y2="360"/><line x1="250" y1="0" x2="250" y2="360"/>
33
+ <line x1="300" y1="0" x2="300" y2="360"/><line x1="350" y1="0" x2="350" y2="360"/>
34
+ <line x1="400" y1="0" x2="400" y2="360"/><line x1="450" y1="0" x2="450" y2="360"/>
35
+ <line x1="500" y1="0" x2="500" y2="360"/><line x1="550" y1="0" x2="550" y2="360"/>
36
+ <line x1="600" y1="0" x2="600" y2="360"/><line x1="650" y1="0" x2="650" y2="360"/>
37
+ <line x1="700" y1="0" x2="700" y2="360"/><line x1="750" y1="0" x2="750" y2="360"/>
38
+ <line x1="800" y1="0" x2="800" y2="360"/><line x1="850" y1="0" x2="850" y2="360"/>
39
+ <line x1="900" y1="0" x2="900" y2="360"/>
40
+ <line x1="0" y1="0" x2="900" y2="0"/><line x1="0" y1="50" x2="900" y2="50"/>
41
+ <line x1="0" y1="100" x2="900" y2="100"/><line x1="0" y1="150" x2="900" y2="150"/>
42
+ <line x1="0" y1="200" x2="900" y2="200"/><line x1="0" y1="250" x2="900" y2="250"/>
43
+ <line x1="0" y1="300" x2="900" y2="300"/><line x1="0" y1="350" x2="900" y2="350"/>
44
+ </g>
45
+
46
+ <!-- Scan lines (x-ray effect) -->
47
+ <rect x="0" y="120" width="900" height="1" fill="url(#scanLine)" opacity="0.4"/>
48
+ <rect x="0" y="180" width="900" height="2" fill="url(#scanLine)" opacity="0.6"/>
49
+ <rect x="0" y="240" width="900" height="1" fill="url(#scanLine)" opacity="0.3"/>
50
+
51
+ <!-- Vertical scan glow -->
52
+ <rect x="280" y="0" width="340" height="360" fill="url(#glow)"/>
53
+
54
+ <!-- Composition tree diagram (left side) -->
55
+ <g transform="translate(60, 80)" opacity="0.3" stroke="#00d4aa" stroke-width="1.5" fill="none">
56
+ <!-- Root node -->
57
+ <rect x="0" y="0" width="120" height="28" rx="4" stroke="#00d4aa" stroke-width="1"/>
58
+ <rect x="0" y="0" width="120" height="28" rx="4" fill="#00d4aa" opacity="0.08"/>
59
+ <text x="60" y="18" text-anchor="middle" fill="#00d4aa" font-family="monospace" font-size="11">dsh-root</text>
60
+ <!-- Branches -->
61
+ <line x1="60" y1="28" x2="30" y2="60"/>
62
+ <line x1="60" y1="28" x2="60" y2="60"/>
63
+ <line x1="60" y1="28" x2="90" y2="60"/>
64
+ <!-- Child nodes -->
65
+ <rect x="0" y="60" width="60" height="22" rx="3" stroke="#00d4aa" stroke-width="1"/>
66
+ <text x="30" y="75" text-anchor="middle" fill="#00d4aa" font-family="monospace" font-size="9">kernel</text>
67
+ <rect x="30" y="60" width="60" height="22" rx="3" stroke="#00d4aa" stroke-width="1"/>
68
+ <text x="60" y="75" text-anchor="middle" fill="#00d4aa" font-family="monospace" font-size="9">profile</text>
69
+ <rect x="60" y="60" width="60" height="22" rx="3" stroke="#00d4aa" stroke-width="1"/>
70
+ <text x="90" y="75" text-anchor="middle" fill="#00d4aa" font-family="monospace" font-size="9">plugin</text>
71
+ <!-- Deeper branches -->
72
+ <line x1="30" y1="82" x2="15" y2="110"/>
73
+ <line x1="30" y1="82" x2="45" y2="110"/>
74
+ <line x1="90" y1="82" x2="75" y2="110"/>
75
+ <line x1="90" y1="82" x2="105" y2="110"/>
76
+ <rect x="0" y="110" width="30" height="18" rx="2" stroke="#00d4aa" stroke-width="1"/>
77
+ <text x="15" y="123" text-anchor="middle" fill="#00d4aa" font-family="monospace" font-size="8">svc</text>
78
+ <rect x="30" y="110" width="30" height="18" rx="2" stroke="#00d4aa" stroke-width="1"/>
79
+ <text x="45" y="123" text-anchor="middle" fill="#00d4aa" font-family="monospace" font-size="8">cfg</text>
80
+ <rect x="60" y="110" width="30" height="18" rx="2" stroke="#00d4aa" stroke-width="1"/>
81
+ <text x="75" y="123" text-anchor="middle" fill="#00d4aa" font-family="monospace" font-size="8">dep</text>
82
+ <rect x="90" y="110" width="30" height="18" rx="2" stroke="#00d4aa" stroke-width="1"/>
83
+ <text x="105" y="123" text-anchor="middle" fill="#00d4aa" font-family="monospace" font-size="8">ext</text>
84
+ </g>
85
+
86
+ <!-- Scan pulse ring (right side) -->
87
+ <g transform="translate(730, 160)">
88
+ <circle cx="0" cy="0" r="30" fill="none" stroke="#00d4aa" stroke-width="1" opacity="0.15"/>
89
+ <circle cx="0" cy="0" r="50" fill="none" stroke="#00d4aa" stroke-width="0.5" opacity="0.1"/>
90
+ <circle cx="0" cy="0" r="70" fill="none" stroke="#00d4aa" stroke-width="0.5" opacity="0.06"/>
91
+ <circle cx="0" cy="0" r="12" fill="#00d4aa" opacity="0.08" filter="url(#glowFilter)"/>
92
+ <circle cx="0" cy="0" r="5" fill="#00d4aa" opacity="0.4"/>
93
+ <!-- Data points around the scan -->
94
+ <circle cx="45" cy="-25" r="3" fill="#00d4aa" opacity="0.3"/>
95
+ <circle cx="-35" cy="40" r="2" fill="#00d4aa" opacity="0.25"/>
96
+ <circle cx="60" cy="15" r="2.5" fill="#00d4aa" opacity="0.2"/>
97
+ <circle cx="-20" cy="-55" r="2" fill="#00d4aa" opacity="0.2"/>
98
+ <circle cx="30" cy="50" r="3" fill="#00d4aa" opacity="0.15"/>
99
+ <!-- Connection lines -->
100
+ <line x1="5" y1="-5" x2="45" y2="-25" stroke="#00d4aa" stroke-width="0.5" opacity="0.2"/>
101
+ <line x1="-5" y1="5" x2="-35" y2="40" stroke="#00d4aa" stroke-width="0.5" opacity="0.2"/>
102
+ <line x1="8" y1="0" x2="60" y2="15" stroke="#00d4aa" stroke-width="0.5" opacity="0.2"/>
103
+ </g>
104
+
105
+ <!-- Category label -->
106
+ <text x="450" y="80" text-anchor="middle" fill="#00d4aa" font-family="'SF Mono', 'Fira Code', 'Cascadia Code', monospace" font-size="13" letter-spacing="4" opacity="0.7">DIAGNOSTIC IMAGING</text>
107
+
108
+ <!-- Main title -->
109
+ <text x="450" y="140" text-anchor="middle" fill="#ffffff" font-family="'Inter', 'SF Pro Display', -apple-system, sans-serif" font-size="56" font-weight="700" letter-spacing="-1">dsh-xray</text>
110
+
111
+ <!-- Subtitle -->
112
+ <text x="450" y="178" text-anchor="middle" fill="#94a3b8" font-family="'Inter', -apple-system, sans-serif" font-size="18" font-weight="400">X-ray for your DeepSeek Harness</text>
113
+
114
+ <!-- Tagline -->
115
+ <text x="450" y="215" text-anchor="middle" fill="#64748b" font-family="'Inter', -apple-system, sans-serif" font-size="14">see what's actually loaded, why, and what it costs you</text>
116
+
117
+ <!-- Status badge -->
118
+ <g transform="translate(450, 250)">
119
+ <rect x="-100" y="-12" width="200" height="24" rx="12" fill="#00d4aa" opacity="0.1" stroke="#00d4aa" stroke-width="0.5" stroke-opacity="0.3"/>
120
+ <text x="0" y="4" text-anchor="middle" fill="#00d4aa" font-family="'SF Mono', monospace" font-size="11">v0.2.x · static + runtime</text>
121
+ </g>
122
+
123
+ <!-- Feature pills -->
124
+ <g transform="translate(450, 295)">
125
+ <g transform="translate(-220, 0)">
126
+ <rect x="-40" y="-10" width="80" height="20" rx="10" fill="#1e293b" stroke="#334155" stroke-width="0.5"/>
127
+ <text x="0" y="4" text-anchor="middle" fill="#94a3b8" font-family="'SF Mono', monospace" font-size="10">attribute</text>
128
+ </g>
129
+ <g transform="translate(-110, 0)">
130
+ <rect x="-40" y="-10" width="80" height="20" rx="10" fill="#1e293b" stroke="#334155" stroke-width="0.5"/>
131
+ <text x="0" y="4" text-anchor="middle" fill="#94a3b8" font-family="'SF Mono', monospace" font-size="10">conflicts</text>
132
+ </g>
133
+ <g transform="translate(0, 0)">
134
+ <rect x="-40" y="-10" width="80" height="20" rx="10" fill="#1e293b" stroke="#334155" stroke-width="0.5"/>
135
+ <text x="0" y="4" text-anchor="middle" fill="#94a3b8" font-family="'SF Mono', monospace" font-size="10">snapshot</text>
136
+ </g>
137
+ <g transform="translate(110, 0)">
138
+ <rect x="-40" y="-10" width="80" height="20" rx="10" fill="#1e293b" stroke="#334155" stroke-width="0.5"/>
139
+ <text x="0" y="4" text-anchor="middle" fill="#94a3b8" font-family="'SF Mono', monospace" font-size="10">health</text>
140
+ </g>
141
+ <g transform="translate(220, 0)">
142
+ <rect x="-40" y="-10" width="80" height="20" rx="10" fill="#1e293b" stroke="#334155" stroke-width="0.5"/>
143
+ <text x="0" y="4" text-anchor="middle" fill="#94a3b8" font-family="'SF Mono', monospace" font-size="10">cost</text>
144
+ </g>
145
+ </g>
146
+
147
+ <!-- Corner accent lines -->
148
+ <line x1="20" y1="20" x2="60" y2="20" stroke="#00d4aa" stroke-width="1" opacity="0.3"/>
149
+ <line x1="20" y1="20" x2="20" y2="60" stroke="#00d4aa" stroke-width="1" opacity="0.3"/>
150
+ <line x1="880" y1="20" x2="840" y2="20" stroke="#00d4aa" stroke-width="1" opacity="0.3"/>
151
+ <line x1="880" y1="20" x2="880" y2="60" stroke="#00d4aa" stroke-width="1" opacity="0.3"/>
152
+ <line x1="20" y1="340" x2="60" y2="340" stroke="#00d4aa" stroke-width="1" opacity="0.3"/>
153
+ <line x1="20" y1="340" x2="20" y2="300" stroke="#00d4aa" stroke-width="1" opacity="0.3"/>
154
+ <line x1="880" y1="340" x2="840" y2="340" stroke="#00d4aa" stroke-width="1" opacity="0.3"/>
155
+ <line x1="880" y1="340" x2="880" y2="300" stroke="#00d4aa" stroke-width="1" opacity="0.3"/>
156
+ </svg>
@@ -0,0 +1,14 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="260" height="60" viewBox="0 0 260 60">
2
+ <defs>
3
+ <linearGradient id="line" x1="0%" y1="0%" x2="100%" y2="0%">
4
+ <stop offset="0%" style="stop-color:#00d4aa;stop-opacity:0"/>
5
+ <stop offset="50%" style="stop-color:#00d4aa;stop-opacity:0.4"/>
6
+ <stop offset="100%" style="stop-color:#00d4aa;stop-opacity:0"/>
7
+ </linearGradient>
8
+ </defs>
9
+ <line x1="0" y1="30" x2="260" y2="30" stroke="url(#line)" stroke-width="1"/>
10
+ <g transform="translate(130, 30)">
11
+ <rect x="-100" y="-16" width="200" height="32" rx="16" fill="#0a0e17" stroke="#1e293b" stroke-width="1"/>
12
+ <text x="0" y="5" text-anchor="middle" fill="#00d4aa" font-family="'SF Mono', 'Fira Code', monospace" font-size="14" font-weight="600" letter-spacing="1">◈ AGENT TOOL</text>
13
+ </g>
14
+ </svg>
@@ -0,0 +1,14 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="288" height="60" viewBox="0 0 288 60">
2
+ <defs>
3
+ <linearGradient id="line" x1="0%" y1="0%" x2="100%" y2="0%">
4
+ <stop offset="0%" style="stop-color:#00d4aa;stop-opacity:0"/>
5
+ <stop offset="50%" style="stop-color:#00d4aa;stop-opacity:0.4"/>
6
+ <stop offset="100%" style="stop-color:#00d4aa;stop-opacity:0"/>
7
+ </linearGradient>
8
+ </defs>
9
+ <line x1="0" y1="30" x2="288" y2="30" stroke="url(#line)" stroke-width="1"/>
10
+ <g transform="translate(144, 30)">
11
+ <rect x="-114" y="-16" width="228" height="32" rx="16" fill="#0a0e17" stroke="#1e293b" stroke-width="1"/>
12
+ <text x="0" y="5" text-anchor="middle" fill="#00d4aa" font-family="'SF Mono', 'Fira Code', monospace" font-size="14" font-weight="600" letter-spacing="1">▦ CAPABILITIES</text>
13
+ </g>
14
+ </svg>
@@ -0,0 +1,14 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="288" height="60" viewBox="0 0 288 60">
2
+ <defs>
3
+ <linearGradient id="line" x1="0%" y1="0%" x2="100%" y2="0%">
4
+ <stop offset="0%" style="stop-color:#00d4aa;stop-opacity:0"/>
5
+ <stop offset="50%" style="stop-color:#00d4aa;stop-opacity:0.4"/>
6
+ <stop offset="100%" style="stop-color:#00d4aa;stop-opacity:0"/>
7
+ </linearGradient>
8
+ </defs>
9
+ <line x1="0" y1="30" x2="288" y2="30" stroke="url(#line)" stroke-width="1"/>
10
+ <g transform="translate(144, 30)">
11
+ <rect x="-114" y="-16" width="228" height="32" rx="16" fill="#0a0e17" stroke="#1e293b" stroke-width="1"/>
12
+ <text x="0" y="5" text-anchor="middle" fill="#00d4aa" font-family="'SF Mono', 'Fira Code', monospace" font-size="14" font-weight="600" letter-spacing="1">▸ CLI COMMANDS</text>
13
+ </g>
14
+ </svg>
@@ -0,0 +1,14 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="232" height="60" viewBox="0 0 232 60">
2
+ <defs>
3
+ <linearGradient id="line" x1="0%" y1="0%" x2="100%" y2="0%">
4
+ <stop offset="0%" style="stop-color:#00d4aa;stop-opacity:0"/>
5
+ <stop offset="50%" style="stop-color:#00d4aa;stop-opacity:0.4"/>
6
+ <stop offset="100%" style="stop-color:#00d4aa;stop-opacity:0"/>
7
+ </linearGradient>
8
+ </defs>
9
+ <line x1="0" y1="30" x2="232" y2="30" stroke="url(#line)" stroke-width="1"/>
10
+ <g transform="translate(116, 30)">
11
+ <rect x="-86" y="-16" width="172" height="32" rx="16" fill="#0a0e17" stroke="#1e293b" stroke-width="1"/>
12
+ <text x="0" y="5" text-anchor="middle" fill="#00d4aa" font-family="'SF Mono', 'Fira Code', monospace" font-size="14" font-weight="600" letter-spacing="1">◆ FEATURES</text>
13
+ </g>
14
+ </svg>
@@ -0,0 +1,14 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="218" height="60" viewBox="0 0 218 60">
2
+ <defs>
3
+ <linearGradient id="line" x1="0%" y1="0%" x2="100%" y2="0%">
4
+ <stop offset="0%" style="stop-color:#00d4aa;stop-opacity:0"/>
5
+ <stop offset="50%" style="stop-color:#00d4aa;stop-opacity:0.4"/>
6
+ <stop offset="100%" style="stop-color:#00d4aa;stop-opacity:0"/>
7
+ </linearGradient>
8
+ </defs>
9
+ <line x1="0" y1="30" x2="218" y2="30" stroke="url(#line)" stroke-width="1"/>
10
+ <g transform="translate(109, 30)">
11
+ <rect x="-79" y="-16" width="158" height="32" rx="16" fill="#0a0e17" stroke="#1e293b" stroke-width="1"/>
12
+ <text x="0" y="5" text-anchor="middle" fill="#00d4aa" font-family="'SF Mono', 'Fira Code', monospace" font-size="14" font-weight="600" letter-spacing="1">▷ INSTALL</text>
13
+ </g>
14
+ </svg>
@@ -0,0 +1,14 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="302" height="60" viewBox="0 0 302 60">
2
+ <defs>
3
+ <linearGradient id="line" x1="0%" y1="0%" x2="100%" y2="0%">
4
+ <stop offset="0%" style="stop-color:#00d4aa;stop-opacity:0"/>
5
+ <stop offset="50%" style="stop-color:#00d4aa;stop-opacity:0.4"/>
6
+ <stop offset="100%" style="stop-color:#00d4aa;stop-opacity:0"/>
7
+ </linearGradient>
8
+ </defs>
9
+ <line x1="0" y1="30" x2="302" y2="30" stroke="url(#line)" stroke-width="1"/>
10
+ <g transform="translate(151, 30)">
11
+ <rect x="-121" y="-16" width="242" height="32" rx="16" fill="#0a0e17" stroke="#1e293b" stroke-width="1"/>
12
+ <text x="0" y="5" text-anchor="middle" fill="#00d4aa" font-family="'SF Mono', 'Fira Code', monospace" font-size="14" font-weight="600" letter-spacing="1">◇ SAFETY STANCE</text>
13
+ </g>
14
+ </svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-xray",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "X-ray for your DeepSeek Harness — see what's actually loaded, why, and what it costs you.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -24,7 +24,8 @@
24
24
  "cordis.patch.yml",
25
25
  "README.md",
26
26
  "README.zh.md",
27
- "docs"
27
+ "docs",
28
+ "assets"
28
29
  ],
29
30
  "dependencies": {
30
31
  "yaml": "^2.6.0"