dsh-plugin-pack 1.0.13 → 1.0.14

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 (2) hide show
  1. package/client.js +157 -70
  2. package/package.json +1 -1
package/client.js CHANGED
@@ -187,6 +187,9 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
187
187
  'jobs.failed': '失败',
188
188
  'jobs.clear': '清空已完成',
189
189
  'conflict.title': '这些插件已经装过了',
190
+ 'conflict.titleNew': '确认导入',
191
+ 'conflict.subtitleAll': '个插件待安装',
192
+ 'conflict.create': '新建',
190
193
  'conflict.subtitle': '个插件与已安装的重名,请选择如何处理:',
191
194
  'conflict.overwrite': '覆盖',
192
195
  'conflict.skip': '跳过',
@@ -380,6 +383,9 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
380
383
  'jobs.failed': 'Failed',
381
384
  'jobs.clear': 'Clear finished',
382
385
  'conflict.title': 'These plugins are already installed',
386
+ 'conflict.titleNew': 'Confirm import',
387
+ 'conflict.subtitleAll': 'plugins to install',
388
+ 'conflict.create': 'New',
383
389
  'conflict.subtitle': 'plugins already exist. Choose what to do:',
384
390
  'conflict.overwrite': 'Overwrite',
385
391
  'conflict.skip': 'Skip',
@@ -546,8 +552,9 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
546
552
 
547
553
  /* 安装偏好:由界面上的「安装后立即启用」勾选同步过来。
548
554
  * 放这里是因为 doImport 在接口层、拿不到组件 state;
549
- * 用一个普通对象透传,避免把选项硬编码进每个调用点。 */
550
- const installPrefs = { enable: true };
555
+ * 用一个普通对象透传,避免把选项硬编码进每个调用点。
556
+ * 默认 false:装完先不启用,由用户自己决定(更安全,也避免"装了没用的插件"). */
557
+ const installPrefs = { enable: false };
551
558
 
552
559
  const getStatus = () => api('/plugin-pack/status');
553
560
  const doExport = (body) => api('/plugin-pack/export', { method: 'POST', body: JSON.stringify(body) });
@@ -1553,7 +1560,7 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
1553
1560
  },
1554
1561
  h('input', {
1555
1562
  type: 'checkbox',
1556
- checked: enableOnInstall !== false,
1563
+ checked: Boolean(enableOnInstall),
1557
1564
  disabled: busy,
1558
1565
  onChange: (event) => onToggleEnable?.(event.target.checked),
1559
1566
  }),
@@ -1576,10 +1583,18 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
1576
1583
  }
1577
1584
 
