dsh-config-manager 0.1.78 → 0.1.80

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.
Files changed (302) hide show
  1. package/lib/adapters/credentials.d.ts +6 -2
  2. package/lib/adapters/credentials.js +19 -3
  3. package/lib/adapters/file-collection.js +2 -1
  4. package/lib/adapters/mcp.d.ts +48 -2
  5. package/lib/adapters/mcp.js +265 -3
  6. package/lib/adapters/messages.d.ts +3 -0
  7. package/lib/adapters/messages.js +7 -0
  8. package/lib/adapters/plugin-files.js +2 -1
  9. package/lib/adapters/plugins.js +105 -20
  10. package/lib/adapters/pnpm-workspace.d.ts +32 -0
  11. package/lib/adapters/pnpm-workspace.js +113 -2
  12. package/lib/adapters/prompts.d.ts +6 -2
  13. package/lib/adapters/prompts.js +17 -2
  14. package/lib/adapters/providers.d.ts +19 -2
  15. package/lib/adapters/providers.js +59 -3
  16. package/lib/adapters/settings.d.ts +6 -2
  17. package/lib/adapters/settings.js +13 -2
  18. package/lib/adapters/skills.d.ts +25 -1
  19. package/lib/adapters/skills.js +60 -0
  20. package/lib/adapters/ui.d.ts +6 -2
  21. package/lib/adapters/ui.js +13 -2
  22. package/lib/adapters/units.d.ts +18 -0
  23. package/lib/adapters/units.js +39 -0
  24. package/lib/adapters/workspaces.js +2 -1
  25. package/lib/client.d.ts +401 -112
  26. package/lib/client.js +2899 -1525
  27. package/lib/core/backup.js +20 -0
  28. package/lib/core/mcp-connector-store.d.ts +159 -0
  29. package/lib/core/mcp-connector-store.js +445 -0
  30. package/lib/core/messages-core.d.ts +2 -0
  31. package/lib/core/messages-core.js +4 -0
  32. package/lib/core/messages.d.ts +20 -0
  33. package/lib/core/messages.js +44 -0
  34. package/lib/core/phase3-host.js +18 -1
  35. package/lib/core/plugin-cli.d.ts +22 -2
  36. package/lib/core/plugin-cli.js +22 -3
  37. package/lib/core/recovery-orchestrator.d.ts +3 -1
  38. package/lib/core/recovery-orchestrator.js +75 -16
  39. package/lib/core/rollback-activity.d.ts +89 -0
  40. package/lib/core/rollback-activity.js +350 -0
  41. package/lib/core/rollback-ledger.d.ts +0 -9
  42. package/lib/core/rollback-ledger.js +37 -0
  43. package/lib/core/rollback-merge.d.ts +22 -2
  44. package/lib/core/rollback-merge.js +63 -13
  45. package/lib/core/rollback-point.d.ts +93 -0
  46. package/lib/core/rollback-point.js +420 -101
  47. package/lib/core/rollback-undo-journal.d.ts +123 -0
  48. package/lib/core/rollback-undo-journal.js +517 -0
  49. package/lib/core/self-update.js +2 -4
  50. package/lib/core/text-fidelity.d.ts +89 -0
  51. package/lib/core/text-fidelity.js +176 -0
  52. package/lib/core/types.d.ts +12 -3
  53. package/lib/core/update-check.js +2 -4
  54. package/lib/core/validator.d.ts +9 -0
  55. package/lib/core/validator.js +12 -0
  56. package/lib/foreign/bundle.js +42 -3
  57. package/lib/foreign/claude-code.js +358 -26
  58. package/lib/foreign/claude-sessions.d.ts +51 -8
  59. package/lib/foreign/claude-sessions.js +111 -13
  60. package/lib/foreign/read-claude-code.d.ts +33 -4
  61. package/lib/foreign/read-claude-code.js +446 -65
  62. package/lib/foreign/read-claude-plugins.d.ts +36 -0
  63. package/lib/foreign/read-claude-plugins.js +403 -0
  64. package/lib/foreign/registry.js +25 -2
  65. package/lib/foreign/truth-table.js +6 -4
  66. package/lib/foreign/types.d.ts +170 -2
  67. package/lib/index.d.ts +14 -5
  68. package/lib/index.js +60 -16
  69. package/lib/market/git-file-writer.js +7 -1
  70. package/lib/profiles/dsh-profile-launcher.d.ts +20 -0
  71. package/lib/profiles/dsh-profile-launcher.js +58 -1
  72. package/lib/profiles/dsh-profile-shared.d.ts +8 -2
  73. package/lib/profiles/dsh-profile-shared.js +8 -2
  74. package/lib/routes/foreign.js +8 -1
  75. package/lib/routes/index.d.ts +1 -1
  76. package/lib/routes/kit.d.ts +2 -2
  77. package/lib/routes/sync.js +173 -9
  78. package/lib/schema/manifest.d.ts +6 -1
  79. package/lib/schema/manifest.js +55 -0
  80. package/lib/schema/types.d.ts +47 -2
  81. package/lib/sync/ancestor.d.ts +22 -0
  82. package/lib/sync/ancestor.js +66 -2
  83. package/lib/sync/autosync-config.d.ts +73 -0
  84. package/lib/sync/autosync-config.js +89 -0
  85. package/lib/sync/autosync-scheduler.d.ts +80 -6
  86. package/lib/sync/autosync-scheduler.js +263 -40
  87. package/lib/sync/gist/gist-transport.d.ts +18 -1
  88. package/lib/sync/gist/gist-transport.js +42 -3
  89. package/lib/sync/gist/messages.d.ts +2 -0
  90. package/lib/sync/gist/messages.js +5 -0
  91. package/lib/sync/git/git-transport.d.ts +42 -3
  92. package/lib/sync/git/git-transport.js +146 -3
  93. package/lib/sync/merge.d.ts +47 -14
  94. package/lib/sync/merge.js +242 -222
  95. package/lib/sync/messages.d.ts +8 -0
  96. package/lib/sync/messages.js +19 -0
  97. package/lib/sync/risk.d.ts +19 -2
  98. package/lib/sync/risk.js +10 -3
  99. package/lib/sync/s3/messages.d.ts +6 -0
  100. package/lib/sync/s3/messages.js +13 -0
  101. package/lib/sync/s3/s3-transport.d.ts +9 -1
  102. package/lib/sync/s3/s3-transport.js +78 -6
  103. package/lib/sync/s3/sigv4.js +11 -2
  104. package/lib/sync/sync-engine.d.ts +212 -8
  105. package/lib/sync/sync-engine.js +514 -58
  106. package/lib/sync/sync-history.d.ts +11 -0
  107. package/lib/sync/sync-history.js +20 -0
  108. package/lib/sync/sync-state.d.ts +43 -0
  109. package/lib/sync/sync-state.js +44 -0
  110. package/lib/sync/sync-watcher.d.ts +76 -0
  111. package/lib/sync/sync-watcher.js +202 -0
  112. package/lib/sync/text-merge.d.ts +85 -0
  113. package/lib/sync/text-merge.js +513 -0
  114. package/lib/sync/transport.d.ts +48 -0
  115. package/lib/sync/transport.js +12 -0
  116. package/lib/sync/watch-scope.d.ts +38 -0
  117. package/lib/sync/watch-scope.js +95 -0
  118. package/lib/sync/webdav/webdav-transport.d.ts +16 -2
  119. package/lib/sync/webdav/webdav-transport.js +128 -11
  120. package/lib/ui/foreign-view.js +10 -0
  121. package/lib/ui/i18n.d.ts +9 -0
  122. package/lib/ui/i18n.js +22 -0
  123. package/lib/ui/rollback-view.d.ts +12 -0
  124. package/lib/ui/rollback-view.js +2 -0
  125. package/lib/ui/sync-settings-view.d.ts +47 -0
  126. package/lib/ui/sync-settings-view.js +24 -0
  127. package/lib/ui/types.d.ts +21 -0
  128. package/lib/utils/env-lock.d.ts +1 -0
  129. package/lib/utils/env-lock.js +7 -4
  130. package/package.json +6 -6
  131. package/src/adapters/credentials.ts +22 -4
  132. package/src/adapters/file-collection.ts +2 -1
  133. package/src/adapters/mcp.test.ts +235 -1
  134. package/src/adapters/mcp.ts +276 -5
  135. package/src/adapters/messages.ts +7 -0
  136. package/src/adapters/plugin-files.ts +2 -1
  137. package/src/adapters/plugins.test.ts +176 -2
  138. package/src/adapters/plugins.ts +107 -21
  139. package/src/adapters/pnpm-workspace.test.ts +89 -1
  140. package/src/adapters/pnpm-workspace.ts +127 -2
  141. package/src/adapters/prompts.ts +20 -3
  142. package/src/adapters/providers.ts +62 -4
  143. package/src/adapters/settings.ts +16 -3
  144. package/src/adapters/skills.test.ts +141 -0
  145. package/src/adapters/skills.ts +58 -2
  146. package/src/adapters/ui.ts +16 -3
  147. package/src/adapters/units-entries.test.ts +190 -0
  148. package/src/adapters/units.ts +50 -0
  149. package/src/adapters/workspaces.ts +2 -1
  150. package/src/client/about/PluginUpdateDialog.tsx +4 -2
  151. package/src/client/about/ReleaseNotesDialog.tsx +4 -2
  152. package/src/client/chat/RollbackReviewDialog.tsx +3 -2
  153. package/src/client/common/Skeleton.tsx +32 -0
  154. package/src/client/common/api-base.test.ts +36 -0
  155. package/src/client/common/http.test.ts +12 -1
  156. package/src/client/common/http.ts +8 -2
  157. package/src/client/common/routes.ts +46 -3
  158. package/src/client/config-manager.module.css +321 -11
  159. package/src/client/home/HomePanel.tsx +14 -6
  160. package/src/client/import/ForeignImportView.tsx +3 -1
  161. package/src/client/import/import-wizard-steps.tsx +2 -1
  162. package/src/client/library/ArtifactRow.tsx +12 -2
  163. package/src/client/library/LibraryActions.tsx +6 -3
  164. package/src/client/library/LibraryPanel.tsx +21 -3
  165. package/src/client/library/RestorePlanView.tsx +4 -2
  166. package/src/client/locales.ts +3 -0
  167. package/src/client/market/market-api.test.ts +3 -2
  168. package/src/client/recovery/RecoveryPanel.tsx +54 -7
  169. package/src/client/recovery/RollbackCard.tsx +7 -2
  170. package/src/client/recovery/RollbackDiffPane.tsx +3 -2
  171. package/src/client/recovery/recovery-locales.ts +20 -2
  172. package/src/client/recovery/recovery-view.test.ts +39 -1
  173. package/src/client/recovery/recovery-view.ts +23 -1
  174. package/src/client/run-store.test.ts +1 -1
  175. package/src/client/run-store.ts +4 -0
  176. package/src/client/sync/AutosyncCard.tsx +49 -6
  177. package/src/client/sync/MergeModal.tsx +220 -0
  178. package/src/client/sync/MergePreviewView.tsx +306 -0
  179. package/src/client/sync/SyncActivityBar.tsx +31 -0
  180. package/src/client/sync/SyncConfirmView.tsx +2 -1
  181. package/src/client/sync/SyncPanel.tsx +130 -87
  182. package/src/client/sync/SyncProbeRow.tsx +162 -0
  183. package/src/client/sync/SyncSettingsView.test.ts +27 -2
  184. package/src/client/sync/WorkDirCard.tsx +44 -6
  185. package/src/client/sync/history-model.ts +4 -1
  186. package/src/client/sync/merge-view.test.ts +248 -0
  187. package/src/client/sync/merge-view.ts +398 -0
  188. package/src/client/sync/probe-view.test.ts +90 -0
  189. package/src/client/sync/probe-view.ts +63 -0
  190. package/src/client/sync/remote-device-view.test.ts +35 -0
  191. package/src/client/sync/remote-device-view.ts +25 -0
  192. package/src/client/sync/sync-api.test.ts +5 -3
  193. package/src/client/sync/sync-api.ts +212 -2
  194. package/src/client/sync/sync-entry.test.ts +78 -0
  195. package/src/client/sync/sync-entry.ts +53 -0
  196. package/src/client/sync/sync-locales.ts +234 -2
  197. package/src/client/sync/sync-view.test.ts +18 -1
  198. package/src/client/sync/sync-view.ts +20 -0
  199. package/src/core/backup.test.ts +41 -0
  200. package/src/core/backup.ts +20 -0
  201. package/src/core/mcp-connector-store.test.ts +265 -0
  202. package/src/core/mcp-connector-store.ts +516 -0
  203. package/src/core/messages-core.ts +4 -0
  204. package/src/core/messages.ts +46 -0
  205. package/src/core/phase3-host.ts +18 -1
  206. package/src/core/phase3-production-integration.test.ts +4 -0
  207. package/src/core/plugin-cli.test.ts +26 -0
  208. package/src/core/plugin-cli.ts +30 -4
  209. package/src/core/recovery-orchestrator.test.ts +104 -5
  210. package/src/core/recovery-orchestrator.ts +74 -17
  211. package/src/core/rollback-activity.test.ts +311 -0
  212. package/src/core/rollback-activity.ts +367 -0
  213. package/src/core/rollback-cross-session.test.ts +694 -0
  214. package/src/core/rollback-interrupted.test.ts +137 -0
  215. package/src/core/rollback-ledger.ts +32 -0
  216. package/src/core/rollback-merge.test.ts +130 -0
  217. package/src/core/rollback-merge.ts +78 -14
  218. package/src/core/rollback-point.ts +468 -91
  219. package/src/core/rollback-undo-journal.test.ts +508 -0
  220. package/src/core/rollback-undo-journal.ts +571 -0
  221. package/src/core/self-update.ts +2 -5
  222. package/src/core/text-fidelity.test.ts +189 -0
  223. package/src/core/text-fidelity.ts +197 -0
  224. package/src/core/types.ts +11 -3
  225. package/src/core/update-check.ts +2 -5
  226. package/src/core/validator.ts +14 -0
  227. package/src/foreign/bundle-origin.test.ts +265 -0
  228. package/src/foreign/bundle.ts +45 -5
  229. package/src/foreign/claude-code.test.ts +268 -0
  230. package/src/foreign/claude-code.ts +406 -25
  231. package/src/foreign/claude-plugins.test.ts +234 -0
  232. package/src/foreign/claude-sessions.test.ts +141 -0
  233. package/src/foreign/claude-sessions.ts +179 -23
  234. package/src/foreign/file-budget.test.ts +4 -1
  235. package/src/foreign/read-claude-code.test.ts +320 -0
  236. package/src/foreign/read-claude-code.ts +490 -71
  237. package/src/foreign/read-claude-plugins.ts +465 -0
  238. package/src/foreign/registry.ts +25 -2
  239. package/src/foreign/session-ir.test.ts +65 -0
  240. package/src/foreign/truth-table.test.ts +81 -0
  241. package/src/foreign/truth-table.ts +6 -3
  242. package/src/foreign/types.ts +162 -2
  243. package/src/index.facade.test.ts +26 -4
  244. package/src/index.ts +76 -19
  245. package/src/market/git-file-writer.test.ts +4 -0
  246. package/src/market/git-file-writer.ts +7 -1
  247. package/src/profiles/dsh-profile-launcher.test.ts +68 -3
  248. package/src/profiles/dsh-profile-launcher.ts +56 -1
  249. package/src/profiles/dsh-profile-shared.ts +8 -2
  250. package/src/routes/foreign.ts +8 -1
  251. package/src/routes/index.ts +1 -1
  252. package/src/routes/kit.ts +2 -2
  253. package/src/routes/sync.ts +176 -9
  254. package/src/schema/manifest-schema.test.ts +87 -2
  255. package/src/schema/manifest.ts +57 -1
  256. package/src/schema/types.ts +45 -2
  257. package/src/sync/ancestor.ts +76 -2
  258. package/src/sync/autosync-config.test.ts +73 -1
  259. package/src/sync/autosync-config.ts +124 -0
  260. package/src/sync/autosync-risk-tier.test.ts +38 -2
  261. package/src/sync/autosync-scheduler.test.ts +264 -12
  262. package/src/sync/autosync-scheduler.ts +296 -44
  263. package/src/sync/gist/gist-conditional-write.test.ts +203 -0
  264. package/src/sync/gist/gist-transport.ts +53 -5
  265. package/src/sync/gist/messages.ts +5 -0
  266. package/src/sync/git/git-probe.test.ts +80 -0
  267. package/src/sync/git/git-transport.test.ts +185 -0
  268. package/src/sync/git/git-transport.ts +178 -5
  269. package/src/sync/merge.test.ts +188 -55
  270. package/src/sync/merge.ts +282 -224
  271. package/src/sync/messages.ts +19 -0
  272. package/src/sync/risk.ts +29 -5
  273. package/src/sync/s3/messages.ts +13 -0
  274. package/src/sync/s3/s3-conditional-write.test.ts +330 -0
  275. package/src/sync/s3/s3-transport.test.ts +2 -1
  276. package/src/sync/s3/s3-transport.ts +87 -9
  277. package/src/sync/s3/sigv4.test.ts +4 -1
  278. package/src/sync/s3/sigv4.ts +11 -2
  279. package/src/sync/sync-device-identity.test.ts +267 -0
  280. package/src/sync/sync-engine.test.ts +410 -19
  281. package/src/sync/sync-engine.ts +602 -57
  282. package/src/sync/sync-history.test.ts +16 -1
  283. package/src/sync/sync-history.ts +26 -0
  284. package/src/sync/sync-state.test.ts +64 -0
  285. package/src/sync/sync-state.ts +79 -0
  286. package/src/sync/sync-watcher.test.ts +197 -0
  287. package/src/sync/sync-watcher.ts +246 -0
  288. package/src/sync/text-merge.test.ts +358 -0
  289. package/src/sync/text-merge.ts +554 -0
  290. package/src/sync/transport.ts +57 -0
  291. package/src/sync/watch-scope.test.ts +122 -0
  292. package/src/sync/watch-scope.ts +120 -0
  293. package/src/sync/webdav/webdav-conditional-write.test.ts +360 -0
  294. package/src/sync/webdav/webdav-transport.ts +137 -14
  295. package/src/ui/foreign-view.test.ts +34 -0
  296. package/src/ui/foreign-view.ts +10 -0
  297. package/src/ui/i18n.ts +22 -0
  298. package/src/ui/rollback-view.ts +14 -0
  299. package/src/ui/sync-settings-view.test.ts +28 -1
  300. package/src/ui/sync-settings-view.ts +43 -0
  301. package/src/ui/types.ts +22 -0
  302. package/src/utils/env-lock.ts +8 -5
