dsh-config-manager 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/README.md +146 -187
- package/README.zh-CN.md +145 -188
- package/lib/client.js +80 -84
- package/lib/client.js.map +1 -1
- package/package.json +1 -1
- package/src/client/import/ConflictList.tsx +5 -3
package/README.zh-CN.md
CHANGED
|
@@ -1,252 +1,209 @@
|
|
|
1
|
-
# DSH Config Manager
|
|
1
|
+
# 🎒 DSH Config Manager
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**把你的 DSH 配置打包带走 —— 换台电脑,环境一键恢复。**
|
|
4
4
|
|
|
5
|
-
[English](README.md)
|
|
5
|
+
[English](README.md) · [简体中文](README.zh-CN.md)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 这是什么?🤔
|
|
10
|
+
|
|
11
|
+
DSH 是你的 AI 助手工作台,里面存着你的各种设置:模型配置、插件、常用技能、工作区……
|
|
12
|
+
|
|
13
|
+
**DSH Config Manager 就是它的「搬家工具」**:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
┌──────────────┐ ① 一键导出 ┌─────────────────┐ ② 一键导入 ┌──────────────┐
|
|
17
|
+
│ 电脑 A │ ─────────────► │ dsh-config.zip │ ─────────────► │ 电脑 B │
|
|
18
|
+
│ 我的配置 │ │ (一个文件) │ │ 配置全部恢复 │
|
|
19
|
+
└──────────────┘ └─────────────────┘ └──────────────┘
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
> ⚠️ **安全第一**:默认**不导出**任何密钥(API Key / Token / 密码)。详见 [安全](#-安全)。
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## ✨ 核心亮点
|
|
8
27
|
|
|
9
|
-
|
|
28
|
+
| 图标 | 功能 | 一句话说明 |
|
|
29
|
+
|:---:|---|---|
|
|
30
|
+
| 🚀 | **一键导出** | 点一下,把推荐配置打包成一个 ZIP |
|
|
31
|
+
| 📦 | **一键导入** | 在另一台电脑点一下,环境就回来了 |
|
|
32
|
+
| 👀 | **先预览再导入** | 导入前完整预览,**绝不偷偷改你的配置** |
|
|
33
|
+
| ⚔️ | **冲突处理** | 遇到同名配置,让你自己选:保留现有的 / 用导入的 |
|
|
34
|
+
| 🗺️ | **路径自动映射** | 换了电脑路径变了?自动检测并让你重新指定 |
|
|
35
|
+
| 🔒 | **密钥安全** | API Key 默认不导出;导入后提醒你重新填写 |
|
|
36
|
+
| ↩️ | **自动回滚** | 导入失败自动恢复原样,不会弄坏现有配置 |
|
|
37
|
+
| 🗂️ | **配置档案 Profiles** | 保存多套配置(工作 / 个人),随时切换 |
|
|
10
38
|
|
|
11
39
|
---
|
|
12
40
|
|
|
13
|
-
##
|
|
41
|
+
## 🔄 它是怎么工作的?
|
|
14
42
|
|
|
15
|
-
|
|
16
|
-
本插件**不整包复制 `~/.dsh`**,而是按真实配置类别分区收集、打包为带清单(manifest)与校验和(checksums)的 ZIP 备份,并在导入端执行
|
|
43
|
+
### 导出(打包带走)
|
|
17
44
|
|
|
18
45
|
```
|
|
19
|
-
|
|
46
|
+
读取你的配置 → 剔除密钥(安全) → 生成清单 → 计算校验和 → 打包成 ZIP
|
|
20
47
|
```
|
|
21
48
|
|
|
22
|
-
|
|
49
|
+
### 导入(恢复环境)
|
|
23
50
|
|
|
24
|
-
|
|
51
|
+
每一步都先确认、先备份,**绝不直接改你的配置**:
|
|
25
52
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
- **Schema 版本与迁移**:`schemaVersion` 独立演进,迁移逻辑集中在 `src/migrations/`。
|
|
34
|
-
- **幂等**:同一 ZIP 重复导入不产生重复数据(按 Plugin ID / MCP serverName / Prompt name / Workspace id / Credential ref 识别)。
|
|
35
|
-
- **兼容性评分**:Excellent / Good / Partial / Unsupported(规则驱动)。
|
|
36
|
-
- **Profiles(配置 Profile)**:保存当前配置为 Profile / 切换 / 复制 / 重命名 / 导出 / 导入 / 删除;切换带 Preview + 快照 + 回滚(`src/profiles/`)。
|
|
53
|
+
```
|
|
54
|
+
选择 ZIP → 校验文件 → 检查完整性 → 检查版本 → 兼容性检查
|
|
55
|
+
→ 扫描内容 → 生成导入计划 → 预览确认
|
|
56
|
+
→ 自动备份当前配置 → 执行导入 → 验证 → 完成
|
|
57
|
+
│
|
|
58
|
+
└─ 中途失败?→ 自动恢复原样(回滚)
|
|
59
|
+
```
|
|
37
60
|
|
|
38
|
-
|
|
61
|
+
---
|
|
39
62
|
|
|
40
|
-
|
|
41
|
-
`dsh.bundle.patch`(指向 `cordis.patch.yml`,CLI 的 bundle 硬判据)与 `dsh.client`(浏览器半声明),
|
|
42
|
-
`npm run build` 产出双半产物(`lib/index.js` Host 半 + `lib/client.js` 浏览器半,后者以
|
|
43
|
-
`window.__ModuleLoader__.load(...)` 装载进 Web GUI)。
|
|
63
|
+
## 📥 安装
|
|
44
64
|
|
|
45
|
-
|
|
65
|
+
本插件是标准的 **DSH 插件**,安装只需要两步:
|
|
46
66
|
|
|
47
67
|
```bash
|
|
48
|
-
# ①
|
|
49
|
-
dsh plugin --profile web add dsh-config-manager --config.auto-install-peers=false
|
|
68
|
+
# ① 安装插件
|
|
69
|
+
dsh plugin --profile web add dsh-config-manager@latest --config.auto-install-peers=false
|
|
50
70
|
|
|
51
|
-
# ②
|
|
52
|
-
npm run build
|
|
53
|
-
npm pack # 产出 dsh-config-manager-0.1.0.tgz
|
|
54
|
-
dsh plugin --profile web add file:/absolute/path/to/dsh-config-manager-0.1.0.tgz
|
|
71
|
+
# ② 重启 DSH(设置页就会出现「备份与迁移」入口)
|
|
55
72
|
```
|
|
56
73
|
|
|
57
|
-
>
|
|
58
|
-
> `@deepseek-ai/dsh-plugin-marketplace`、`dsh-host-plugin-inventory`)尚未发布到公共 npm registry,
|
|
59
|
-
> 只在本地 DSH profile 环境存在。安装时若 npm/pnpm 尝试解析 peer 依赖并失败,请跳过 peer 自动安装:
|
|
60
|
-
> - npm 直接安装:`npm install --legacy-peer-deps`
|
|
61
|
-
> - `dsh plugin add`(内部转发 pnpm):`dsh plugin --profile web add <spec> --config.auto-install-peers=false`
|
|
62
|
-
>
|
|
63
|
-
> 运行时这些包由 DSH profile 自身提供(peerDependencies 语义),插件不重复安装。
|
|
74
|
+
> 💡 照着复制就行:`--config.auto-install-peers=false` 跳过几个尚未公开发布的 DSH 核心依赖(运行时由 DSH 自己提供),`@latest` 确保装到最新版。
|
|
64
75
|
|
|
65
|
-
|
|
66
|
-
> ```bash
|
|
67
|
-
> $env:DSH_HOME = "D:\tmp\dsh-home" # Windows PowerShell
|
|
68
|
-
> dsh plugin --profile test add file:<tgz> --config.auto-install-peers=false
|
|
69
|
-
> dsh --profile test --dump-config | Select-String config-manager # 应看到挂载行
|
|
70
|
-
> ```
|
|
76
|
+
---
|
|
71
77
|
|
|
72
|
-
##
|
|
78
|
+
## 🚀 快速上手(3 分钟体验)
|
|
73
79
|
|
|
74
|
-
|
|
80
|
+
```
|
|
81
|
+
电脑 A(导出)
|
|
82
|
+
1. 打开 DSH → 设置 → 「备份与迁移」
|
|
83
|
+
2. 点「导出配置」→ 选「快速导出」
|
|
84
|
+
3. 得到一个 dsh-config-2026-08-14.zip(可确认报告里没有密钥)
|
|
85
|
+
|
|
86
|
+
把 ZIP 拷到电脑 B(导入)
|
|
87
|
+
1. 打开 DSH → 「备份与迁移」→「导入配置」
|
|
88
|
+
2. 选择 ZIP → 等待分析 → 查看「导入预览」
|
|
89
|
+
3. 有路径问题?→ 选择新路径(可批量映射)
|
|
90
|
+
4. 有同名配置冲突?→ 选择 保留现有的 / 用导入的
|
|
91
|
+
5. 确认导入 → 等待完成
|
|
92
|
+
6. 按提示重新填写缺失的 API Key
|
|
93
|
+
7. ✅ 设置 / 插件 / MCP / 技能 / 工作区都回来了
|
|
94
|
+
```
|
|
75
95
|
|
|
76
|
-
|
|
77
|
-
- **Custom Export**:按分区逐项选择(可选 `pluginFiles`、`sessions`;`sessions` 默认关闭)。
|
|
96
|
+
---
|
|
78
97
|
|
|
79
|
-
|
|
98
|
+
## 🧩 功能详解
|
|
80
99
|
|
|
81
|
-
|
|
100
|
+
### 📤 导出(两种方式)
|
|
82
101
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
```
|
|
102
|
+
| 方式 | 说明 |
|
|
103
|
+
|---|---|
|
|
104
|
+
| **快速导出**(推荐) | 一键导出推荐配置:设置 / UI / 模型 / 插件 / MCP / 技能 / 工作区等 |
|
|
105
|
+
| **自定义导出** | 自己勾选要导出的分类 |
|
|
88
106
|
|
|
89
|
-
|
|
107
|
+
> 导出文件:`dsh-config-<日期>.zip`,内含清单 + 各分类数据 + SHA-256 校验和。
|
|
90
108
|
|
|
91
|
-
|
|
109
|
+
### 📥 导入(安全流程)
|
|
92
110
|
|
|
93
|
-
|
|
111
|
+
- **未确认不写入**:分析、预览阶段零修改
|
|
112
|
+
- **先备份再导入**:执行前自动备份将被修改的配置
|
|
113
|
+
- **失败自动回滚**:按你的选择整体回滚或跳过失败项继续
|
|
94
114
|
|
|
95
|
-
|
|
96
|
-
- `ctx.settings.describe({ redactSecrets: true })` 作为第一道防线剥离 DSH 已知秘密;敏感字段扫描器作为第二道防线兜底插件自定义字段。
|
|
97
|
-
- 凭据(`.credentials.yaml`)**永不导出值**,只导出状态(`{ref, required, configured, hasValue:false}`),导入后生成「N credentials need attention」补录清单。
|
|
98
|
-
- **加密完整备份(可选)**:显式勾选「Include secrets」时,要求设置备份密码,使用 `node:crypto`(scrypt 派生 + AES-256-GCM 加密),**密码绝不写入 manifest**;`secrets.enc` 只有解密后经 `ctx.credentials.set()` 写回。
|
|
99
|
-
- 无加密提供者时 `includeSecrets: true` 会被拒绝(绝不明文泄密)。
|
|
100
|
-
- 日志系统全部经过 redaction,Secret 值永不进入日志。
|
|
101
|
-
- ZIP 属于不可信输入:防御 Zip Slip / 绝对路径 / 符号链接 / zip bomb(条目数 / 压缩体积 / 解压体积 / 压缩比上限)/ 畸形 ZIP / checksum 不匹配,任何一条触发即整体拒绝。
|
|
115
|
+
### 👀 导入预览(Dry Run)
|
|
102
116
|
|
|
103
|
-
|
|
117
|
+
导入前完整展示:
|
|
104
118
|
|
|
105
|
-
|
|
119
|
+
```
|
|
120
|
+
✓ 18 项设置将被更新 ✓ 6 个插件已安装
|
|
121
|
+
⚠ 2 个插件需要安装 ⚠ 3 个密钥需要重新填写
|
|
122
|
+
⚠ 1 个路径需要映射 ⚠ 2 处冲突需要处理
|
|
123
|
+
```
|
|
106
124
|
|
|
107
|
-
|
|
108
|
-
- `~/.dsh/.anonymous-user-id`(设备唯一 ID)
|
|
109
|
-
- 会话历史(`sessions/`,默认关闭;v1 仅支持文件级复制)
|
|
110
|
-
- Logs / Cache / 临时文件
|
|
111
|
-
- 浏览器 localStorage 中的 UI 状态(Host 侧无通道,仅导出 `uiMigrationNotes` 说明)
|
|
112
|
-
- 插件二进制(绝不打包,只迁移清单并走官方安装机制)
|
|
125
|
+
### ⚔️ 冲突处理
|
|
113
126
|
|
|
114
|
-
|
|
127
|
+
目标电脑已有同名配置时,让你选:
|
|
115
128
|
|
|
116
|
-
|
|
|
129
|
+
| 选项 | 含义 |
|
|
117
130
|
|---|---|
|
|
118
|
-
|
|
|
119
|
-
|
|
|
120
|
-
|
|
131
|
+
| **保留现有的** | 不动目标电脑的原配置 |
|
|
132
|
+
| **用导入的** | 用备份里的配置覆盖 |
|
|
133
|
+
|
|
134
|
+
> 说明:刻意**不提供**「稍后决定 / 再看看」选项——未决的冲突会让导入无法继续,每个冲突都必须在继续前做出选择。
|
|
121
135
|
|
|
122
|
-
|
|
136
|
+
### 🗺️ 路径映射
|
|
123
137
|
|
|
124
|
-
|
|
138
|
+
换了电脑,`C:\Users\alice\projects` 在另一台机器上不存在?插件会:
|
|
139
|
+
1. 自动检测失效的绝对路径
|
|
140
|
+
2. 让你选择新路径
|
|
141
|
+
3. 支持**批量前缀映射**(如 `C:\Users\alice\` → `/Users/bob/` 一键替换所有相关路径)
|
|
142
|
+
|
|
143
|
+
### 🔒 密钥处理
|
|
144
|
+
|
|
145
|
+
| 场景 | 行为 |
|
|
125
146
|
|---|---|
|
|
126
|
-
|
|
|
127
|
-
|
|
|
128
|
-
|
|
|
129
|
-
| Unsupported | schema 超出支持范围 |
|
|
147
|
+
| 默认备份 | **不含任何密钥值**,只记录"哪些密钥需要填写" |
|
|
148
|
+
| 加密备份(可选) | 设置密码后用 AES-256-GCM 加密,密码**绝不写入备份文件** |
|
|
149
|
+
| 导入后 | 提示「3 个密钥需要重新填写」,输入后仅保存在内存中写入 |
|
|
130
150
|
|
|
131
|
-
|
|
151
|
+
### 🗂️ 配置档案(Profiles)
|
|
132
152
|
|
|
133
|
-
|
|
134
|
-
dsh-config-2026-08-14.zip
|
|
135
|
-
├── manifest.json # schemaVersion / exporter / source / sections / security
|
|
136
|
-
├── config/settings.json # 非 UI settings namespace(redacted + revision)
|
|
137
|
-
├── config/ui.json # UI namespace + uiMigrationNotes
|
|
138
|
-
├── ai/providers.json # llm-* providers/models(同 section 不拆分)
|
|
139
|
-
├── plugins/plugins.json + patch.json
|
|
140
|
-
├── mcp/servers.json # 组合 patch 提取的 dsh-mcp-client 条目
|
|
141
|
-
├── custom/prompts.json + skills/
|
|
142
|
-
├── agents/presets/
|
|
143
|
-
├── workspaces/workspaces.json
|
|
144
|
-
├── plugin-files/ # 可选
|
|
145
|
-
├── security/credentials.json # 凭据状态(永不含值)
|
|
146
|
-
├── security/secrets.enc # 仅加密备份
|
|
147
|
-
└── integrity/checksums.json # SHA-256
|
|
148
|
-
```
|
|
153
|
+
保存多套配置(如「工作」「个人」),随时切换;切换同样带预览 + 自动备份 + 回滚。
|
|
149
154
|
|
|
150
|
-
|
|
155
|
+
---
|
|
151
156
|
|
|
152
|
-
|
|
153
|
-
npm install --legacy-peer-deps # peer 含未发布公共 registry 的 DSH 核心包,见 Installation
|
|
154
|
-
npm run typecheck # tsc --noEmit
|
|
155
|
-
npm run build # tsc -p tsconfig.build.json(Host 半 lib/)+ tsdown(client bundle lib/client.js)
|
|
156
|
-
npm run bundle # 仅重新构建 client bundle(tsdown)
|
|
157
|
-
npm test # node --test "src/**/*.test.ts" "tests/**/*.test.ts"
|
|
158
|
-
```
|
|
157
|
+
## 🛡️ 安全
|
|
159
158
|
|
|
160
|
-
|
|
159
|
+
- **默认备份不包含任何密钥值** —— 这是硬性规则,导出时强制执行
|
|
160
|
+
- **不导出**:API Key / 密码 / Token / Cookie / 会话 / 设备唯一 ID / 日志缓存 / 插件二进制
|
|
161
|
+
- **ZIP 是"不可信输入"**:防御 Zip Slip、恶意路径、压缩炸弹、损坏文件——任何一项触发就整体拒绝
|
|
162
|
+
- **日志全程脱敏**:密钥值永不进入日志
|
|
163
|
+
- **加密备份**:scrypt + AES-256-GCM,密码只在内存中,绝不写入文件
|
|
161
164
|
|
|
162
|
-
|
|
165
|
+
---
|
|
163
166
|
|
|
164
|
-
|
|
167
|
+
## 🤝 兼容性
|
|
165
168
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
169
|
+
| 状态 | 含义 |
|
|
170
|
+
|---|---|
|
|
171
|
+
| ✅ Excellent | 同平台、配置齐全、版本兼容 |
|
|
172
|
+
| 👍 Good | 备份来自更旧版本的 DSH |
|
|
173
|
+
| ⚠️ Partial | 跨平台 / 部分配置缺失 / 备份比当前新 |
|
|
174
|
+
| ❌ Unsupported | 备份版本超出支持范围(无法导入) |
|
|
170
175
|
|
|
171
|
-
|
|
176
|
+
---
|
|
172
177
|
|
|
173
|
-
|
|
174
|
-
1. 打开包页面:https://www.npmjs.com/package/dsh-config-manager → **Settings → Publishing access**。
|
|
175
|
-
2. **Add trusted publisher**:Provider **GitHub Actions** · owner `xiajiajun516` · repository `dsh-config-manager` · workflow filename `publish.yml`。
|
|
178
|
+
## ❓ 常见问题
|
|
176
179
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
npm logout
|
|
180
|
-
npm login # 网页 OAuth + 2FA 验证码
|
|
181
|
-
npm trust github dsh-config-manager \
|
|
182
|
-
--file publish.yml \
|
|
183
|
-
--repo xiajiajun516/dsh-config-manager \
|
|
184
|
-
--allow-publish # 首次会要求输入 2FA 验证码
|
|
185
|
-
npm trust list dsh-config-manager # 验证
|
|
186
|
-
```
|
|
180
|
+
**Q:备份会包含我的 API Key 吗?**
|
|
181
|
+
不会。默认备份**绝不包含任何密钥**,只记录哪些密钥需要重新填写。
|
|
187
182
|
|
|
188
|
-
|
|
183
|
+
**Q:导入会不会覆盖我现有的配置?**
|
|
184
|
+
不会偷偷覆盖。有冲突时让你选择:保留现有的 / 用导入的;导入前还会自动备份,失败可回滚。
|
|
189
185
|
|
|
190
|
-
|
|
186
|
+
**Q:换电脑(Windows → macOS)能用吗?**
|
|
187
|
+
能。插件会自动检测失效的绝对路径,让你重新映射(支持批量替换)。
|
|
191
188
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
- 也可在 Actions 页面点 **Run workflow** 手动触发。
|
|
189
|
+
**Q:导出的 ZIP 被改坏了还能导入吗?**
|
|
190
|
+
不能。校验和检查不通过会直接拒绝导入(防止损坏或篡改)。
|
|
195
191
|
|
|
196
|
-
|
|
192
|
+
**Q:重复导入会重复吗?**
|
|
193
|
+
不会。按插件 ID / MCP 名称 / 技能名等稳定标识去重,重复导入自动跳过已有项。
|
|
197
194
|
|
|
198
|
-
|
|
195
|
+
---
|
|
199
196
|
|
|
200
|
-
|
|
197
|
+
## 📋 已知限制(用户须知)
|
|
201
198
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
| Migration(场景 G) | `migrateToCurrent` 机制级:同版本 / 过新 / 低于最低 / 无路径 / 注册重叠 / 链式推进(**如实说明:当前 v1 即最新,无真实 v2 可端到端验证**) |
|
|
208
|
-
| Security(场景 F) | 畸形 ZIP / 超大条目数 / checksum 不匹配与缺失 / Zip Slip / 绝对路径 |
|
|
209
|
-
| Cross-platform(场景 B) | win32→darwin / darwin→win32 / linux→win32 批量前缀映射 |
|
|
210
|
-
| Redaction | 日志消息 / meta / 全链路不泄 Secret 值 |
|
|
211
|
-
| Schema | manifest 结构校验 / 版本判定函数 |
|
|
212
|
-
|
|
213
|
-
当前测试结果:**186 tests, all passing**(`npm test`),`npm run typecheck` 与 `npm run build` 均通过。
|
|
214
|
-
|
|
215
|
-
## Known limitations
|
|
216
|
-
|
|
217
|
-
1. **Workspace 只能建/改标题**:DSH 的 workspace 服务没有「整体覆盖」写通道——导入时可创建 workspace 与更新标题;path 与会话列表由 DSH 依真实目录自行维护,跨设备路径通过路径映射适配。
|
|
218
|
-
2. **部分 DSH 核心包未发布公共 npm registry**(如 `@deepseek-ai/dsh-plugin-marketplace`、`dsh-host-plugin-inventory`):依赖其 API 的功能只在本地 profile 环境可用;安装本插件需跳过 peer 自动安装(见 [Installation](#installation) 的 `--legacy-peer-deps` 说明)。
|
|
219
|
-
3. **MCP 无管理 API**(研究报告 §4.3):MCP 以组合 patch 行导入,需重启 DSH 生效;无增删改 API。
|
|
220
|
-
4. **插件安装需重启**:`pluginMarketplace.installPlugin` 只返回 `needsRestart`,重启依赖 DSH Desktop。
|
|
221
|
-
5. **浏览器 localStorage UI 状态不迁移**(任务看板数据、面板宽度等):Host 无通道。
|
|
222
|
-
6. **keybindings / workflows 配置 / commands / rules 文件**:DSH 当前无这些概念,不实现分区(不发明)。
|
|
223
|
-
7. **凭据值无法回滚**:DSH 不回读凭据值,导入中覆盖的凭据在回滚时只能标记 `manualHint` 人工补录。
|
|
224
|
-
8. **新建项无法删除回滚**:DSH settings 无删除语义,导入新建的 namespace 在回滚时只能人工处理(如实报告 partial)。
|
|
225
|
-
9. **Schema 迁移**:v1→v2 为占位(当前 `CURRENT_SCHEMA_VERSION=1`),机制已就绪但无真实 v2 可验证。
|
|
226
|
-
10. **历史会话迁移**:默认关闭,v1 仅文件级复制。
|
|
227
|
-
11. **加密备份**:依赖用户设置强密码;密码丢失则 `secrets.enc` 无法解密(设计使然)。
|
|
228
|
-
|
|
229
|
-
## Manual Test(最短人工测试流程)
|
|
230
|
-
|
|
231
|
-
> 前提:两台 DSH(或同一台的两份配置目录);本插件已按 [Installation](#installation) 打包并安装。
|
|
199
|
+
1. **安装/更新插件或 MCP 后需重启 DSH 才生效**
|
|
200
|
+
2. **部分界面状态不迁移**(如任务看板数据、面板宽度——它们存在浏览器里,不在 DSH 配置文件内)
|
|
201
|
+
3. **keybindings / workflows 配置 / commands / rules**:DSH 当前没有这些概念,因此不会导出相关内容
|
|
202
|
+
4. **历史会话默认不迁移**(v1 仅支持文件级复制)
|
|
203
|
+
5. **加密备份**:密码丢失则无法解密(设计使然——请牢记密码)
|
|
232
204
|
|
|
233
|
-
|
|
234
|
-
DSH A
|
|
235
|
-
→ 打开 Config Manager → Export Configuration
|
|
236
|
-
→ 选择 Quick Export → 导出 dsh-config-<date>.zip(确认报告中 Secret 均被排除)
|
|
237
|
-
→ 将 ZIP 复制到 DSH B
|
|
238
|
-
|
|
239
|
-
DSH B
|
|
240
|
-
→ 打开 Config Manager → Import Configuration
|
|
241
|
-
→ 选择 ZIP → 等待 Analyzing... → 查看 Import Preview(分区/插件/路径映射/凭据补录清单)
|
|
242
|
-
→ 如有路径问题 → 选择映射目录(批量前缀映射)
|
|
243
|
-
→ 解决冲突(Keep Current / Use Imported / Review)
|
|
244
|
-
→ 确认 Import → 观察进度 → 查看结果报告
|
|
245
|
-
→ 补充缺失凭据(N credentials need attention)
|
|
246
|
-
→ Verify:确认 settings / 插件 / MCP / Prompts / Skills / Workspaces 已恢复;
|
|
247
|
-
若导入中途失败 → 确认已自动回滚、原配置可正常使用
|
|
248
|
-
```
|
|
205
|
+
> 维护者与开发者:构建、测试、自动发布与完整技术说明见 [DEVELOPERS.md](DEVELOPERS.md)。
|
|
249
206
|
|
|
250
207
|
---
|
|
251
208
|
|
|
252
|
-
|
|
209
|
+
**产品原则**:宁可少迁移一个配置,也不要破坏你现有的配置。任何导入都遵循 `分析 → 预览 → 备份 → 修改 → 验证 → 回滚(如需要)`;任何密钥都遵循 `不默认导出 / 不记日志 / 不暴露 / 不静默转移`。
|
package/lib/client.js
CHANGED
|
@@ -559,93 +559,93 @@ if (typeof document !== "undefined" && document.querySelector("style[data-tag=\"
|
|
|
559
559
|
document.head.appendChild(tag);
|
|
560
560
|
}
|
|
561
561
|
var config_manager_module_css_default = {
|
|
562
|
+
"actionRow": "_367UGW_actionRow",
|
|
563
|
+
"formError": "_367UGW_formError",
|
|
564
|
+
"errorItem": "_367UGW_errorItem",
|
|
565
|
+
"secretFields": "_367UGW_secretFields",
|
|
566
|
+
"section": "_367UGW_section",
|
|
567
|
+
"sectionBody": "_367UGW_sectionBody",
|
|
568
|
+
"groupHeader": "_367UGW_groupHeader",
|
|
569
|
+
"fieldLabel": "_367UGW_fieldLabel",
|
|
562
570
|
"input": "_367UGW_input",
|
|
563
|
-
"dangerButton": "_367UGW_dangerButton",
|
|
564
|
-
"badgeInfo": "_367UGW_badgeInfo",
|
|
565
|
-
"errorReason": "_367UGW_errorReason",
|
|
566
|
-
"pathMappingList": "_367UGW_pathMappingList",
|
|
567
|
-
"sectionTitleBlock": "_367UGW_sectionTitleBlock",
|
|
568
|
-
"radioLabel": "_367UGW_radioLabel",
|
|
569
|
-
"modeTab": "_367UGW_modeTab",
|
|
570
571
|
"groupLabel": "_367UGW_groupLabel",
|
|
571
|
-
"
|
|
572
|
-
"
|
|
573
|
-
"groupNote": "_367UGW_groupNote",
|
|
574
|
-
"dshCmSpin": "_367UGW_dshCmSpin",
|
|
572
|
+
"radioLabel": "_367UGW_radioLabel",
|
|
573
|
+
"modeTabs": "_367UGW_modeTabs",
|
|
575
574
|
"progressMeta": "_367UGW_progressMeta",
|
|
576
|
-
"
|
|
577
|
-
"
|
|
578
|
-
"
|
|
579
|
-
"
|
|
575
|
+
"conflictHead": "_367UGW_conflictHead",
|
|
576
|
+
"conflictOptions": "_367UGW_conflictOptions",
|
|
577
|
+
"conflictId": "_367UGW_conflictId",
|
|
578
|
+
"pathIssueKind": "_367UGW_pathIssueKind",
|
|
579
|
+
"iconButton": "_367UGW_iconButton",
|
|
580
|
+
"empty": "_367UGW_empty",
|
|
581
|
+
"dshCmSpin": "_367UGW_dshCmSpin",
|
|
582
|
+
"errorActionLabel": "_367UGW_errorActionLabel",
|
|
583
|
+
"progressLabel": "_367UGW_progressLabel",
|
|
580
584
|
"errorList": "_367UGW_errorList",
|
|
581
|
-
"
|
|
585
|
+
"conflictList": "_367UGW_conflictList",
|
|
586
|
+
"severityError": "_367UGW_severityError",
|
|
587
|
+
"banner": "_367UGW_banner",
|
|
588
|
+
"card": "_367UGW_card",
|
|
589
|
+
"pathMappingList": "_367UGW_pathMappingList",
|
|
590
|
+
"spinnerWrap": "_367UGW_spinnerWrap",
|
|
591
|
+
"badgeInfo": "_367UGW_badgeInfo",
|
|
592
|
+
"pathOld": "_367UGW_pathOld",
|
|
593
|
+
"pathRow": "_367UGW_pathRow",
|
|
594
|
+
"spinner": "_367UGW_spinner",
|
|
595
|
+
"groupItems": "_367UGW_groupItems",
|
|
596
|
+
"errorLine": "_367UGW_errorLine",
|
|
582
597
|
"conflictItem": "_367UGW_conflictItem",
|
|
583
|
-
"
|
|
598
|
+
"progressBarDone": "_367UGW_progressBarDone",
|
|
584
599
|
"sectionTitle": "_367UGW_sectionTitle",
|
|
585
|
-
"
|
|
600
|
+
"pathValue": "_367UGW_pathValue",
|
|
601
|
+
"dshCmIndeterminate": "_367UGW_dshCmIndeterminate",
|
|
586
602
|
"progressBlock": "_367UGW_progressBlock",
|
|
587
|
-
"
|
|
603
|
+
"progressPercent": "_367UGW_progressPercent",
|
|
604
|
+
"badgeWarn": "_367UGW_badgeWarn",
|
|
605
|
+
"sectionSubtitle": "_367UGW_sectionSubtitle",
|
|
606
|
+
"conflictDetail": "_367UGW_conflictDetail",
|
|
588
607
|
"hiddenFile": "_367UGW_hiddenFile",
|
|
589
|
-
"groupList": "_367UGW_groupList",
|
|
590
|
-
"progressDetail": "_367UGW_progressDetail",
|
|
591
|
-
"conflictHead": "_367UGW_conflictHead",
|
|
592
|
-
"errorLine": "_367UGW_errorLine",
|
|
593
|
-
"optionsCard": "_367UGW_optionsCard",
|
|
594
608
|
"groupCard": "_367UGW_groupCard",
|
|
595
|
-
"
|
|
609
|
+
"viewTabs": "_367UGW_viewTabs",
|
|
610
|
+
"spinnerLabel": "_367UGW_spinnerLabel",
|
|
611
|
+
"viewTab": "_367UGW_viewTab",
|
|
612
|
+
"progressIndeterminate": "_367UGW_progressIndeterminate",
|
|
613
|
+
"dangerButton": "_367UGW_dangerButton",
|
|
614
|
+
"field": "_367UGW_field",
|
|
615
|
+
"progressBar": "_367UGW_progressBar",
|
|
616
|
+
"sectionTitleBlock": "_367UGW_sectionTitleBlock",
|
|
617
|
+
"groupList": "_367UGW_groupList",
|
|
618
|
+
"progressTrack": "_367UGW_progressTrack",
|
|
619
|
+
"reportText": "_367UGW_reportText",
|
|
620
|
+
"rollbackBox": "_367UGW_rollbackBox",
|
|
621
|
+
"secretsList": "_367UGW_secretsList",
|
|
596
622
|
"warnList": "_367UGW_warnList",
|
|
597
|
-
"
|
|
598
|
-
"
|
|
599
|
-
"
|
|
623
|
+
"pathNew": "_367UGW_pathNew",
|
|
624
|
+
"badgeOk": "_367UGW_badgeOk",
|
|
625
|
+
"statRow": "_367UGW_statRow",
|
|
600
626
|
"errorBanner": "_367UGW_errorBanner",
|
|
601
|
-
"
|
|
627
|
+
"hint": "_367UGW_hint",
|
|
628
|
+
"sectionHeader": "_367UGW_sectionHeader",
|
|
629
|
+
"progressDetail": "_367UGW_progressDetail",
|
|
630
|
+
"reportFooter": "_367UGW_reportFooter",
|
|
631
|
+
"ghostButton": "_367UGW_ghostButton",
|
|
632
|
+
"checkboxRow": "_367UGW_checkboxRow",
|
|
633
|
+
"groupNote": "_367UGW_groupNote",
|
|
602
634
|
"categoryItem": "_367UGW_categoryItem",
|
|
603
635
|
"errorAction": "_367UGW_errorAction",
|
|
604
636
|
"categoryDesc": "_367UGW_categoryDesc",
|
|
605
|
-
"secretsList": "_367UGW_secretsList",
|
|
606
|
-
"viewTab": "_367UGW_viewTab",
|
|
607
|
-
"progressPercent": "_367UGW_progressPercent",
|
|
608
|
-
"reportView": "_367UGW_reportView",
|
|
609
|
-
"conflictDetail": "_367UGW_conflictDetail",
|
|
610
|
-
"ghostButton": "_367UGW_ghostButton",
|
|
611
|
-
"checkboxRow": "_367UGW_checkboxRow",
|
|
612
|
-
"iconButton": "_367UGW_iconButton",
|
|
613
637
|
"primaryButton": "_367UGW_primaryButton",
|
|
638
|
+
"categoryName": "_367UGW_categoryName",
|
|
639
|
+
"reportView": "_367UGW_reportView",
|
|
640
|
+
"errorFooter": "_367UGW_errorFooter",
|
|
641
|
+
"optionsCard": "_367UGW_optionsCard",
|
|
614
642
|
"errorTitle": "_367UGW_errorTitle",
|
|
615
|
-
"conflictOptions": "_367UGW_conflictOptions",
|
|
616
|
-
"sectionHeader": "_367UGW_sectionHeader",
|
|
617
|
-
"progressTrack": "_367UGW_progressTrack",
|
|
618
|
-
"progressIndeterminate": "_367UGW_progressIndeterminate",
|
|
619
|
-
"formError": "_367UGW_formError",
|
|
620
|
-
"empty": "_367UGW_empty",
|
|
621
|
-
"spinner": "_367UGW_spinner",
|
|
622
|
-
"pathRow": "_367UGW_pathRow",
|
|
623
|
-
"pathIssueKind": "_367UGW_pathIssueKind",
|
|
624
|
-
"sectionSubtitle": "_367UGW_sectionSubtitle",
|
|
625
643
|
"badgeError": "_367UGW_badgeError",
|
|
626
|
-
"
|
|
627
|
-
"
|
|
628
|
-
"
|
|
629
|
-
"pathOld": "_367UGW_pathOld",
|
|
630
|
-
"field": "_367UGW_field",
|
|
631
|
-
"statRow": "_367UGW_statRow",
|
|
632
|
-
"banner": "_367UGW_banner",
|
|
633
|
-
"fieldLabel": "_367UGW_fieldLabel",
|
|
634
|
-
"modeTabs": "_367UGW_modeTabs",
|
|
635
|
-
"progressBar": "_367UGW_progressBar",
|
|
636
|
-
"errorActionLabel": "_367UGW_errorActionLabel",
|
|
637
|
-
"pathNew": "_367UGW_pathNew",
|
|
638
|
-
"spinnerLabel": "_367UGW_spinnerLabel",
|
|
639
|
-
"rollbackBox": "_367UGW_rollbackBox",
|
|
640
|
-
"reportText": "_367UGW_reportText",
|
|
644
|
+
"badge": "_367UGW_badge",
|
|
645
|
+
"errorReason": "_367UGW_errorReason",
|
|
646
|
+
"modeTab": "_367UGW_modeTab",
|
|
641
647
|
"viewBody": "_367UGW_viewBody",
|
|
642
|
-
"
|
|
643
|
-
"conflictList": "_367UGW_conflictList",
|
|
644
|
-
"badgeWarn": "_367UGW_badgeWarn",
|
|
645
|
-
"progressLabel": "_367UGW_progressLabel",
|
|
646
|
-
"secretFields": "_367UGW_secretFields",
|
|
647
|
-
"pathValue": "_367UGW_pathValue",
|
|
648
|
-
"badge": "_367UGW_badge"
|
|
648
|
+
"modeHint": "_367UGW_modeHint"
|
|
649
649
|
};
|
|
650
650
|
//#endregion
|
|
651
651
|
//#region src/client/common/ui.tsx
|
|
@@ -1651,23 +1651,19 @@ function nextFlowPhase(list, from) {
|
|
|
1651
1651
|
* 冲突决策列表(规范 §11,绑 src/ui/conflict-view.ts 的 ConflictCollector)。
|
|
1652
1652
|
*
|
|
1653
1653
|
* 渲染 plan 中 kind === 'Conflict' 的项,用户逐项选择
|
|
1654
|
-
* Keep Current / Use Imported
|
|
1654
|
+
* Keep Current / Use Imported;决策实时写入 collector,
|
|
1655
1655
|
* 完成时父组件调用 collector.toResolutions() → wizard.setResolutions()。
|
|
1656
|
+
*
|
|
1657
|
+
* 注意:不提供 "Review(稍后决定)" 选项——Review 会被收集器计为
|
|
1658
|
+
* unresolved,导致「下一步」永远禁用(死路)。要么决策,要么不进入本步。
|
|
1656
1659
|
*/
|
|
1657
|
-
const RESOLUTION_OPTIONS = [
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
key: "import.conflicts.useImported"
|
|
1665
|
-
},
|
|
1666
|
-
{
|
|
1667
|
-
value: "review",
|
|
1668
|
-
key: "import.conflicts.review"
|
|
1669
|
-
}
|
|
1670
|
-
];
|
|
1660
|
+
const RESOLUTION_OPTIONS = [{
|
|
1661
|
+
value: "keepCurrent",
|
|
1662
|
+
key: "import.conflicts.keepCurrent"
|
|
1663
|
+
}, {
|
|
1664
|
+
value: "useImported",
|
|
1665
|
+
key: "import.conflicts.useImported"
|
|
1666
|
+
}];
|
|
1671
1667
|
/** 冲突项决策列表 */
|
|
1672
1668
|
function ConflictList({ collector, t, onChanged }) {
|
|
1673
1669
|
const [tick, setTick] = (0, react.useState)(0);
|