1578
1585
  function ConflictDialog({ pending, onConfirm, onCancel, t }) {
1586
+ /**
1587
+ * 弹窗列的是包里的**所有**插件,不只是重名的。
1588
+ * - 重名的(exists=true)→ 可选「覆盖 / 跳过」
1589
+ * - 新的(exists=false) → 标「新建」,没有二选一
1590
+ * 这样用户在真正写盘之前,能看清这次到底要装什么。
1591
+ */
1579
1592
  const conflicts = pending?.conflicts ?? [];
1593
+ const rows = pending?.rows ?? conflicts;
1594
+ const existing = rows.filter((item) => item.exists);
1580
1595
  /** 初始全部选「覆盖」——多数人是想升级到新版本。 */
1581
1596
  const [decisions, setDecisions] = useState(() =>
1582
- Object.fromEntries(conflicts.map((item) => [item.name, 'overwrite'])),
1597
+ Object.fromEntries(existing.map((item) => [item.name, 'overwrite'])),
1583
1598
  );
1584
1599
 
1585
1600
  // 弹窗打开时挂 Esc
@@ -1593,9 +1608,10 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
1593
1608
 
1594
1609
  if (!pending) return null;
1595
1610
 
1596
- const setAll = (value) => setDecisions(Object.fromEntries(conflicts.map((item) => [item.name, value])));
1611
+ const setAll = (value) => setDecisions(Object.fromEntries(existing.map((item) => [item.name, value])));
1597
1612
  const overwriteCount = Object.values(decisions).filter((v) => v === 'overwrite').length;
1598
1613
  const skipCount = Object.values(decisions).filter((v) => v === 'skip').length;
1614
+ const createCount = rows.length - existing.length;
1599
1615
 
1600
1616
  return h(
1601
1617
  'div',
@@ -1632,30 +1648,38 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
1632
1648
  h(
1633
1649
  'div',
1634
1650
  { style: { padding: '12px 16px', borderBottom: '.5px solid var(--dsw-alias-border-l1,#eee)' } },
1635
- h('b', { style: { fontSize: 14, fontWeight: 600, display: 'block', marginBottom: 4 } }, t('conflict.title')),
1636
1651
  h(
1637
- 'span',
1638
- { className: 'pp-hint' },
1639
- `${conflicts.length} ${t('conflict.subtitle')}`,
1652
+ 'b',
1653
+ { style: { fontSize: 14, fontWeight: 600, display: 'block', marginBottom: 4 } },
1654
+ existing.length ? t('conflict.title') : t('conflict.titleNew'),
1640
1655
  ),
1641
- ),
1642
- // 一键按钮
1643
- h(
1644
- 'div',
1645
- { className: 'pp-bar', style: { padding: '10px 16px 0', marginBottom: 0 } },
1646
- h('button', { className: 'pp-btn sm', onClick: () => setAll('overwrite') }, t('conflict.allOverwrite')),
1647
- h('button', { className: 'pp-btn sm', onClick: () => setAll('skip') }, t('conflict.allSkip')),
1648
1656
  h(
1649
1657
  'span',
1650
- { className: 'pp-hint', style: { marginLeft: 'auto' } },
1651
- `${t('conflict.overwrite')} ${overwriteCount} · ${t('conflict.skip')} ${skipCount}`,
1658
+ { className: 'pp-hint' },
1659
+ existing.length
1660
+ ? `${rows.length} ${t('conflict.subtitleAll')} · ${existing.length} ${t('conflict.subtitle')}`
1661
+ : `${rows.length} ${t('conflict.subtitleAll')}`,
1652
1662
  ),
1653
1663
  ),
1654
- // 列表
1664
+ // 一键按钮(只有存在重名时才有意义)
1665
+ existing.length
1666
+ ? h(
1667
+ 'div',
1668
+ { className: 'pp-bar', style: { padding: '10px 16px 0', marginBottom: 0 } },
1669
+ h('button', { className: 'pp-btn sm', onClick: () => setAll('overwrite') }, t('conflict.allOverwrite')),
1670
+ h('button', { className: 'pp-btn sm', onClick: () => setAll('skip') }, t('conflict.allSkip')),
1671
+ h(
1672
+ 'span',
1673
+ { className: 'pp-hint', style: { marginLeft: 'auto' } },
1674
+ `${t('conflict.overwrite')} ${overwriteCount} · ${t('conflict.skip')} ${skipCount}`,
1675
+ ),
1676
+ )
1677
+ : null,
1678
+ // 列表:全部插件
1655
1679
  h(
1656
1680
  'div',
1657
1681
  { style: { flex: 1, minHeight: 120, overflow: 'auto', padding: '8px 16px' } },
1658
- conflicts.map((item) =>
1682
+ rows.map((item) =>
1659
1683
  h(
1660
1684
  'div',
1661
1685
  {
@@ -1670,34 +1694,49 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
1670
1694
  'div',
1671
1695
  { className: 'pp-name' },
1672
1696
  item.name,
1673
- item.installedVersion
1697
+ item.exists && item.installedVersion
1674
1698
  ? h('span', { className: 'pp-ver' }, `${item.installedVersion} → ${item.version}`)
1675
1699
  : h('span', { className: 'pp-ver' }, item.version),
1676
- item.sameVersion ? h('span', { className: 'pp-ver' }, t('conflict.sameVersion')) : null,
1677
- ),
1678
- h('div', { className: 'pp-meta pp-mono', style: { fontSize: 11 } }, item.dest),
1679
- ),
1680
- // 每个插件单独选
1681
- h(
1682
- 'div',
1683
- { style: { display: 'flex', gap: 4, flex: 'none' } },
1684
- h(
1685
- 'button',
1686
- {
1687
- className: `pp-btn sm${decisions[item.name] === 'overwrite' ? ' primary' : ''}`,
1688
- onClick: () => setDecisions((prev) => ({ ...prev, [item.name]: 'overwrite' })),
1689
- },
1690
- t('conflict.overwrite'),
1691
- ),
1692
- h(
1693
- 'button',
1694
- {
1695
- className: `pp-btn sm${decisions[item.name] === 'skip' ? ' primary' : ''}`,
1696
- onClick: () => setDecisions((prev) => ({ ...prev, [item.name]: 'skip' })),
1697
- },
1698
- t('conflict.skip'),
1700
+ item.exists && item.sameVersion
1701
+ ? h('span', { className: 'pp-ver' }, t('conflict.sameVersion'))
1702
+ : null,
1699
1703
  ),
1704
+ item.dest ? h('div', { className: 'pp-meta pp-mono', style: { fontSize: 11 } }, item.dest) : null,
1700
1705
  ),
1706
+ // 重名的给二选一;新的只标「新建」
1707
+ item.exists
1708
+ ? h(
1709
+ 'div',
1710
+ { style: { display: 'flex', gap: 4, flex: 'none' } },
1711
+ h(
1712
+ 'button',
1713
+ {
1714
+ className: `pp-btn sm${decisions[item.name] === 'overwrite' ? ' primary' : ''}`,
1715
+ onClick: () => setDecisions((prev) => ({ ...prev, [item.name]: 'overwrite' })),
1716
+ },
1717
+ t('conflict.overwrite'),
1718
+ ),
1719
+ h(
1720
+ 'button',
1721
+ {
1722
+ className: `pp-btn sm${decisions[item.name] === 'skip' ? ' primary' : ''}`,
1723
+ onClick: () => setDecisions((prev) => ({ ...prev, [item.name]: 'skip' })),
1724
+ },
1725
+ t('conflict.skip'),
1726
+ ),
1727
+ )
1728
+ : h(
1729
+ 'span',
1730
+ {
1731
+ className: 'pp-pill',
1732
+ style: {
1733
+ flex: 'none',
1734
+ background: 'color-mix(in srgb,var(--dsw-alias-state-success-primary,#16a34a) 14%,transparent)',
1735
+ color: 'var(--dsw-alias-state-success-primary,#15803d)',
1736
+ },
1737
+ },
1738
+ t('conflict.create'),
1739
+ ),
1701
1740
  ),
1702
1741
  ),
1703
1742
  ),
@@ -1710,9 +1749,16 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
1710
1749
  borderTop: '.5px solid var(--dsw-alias-border-l1,#eee)',
1711
1750
  display: 'flex',
1712
1751
  gap: 8,
1713
- justifyContent: 'flex-end',
1752
+ alignItems: 'center',
1714
1753
  },
1715
1754
  },
