# 工程结构说明

```text
harness-plugin/
├─ package.json                 # npm、dsh.bundle、dsh.client 与脚本清单
├─ cordis.patch.yml             # 把插件 Host 行插入当前 profile
├─ tsconfig.json                # 开发期严格 TypeScript 配置
├─ tsconfig.build.json          # 仅生成发布用声明文件
├─ tsdown.config.ts             # Host ESM + 浏览器 lazy-CJS bundle
├─ assets/
│  └─ backgrounds/              # 从 F:\tmp 选取并优化的五张摄影背景
├─ scripts/
│  ├─ generate-background-assets.mjs # 把 JPEG 生成可打包的 data URL 模块
│  └─ install-profile.mjs       # Desktop/Web profile 安装脚本
├─ src/
│  ├─ index.ts                  # Host 入口，注册 ctx.skinTokenUsage
│  ├─ usage.ts                  # 投影校验与 Token 汇总纯函数
│  └─ client/
│     ├─ index.tsx              # Client 入口，注册主题、背景与设置项
│     ├─ themes.ts              # 两套半透明 --dsw-* 主题定义
│     ├─ backgrounds.ts         # 背景清单、持久化与 DOM 应用控制器
│     ├─ background-assets.generated.ts # 构建前生成的内嵌图片数据
│     ├─ ThemePicker.tsx        # 皮肤与背景切换设置组件
│     ├─ TokenUsagePanel.tsx    # “设置 → Token 用量”详细面板
│     ├─ token-usage-source.ts  # 当前会话与 tokenUsage 投影订阅桥
│     └─ styles.ts              # 主题、背景与设置面板样式
├─ tests/
│  ├─ plugin.spec.ts            # Host 激活依赖回归测试
│  ├─ usage.spec.ts             # Token 求和、缓存率、异常输入
│  ├─ token-usage-panel.spec.ts # Token 面板空状态与汇总回归测试
│  ├─ themes.spec.ts            # 主题 ID 与 Token 字典约束
│  └─ backgrounds.spec.ts       # 背景 ID、内嵌资源与偏好约束
├─ docs/
│  ├─ STRUCTURE.md              # 本文件
│  ├─ ARCHITECTURE.md           # Host/Client 数据流与边界
│  └─ DEVELOPMENT.md            # 调试、构建、安装、发布
├─ README.md                    # 用户入口与快速开始
├─ LICENSE                      # MIT
└─ .gitignore
```

## 各层职责

### Profile 组合层

`package.json` 的 `dsh.bundle.patch` 指向 `cordis.patch.yml`。用户通过 `dsh plugin ... add` 安装后，Harness 将该 patch 加入 profile 的 bundle 列表。

`cordis.patch.yml` 只插入一个 Host 行，不覆盖 base/web 内置行，因此不会重复注册 `token-meter`、`session-projection` 或主题运行时。

### Host 层

`src/index.ts` 仅等待标准 base profile 提供的 `sessionProjections` 服务，然后注册 `skinTokenUsage`。服务读取官方 token-meter 写入的 `tokenUsage` 投影，并把四个互斥桶转换成业务友好的汇总对象；token-meter 缺失只会导致统计为空，不会阻塞插件激活。

`src/usage.ts` 不依赖 Cordis，便于单元测试，也把未来投影兼容改动限制在一个文件内。

### Client 层

`src/client/index.tsx` 由 Harness Client Module Loader 加载，完成五件事：

1. 注册固定主题定义。
2. 安装背景控制器并恢复本地偏好。
3. 监听 `theme/change`，向 React 组件提供稳定的外部状态源。
4. 向 `settings.general.item` slot 注册皮肤与背景组合选择器。
5. 跟随当前会话的 `tokenUsage` 投影，并向 `settings.section` 注册独立的 Token 用量页面。

主题切换调用 `ctx.theme.setTheme(id)`。主题注销由 Cordis effect 自动清理；若正在使用的第三方主题被注销，ThemeRuntime 会回退到默认偏好。

背景控制器只在根元素写入插件私有 data 属性和 CSS 变量。照片以 data URL 打进 Client bundle，安装后不读取 `F:` 盘；背景偏好存入 `localStorage`，卸载 effect 会清理 DOM 状态。

### 构建层

`npm run backgrounds:generate` 先把优化后的 JPEG 转换为带显式类型的生成模块，再由 `tsdown.config.ts` 生成：

- `lib/index.js`：Node/Host ESM。
- `lib/client.js`：由 `window.__ModuleLoader__.load(...)` 包装的浏览器动态 bundle，包含内嵌背景。
- Source map：便于桌面端开发工具定位源码。

`tsconfig.build.json` 生成 `lib/types/**` 声明文件。发布包包含运行产物、优化后的背景资源、patch、文档、脚本与许可证。