@@ -1,8 +1,21 @@
1
1
  import { FileCollectionAdapter } from './file-collection.ts';
2
- import type { HostContext, SkillDefinitionView } from '../core/types.ts';
2
+ import type { HostContext, ImportContext, PlanItem, SkillDefinitionView } from '../core/types.ts';
3
+ import type { FilesSection } from '../schema/types.ts';
3
4
  import type { RecursiveListing } from '../utils/recursive-walk.ts';
4
5
  /** 技能服务技能的虚拟路径(相对 baseDir):`<name>/SKILL.md`。 */
5
6
  export declare function skillServiceRel(name: string): string;
7
+ /**
8
+ * 该来源的技能能否进本分区备份(issue #102)。
9
+ *
10
+ * `bundled` = 插件包 / DSH 内置目录里随插件发行的技能(宿主的 `SkillSummaryView.source`)。
11
+ * 技能服务端口只暴露 **SKILL.md 文本**(`ctx.skills.get()` 返回 name/description/content),
12
+ * 技能的 `scripts/`、模板、资源文件一律拿不到 —— 备份出来必然是**残缺影子**;导入后它还会以
13
+ * 同名同 rank 落在 `$DSH_HOME/skills`,跟插件自己的版本争谁生效,且不随插件升级更新。
14
+ * 正确姿势是「装/升级对应的插件」,不是搬 SKILL.md。
15
+ *
16
+ * `source === undefined`(旧宿主不报来源)必须当**可迁移**:否则旧宿主上一个技能都备份不到。
17
+ */
18
+ export declare function isMigratableSkillSource(source?: string): boolean;
6
19
  /**
7
20
  * 由技能定义重建 `SKILL.md` 文本。
8
21
  *
@@ -42,4 +55,15 @@ export declare class SkillsAdapter extends FileCollectionAdapter {
42
55
  sizeBytes: number;
43
56
  contentHash: string;
44
57
  }>;
58
+ /**
59
+ * 导入侧:备份里的 bundled 技能一律跳过(issue #102)。
60
+ *
61
+ * 旧备份(本修复之前导出的)会把插件内置技能写成残缺影子,导入后落在 `$DSH_HOME/skills`,
62
+ * 与插件自己的同名技能争生效顺序。这里在**计划阶段**就把它们降级成 Skip(不写盘、不进
63
+ * 冲突收集器),并给出可理解的说明;不是静默丢弃。
64
+ *
65
+ * 目标机技能清单只查一次(`ctx.target.skills.list()`)—— 逐文件调 `get()` 会是 O(n²);
66
+ * 查不到(旧宿主 / 服务抛错)就**原样放行**,绝不因为判不出而少导入用户真正的技能。
67
+ */
68
+ analyzeImport(data: FilesSection, ctx: ImportContext): Promise<PlanItem[]>;
45
69
  }