1755
+ h(
1756
+ 'span',
1757
+ { className: 'pp-hint', style: { flex: 1 } },
1758
+ existing.length
1759
+ ? `${t('conflict.overwrite')} ${overwriteCount} · ${t('conflict.skip')} ${skipCount} · ${t('conflict.create')} ${createCount}`
1760
+ : `${t('conflict.create')} ${createCount}`,
1761
+ ),
1716
1762
  h('button', { className: 'pp-btn', onClick: onCancel }, t('conflict.cancel')),
1717
1763
  h(
1718
1764
  'button',
@@ -1901,8 +1947,8 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
1901
1947
  const [netResult, setNetResult] = useState(null);
1902
1948
  /** 「添加整合包」弹窗是否打开。 */
1903
1949
  const [netOpen, setNetOpen] = useState(false);
1904
- /** 安装后是否立即启用(勾选框)。关掉 → 只装文件,不进 bundles。 */
1905
- const [enableOnInstall, setEnableOnInstall] = useState(true);
1950
+ /** 安装后是否立即启用(勾选框)。默认关:先装上,用户想用再启用。 */
1951
+ const [enableOnInstall, setEnableOnInstall] = useState(false);
1906
1952
  /** 刚装完的插件及其启用状态,用于装完后再切换。 */
1907
1953
  const [enablePrompt, setEnablePrompt] = useState(null);
1908
1954
  /** 后台任务列表:切走画面回来靠它恢复 */
@@ -2151,21 +2197,35 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
2151
2197
  return;
2152
2198
  }
2153
2199
 
2154
- if (conflicts.length) {
2155
- /* 先把冲突列表给出来,用户选完才上传 + 真导入。
2156
- * 这时还没上传,所以待决策任务在服务端也不存在 —— 全靠确认时再登记。 */
2157
- setPendingImport({
2158
- kind: 'bundle',
2159
- pendingFile: file, // 还没上传,先拿着 File 对象
2160
- file: null,
2161
- conflicts,
2162
- plugins: packPlugins,
2163
- quick: true,
2164
- });
2165
- setBusy(false);
2166
- setPhase('');
2167
- return;
2168
- }
2200
+ /* 不管有没有重名,都在写盘之前弹一次确认框,列出包里所有插件:
2201
+ * - 重名的 → 覆盖 / 跳过
2202
+ * - 新的 → 标「新建」
2203
+ * 这时文件还没上传,取消就什么都不发生。 */
2204
+ const rows = packPlugins.map((plugin) => {
2205
+ const hit = installed.get(plugin.name);
2206
+ return {
2207
+ name: plugin.name,
2208
+ version: plugin.version ?? null,
2209
+ installedVersion: hit?.version ?? null,
2210
+ dest: hit?.dir ?? null,
2211
+ bytes: plugin.bytes ?? null,
2212
+ sameVersion: (hit?.version ?? null) === (plugin.version ?? null),
2213
+ exists: Boolean(hit),
2214
+ };
2215
+ });
2216
+
2217
+ setPendingImport({
2218
+ kind: 'bundle',
2219
+ pendingFile: file, // 还没上传,先拿着 File 对象
2220
+ file: null,
2221
+ conflicts: rows.filter((row) => row.exists),
2222
+ rows,
2223
+ plugins: packPlugins,
2224
+ quick: true,
2225
+ });
2226
+ setBusy(false);
2227
+ setPhase('');
2228
+ return;
2169
2229
  }