@@ -31,6 +31,20 @@ import { sectionMeta } from '../schema/section-registry.js';
31
31
  export function skillServiceRel(name) {
32
32
  return normalizePath(path.join(name, 'SKILL.md'));
33
33
  }
34
+ /**
35
+ * 该来源的技能能否进本分区备份(issue #102)。
36
+ *
37
+ * `bundled` = 插件包 / DSH 内置目录里随插件发行的技能(宿主的 `SkillSummaryView.source`)。
38
+ * 技能服务端口只暴露 **SKILL.md 文本**(`ctx.skills.get()` 返回 name/description/content),
39
+ * 技能的 `scripts/`、模板、资源文件一律拿不到 —— 备份出来必然是**残缺影子**;导入后它还会以
40
+ * 同名同 rank 落在 `$DSH_HOME/skills`,跟插件自己的版本争谁生效,且不随插件升级更新。
41
+ * 正确姿势是「装/升级对应的插件」,不是搬 SKILL.md。
42
+ *
43
+ * `source === undefined`(旧宿主不报来源)必须当**可迁移**:否则旧宿主上一个技能都备份不到。
44
+ */
45
+ export function isMigratableSkillSource(source) {
46
+ return source !== 'bundled';
47
+ }
34
48
  /**
35
49
  * YAML 标量编码(issue #71 真机验收发现的缺陷修复)。
36
50
  *
@@ -184,6 +198,9 @@ export class SkillsAdapter extends FileCollectionAdapter {
184
198
  // 名字要能当路径用:DSH 的 SKILL_NAME 是 [a-z0-9-],这里再做一道通用安全校验(拒 `..`/绝对路径)
185
199
  if (typeof summary.name !== 'string' || !isPathSafe(summary.name) || summary.name.includes('/'))
186
200
  continue;
201
+ // issue #102:bundled 技能不进备份(残缺影子,见 isMigratableSkillSource)
202
+ if (!isMigratableSkillSource(summary.source))
203
+ continue;
187
204
  const rel = skillServiceRel(summary.name);
188
205
  if (onDisk.has(rel))
189
206
  continue; // 文件系统优先
@@ -231,5 +248,48 @@ export class SkillsAdapter extends FileCollectionAdapter {
231
248
  }
232
249
  return { data, sizeBytes: data.byteLength, contentHash: sha256Hex(data) };
233
250
  }
251
+ /**
252
+ * 导入侧:备份里的 bundled 技能一律跳过(issue #102)。
253
+ *
254
+ * 旧备份(本修复之前导出的)会把插件内置技能写成残缺影子,导入后落在 `$DSH_HOME/skills`,
255
+ * 与插件自己的同名技能争生效顺序。这里在**计划阶段**就把它们降级成 Skip(不写盘、不进
256
+ * 冲突收集器),并给出可理解的说明;不是静默丢弃。
257
+ *
258
+ * 目标机技能清单只查一次(`ctx.target.skills.list()`)—— 逐文件调 `get()` 会是 O(n²);
259
+ * 查不到(旧宿主 / 服务抛错)就**原样放行**,绝不因为判不出而少导入用户真正的技能。
260
+ */
261
+ async analyzeImport(data, ctx) {
262
+ const items = await super.analyzeImport(data, ctx);
263
+ if (ctx.target.skills === undefined)
264
+ return items;
265
+ let bundled;
266
+ try {
267
+ const summaries = await ctx.target.skills.list();
268
+ bundled = new Set(summaries.filter((s) => !isMigratableSkillSource(s.source)).map((s) => s.name));
269
+ }
270
+ catch (err) {
271
+ ctx.log.warn(`技能服务列举失败(无法识别 bundled 技能,按旧行为导入): ${err instanceof Error ? err.message : String(err)}`);
272
+ return items;
273
+ }
274
+ if (bundled.size === 0)
275
+ return items;
276
+ return items.map((item) => {
277
+ if (item.kind === 'Error')
278
+ return item;
279
+ const ref = item.target?.ref;
280
+ if (ref === undefined)
281
+ return item;
282
+ const name = this.unitIdOf(ref);
283
+ if (!bundled.has(name))
284
+ return item;
285
+ return {
286
+ ...item,
287
+ kind: 'Skip',
288
+ severity: 'info',
289
+ target: undefined,
290
+ description: ctx.msg('adapter.skillBundledSkipped', { name }),
291
+ };
292
+ });
293
+ }
234
294
  }