2170
2230
 
2171
2231
  // 第二步:确认无冲突(或拿不到快速清单)才上传
@@ -2173,18 +2233,32 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
2173
2233
  const uploaded = await uploadZip(file);
2174
2234
  setZipPath(uploaded.file);
2175
2235
 
2176
- // 先 dryRun 探一次:有重名冲突就弹窗让用户决定
2236
+ // 先 dryRun 探一次:拿到完整插件清单,写盘前弹确认
2177
2237
  setPhase(t('import.checking'));
2178
2238
  const preview = await doImport({ file: uploaded.file, dryRun: true });
2179
2239
  const conflicts = Array.isArray(preview?.conflicts) ? preview.conflicts : [];
2180
- if (conflicts.length) {
2181
- // 服务端在 dryRun 时已登记了"待决策"任务,带 jobId 回来
2240
+ const conflictByName = new Map(conflicts.map((item) => [item.name, item]));
2241
+ const previewRows = (preview?.plugins ?? []).map((plugin) => {
2242
+ const hit = conflictByName.get(plugin.name);
2243
+ return {
2244
+ name: plugin.name,
2245
+ version: plugin.version ?? null,
2246
+ installedVersion: hit?.installedVersion ?? null,
2247
+ dest: hit?.dest ?? null,
2248
+ sameVersion: Boolean(hit?.sameVersion),
2249
+ exists: Boolean(hit),
2250
+ };
2251
+ });
2252
+
2253
+ if (previewRows.length) {
2254
+ // 服务端在 dryRun 时已登记了"待决策"任务(仅当有重名),带 jobId 回来
2182
2255
  pendingJobId.current = preview?.jobId ?? null;
2183
2256
  setPendingImport({
2184
2257
  kind: 'bundle',
2185
2258
  jobId: preview?.jobId ?? null,
2186
2259
  file: uploaded.file,
2187
2260
  conflicts,
2261
+ rows: previewRows,
2188
2262
  plugins: preview.plugins ?? [],
2189
2263
  });
2190
2264
  setBusy(false);
@@ -2279,19 +2353,32 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
2279
2353
  return;
2280
2354
  }
2281
2355
 
2282
- // 下载好的包按普通导入走一遍:先 dryRun 看有没有重名冲突
2356
+ // 下载好的包:先 dryRun 拿完整清单,写盘前弹确认
2283
2357
  const preview = await doImport({ file: fetched.file, dryRun: true });
2284
- const conflicts = Array.isArray(preview?.conflicts) ? preview.conflicts : [];
2285
- if (conflicts.length) {
2358
+ const netConflicts = Array.isArray(preview?.conflicts) ? preview.conflicts : [];
2359
+ const netConflictByName = new Map(netConflicts.map((item) => [item.name, item]));
2360
+ const netRows = (preview?.plugins ?? []).map((plugin) => {
2361
+ const hit = netConflictByName.get(plugin.name);
2362
+ return {
2363
+ name: plugin.name,
2364
+ version: plugin.version ?? null,
2365
+ installedVersion: hit?.installedVersion ?? null,
2366
+ dest: hit?.dest ?? null,
2367
+ sameVersion: Boolean(hit?.sameVersion),
2368
+ exists: Boolean(hit),
2369
+ };
2370
+ });
2371
+ if (netRows.length) {
2286
2372
  pendingJobId.current = preview?.jobId ?? null;
2287
2373
  setPendingImport({
2288
2374
  kind: 'bundle',
2289
2375
  jobId: preview?.jobId ?? null,
2290
2376
  file: fetched.file,
2291
- conflicts,
2377
+ conflicts: netConflicts,
2378
+ rows: netRows,
2292
2379
  plugins: preview.plugins ?? [],
2293
2380
  });
2294
- // 交给冲突弹窗接管,先关掉来源弹窗
2381
+ // 交给确认弹窗接管,先关掉来源弹窗
2295
2382
  setNetOpen(false);
2296
2383
  return;
2297
2384
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-pack",
3
- "version": "1.0.13",
3
+ "version": "1.0.14",
4
4
  "description": "DeepSeek Harness 插件整合包:一键把当前 profile 的第三方插件连依赖和配置导出成 zip(内部每个插件是标准 npm tgz),换机/换 profile 拖进去就能还原。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",