235
295
  //# sourceMappingURL=skills.js.map
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import type { UiSection } from '../schema/types.ts';
7
7
  import type { MsgFunc } from '../core/messages.ts';
8
- import type { ApplyResult, ConfigAdapter, ExportOptions, ExportSection, HostContext, ImportContext, PlanItem, ValidationResult } from '../core/types.ts';
8
+ import type { ApplyResult, ConfigAdapter, ExportOptions, ExportSection, ExportUnit, HostContext, ImportContext, PlanItem, ValidationResult } from '../core/types.ts';
9
9
  import { type NamespaceProvider } from './settings.ts';
10
10
  /** UI 类 namespace 前缀名单(设计 §4.1;随新插件扩展,只影响「某一 namespace 归哪一边」,不影响数据完整性) */
11
11
  export declare const KNOWN_UI_NAMESPACE_PREFIXES: readonly string[];
@@ -20,7 +20,11 @@ export declare class UiAdapter implements ConfigAdapter<UiSection> {
20
20
  readonly portability: import("../schema/section-registry.ts").SectionPortability;
21
21
  private readonly namespaces;
22
22
  constructor(namespaces?: string[] | NamespaceProvider);
23
- export(ctx: HostContext, _options: ExportOptions): Promise<ExportSection<UiSection>>;
23
+ export(ctx: HostContext, options: ExportOptions): Promise<ExportSection<UiSection>>;
24
+ /** 单元 id:`ui:<namespace>` */
25
+ private unitId;
26
+ /** 条目级单元清单(零 I/O):一个 UI namespace = 一个单元 */
27
+ listUnits(section: ExportSection<UiSection>): ExportUnit[];
24
28
  analyzeImport(data: UiSection, ctx: ImportContext): Promise<PlanItem[]>;
25
29
  applyItem(item: PlanItem, ctx: ImportContext): Promise<ApplyResult>;
26
30
  validate(data: UiSection, msg?: MsgFunc): Promise<ValidationResult>;
@@ -3,6 +3,7 @@ import { engineMsg } from './messages.js';
3
3
  import { collectNamespaceRecords, planNamespaceItems, applyNamespaceItem, resolveNamespaces } from './settings.js';
4
4
  import { sectionMeta } from '../schema/section-registry.js';
5
5
  import { validateJsonSection } from './json-section.js';
6
+ import { pickRecord, recordUnits } from './units.js';
6
7
  /** UI 类 namespace 前缀名单(设计 §4.1;随新插件扩展,只影响「某一 namespace 归哪一边」,不影响数据完整性) */
7
8
  export const KNOWN_UI_NAMESPACE_PREFIXES = [
8
9
  'pet',
@@ -53,11 +54,13 @@ export class UiAdapter {
53
54
  constructor(namespaces = []) {
54
55
  this.namespaces = namespaces;
55
56
  }
56
- async export(ctx, _options) {
57
+ async export(ctx, options) {
57
58
  const warnings = [];
58
59
  const all = await resolveNamespaces(this.namespaces, ctx);
59
60
  const uiNames = all.filter((n) => isUiNamespace(n));
60
- const namespaces = await collectNamespaceRecords(ctx, uiNames, warnings);
61
+ const collected = await collectNamespaceRecords(ctx, uiNames, warnings);
62
+ // 条目级白名单:未勾选的 namespace 整条不带走;迁移说明(纯说明、不含值)与选择无关,始终保留
63
+ const namespaces = pickRecord(collected, options.includeItems?.[this.id], (ns) => this.unitId(ns));
61
64
  const notes = uiMigrationNotes(ctx.msg);
62
65
  return {
63
66
  sectionId: 'ui',
@@ -66,6 +69,14 @@ export class UiAdapter {
66
69
  warnings,
67
70
  };
68
71
  }
72
+ /** 单元 id:`ui:<namespace>` */
73
+ unitId(namespace) {
74
+ return this.id + ':' + namespace;
75
+ }
76
+ /** 条目级单元清单(零 I/O):一个 UI namespace = 一个单元 */
77
+ listUnits(section) {
78
+ return recordUnits(this.id, section.data.namespaces ?? {});
79
+ }
69
80
  async analyzeImport(data, ctx) {
70
81
  return planNamespaceItems(data.namespaces, 'ui', ctx);
71
82
  }
@@ -40,3 +40,21 @@ export declare function unitsFromEntries(sectionId: string, entries: readonly {
40
40
  relativePath: string;
41
41
  sizeBytes: number;
42
42
  }[], unitIdOf: (rel: string) => string): ExportUnit[];
43
+ /**
44
+ * JSON / 记录型分区的单元体积 = 该条目在包里的 UTF-8 字节数。
45
+ *
46
+ * 与文件类不同,这里不需要读盘:条目本身就是 export() 的产物,直接量它的序列化长度,
47
+ * 预览与导出因此天然同口径(同一个函数量同一个对象)。
48
+ */
49
+ export declare function entryByteSize(value: unknown): number;
50
+ /**
51
+ * 按单元白名单过滤条目(JSON / 记录型分区共用)。
52
+ *
53
+ * allow === undefined = 未指定 → 全量(旧调用方 / 旧备份零改动);空数组 = 一条都不留。
54
+ * 与 unitAllowed 同一判据,只是作用在整批条目上。
55
+ */
56
+ export declare function filterByUnits<T>(items: readonly T[], allow: readonly string[] | undefined, idOf: (item: T) => string): T[];
57
+ /** 记录型分区的单元清单:一个顶层键 = 一个单元(零 I/O;体积 = 条目序列化长度)。 */
58
+ export declare function recordUnits<V>(sectionId: string, record: Record<string, V>, detailOf?: (value: V, key: string) => string | undefined): ExportUnit[];
59
+ /** 记录型分区的白名单过滤(键 → 单元 id 由 idOf 决定,与 recordUnits 同一规则)。 */
60
+ export declare function pickRecord<V>(record: Record<string, V>, allow: readonly string[] | undefined, idOf: (key: string) => string): Record<string, V>;
@@ -43,4 +43,43 @@ export function unitsFromEntries(sectionId, entries, unitIdOf) {
43
43
  sizeBytes: agg.size,
44
44
  }));
45
45
  }
46
+ /**
47
+ * JSON / 记录型分区的单元体积 = 该条目在包里的 UTF-8 字节数。
48
+ *
49
+ * 与文件类不同,这里不需要读盘:条目本身就是 export() 的产物,直接量它的序列化长度,
50
+ * 预览与导出因此天然同口径(同一个函数量同一个对象)。
51
+ */
52
+ export function entryByteSize(value) {
53
+ return new TextEncoder().encode(JSON.stringify(value) ?? '').byteLength;
54
+ }
55
+ /**
56
+ * 按单元白名单过滤条目(JSON / 记录型分区共用)。
57
+ *
58
+ * allow === undefined = 未指定 → 全量(旧调用方 / 旧备份零改动);空数组 = 一条都不留。
59
+ * 与 unitAllowed 同一判据,只是作用在整批条目上。
60
+ */
61
+ export function filterByUnits(items, allow, idOf) {
62
+ if (allow === undefined)
63
+ return [...items];
64
+ return items.filter((item) => allow.includes(idOf(item)));
65
+ }
66
+ /** 记录型分区的单元清单:一个顶层键 = 一个单元(零 I/O;体积 = 条目序列化长度)。 */
67
+ export function recordUnits(sectionId, record, detailOf) {
68
+ return Object.entries(record).map(([key, value]) => {
69
+ const unit = { id: sectionId + ':' + key, label: key, sizeBytes: entryByteSize(value) };
70
+ const detail = detailOf?.(value, key);
71
+ if (detail !== undefined && detail !== '')
72
+ unit.detail = detail;
73
+ return unit;
74
+ });
75
+ }
76
+ /** 记录型分区的白名单过滤(键 → 单元 id 由 idOf 决定,与 recordUnits 同一规则)。 */
77
+ export function pickRecord(record, allow, idOf) {
78
+ const out = {};
79
+ for (const [key, value] of Object.entries(record)) {
80
+ if (unitAllowed(allow, idOf(key)))
81
+ out[key] = value;
82
+ }
83
+ return out;
84
+ }
46
85
  //# sourceMappingURL=units.js.map
@@ -94,7 +94,8 @@ export class WorkspacesAdapter {
94
94
  }
95
95
  /** 单元清单(零 I/O):一条工作区记录 = 一个单元;标题缺失时退回 id。 */
96
96
  listUnits(section) {
97
- return section.data.workspaces.map((rec) => ({
97
+ // workspaces 可能缺省(空分区 / 手写 section):按空表处理,不抛错 —— 选择器对任何分区都会调 listUnits
98
+ return (section.data.workspaces ?? []).map((rec) => ({
98
99
  id: `workspace:${rec.id}`,
99
100
  label: rec.title !== undefined && rec.title !== '' ? rec.title : rec.id,
100
101
  detail: rec.path,