@restregular/dsh-powerup 0.2.0 → 0.2.2

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 (3) hide show
  1. package/README.md +10 -2
  2. package/client.js +290 -128
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -66,8 +66,9 @@ unload the dialog mid-flow. Use **Add plugin** with the new package version.
66
66
  inside the plugin's brand SVG artwork.
67
67
  - **Two icons, two jobs.** `icon.svg` is the 256px brand tile shown by the
68
68
  Plugin Manager. The sidebar uses the same double-chevron mark as a 16-grid,
69
- `fill:none`, `stroke:currentColor` line drawing, so it inherits the sidebar's
70
- text color in either theme. The reference line artwork is
69
+ `fill:none`, `stroke:currentColor` line drawing, but without the tile frame:
70
+ the mark gets the full grid, so the chevrons and the amber baseline never
71
+ collide with a border. The reference line artwork is
71
72
  `design/sidebar-icon.svg`; the runtime copy lives in `client.js`.
72
73
  - **No imports from Harness Client packages.** The menu is plain React + CSS and
73
74
  observes the trajectory package's own `data-*` contracts. If those attributes
@@ -80,6 +81,13 @@ unload the dialog mid-flow. Use **Add plugin** with the new package version.
80
81
  installation use the same `remote.pluginManager` calls as **Add plugin**. Only
81
82
  the process restart needs Host code: a loopback-only
82
83
  `/dsh-powerup/api/restart` route.
84
+ - **The dialog mirrors the host modal.** The backdrop is
85
+ `--dsw-alias-bg-mask-1` with the shared mask blur, the surface is
86
+ `--dsw-alias-bg-layer-2` with `--dsw-radius-panel` and
87
+ `--dsw-elevation-prominent`, and the primary button uses
88
+ `--dsw-alias-button-primary-fill` / `-hover`, so the dialog follows both
89
+ themes instead of inventing its own palette. The registry picker and version
90
+ list are custom controls built from `--dsw-alias-*` tokens.
83
91
 
84
92
  ## Development
85
93
 
package/client.js CHANGED
@@ -44,7 +44,7 @@
44
44
 
45
45
  const NS = 'dsh-powerup';
46
46
  const SETTINGS_KEY = 'dsh-powerup:settings:v1';
47
- const VERSION = '0.2.0';
47
+ const VERSION = '0.2.2';
48
48
  const MENU_GAP = 8;
49
49
  const MENU_WIDTH = 248;
50
50
 
@@ -121,9 +121,13 @@
121
121
  'update.loadingVersions': '正在从安装源读取版本…',
122
122
  'update.loading': '正在读取插件信息…',
123
123
  'update.chooseVersion': '选择版本',
124
+ 'update.hideVersions': '收起列表',
125
+ 'update.versionsCount': '共 {count} 个版本',
124
126
  'update.versionsFailed': '读取版本失败:{message}',
125
127
  'update.versionsEmpty': '安装源没有返回可用版本',
126
128
  'update.latest': '最新',
129
+ 'update.currentTag': '当前',
130
+ 'update.currentAndLatest': '当前 · 最新',
127
131
  'update.retry': '重试',
128
132
  'update.registry': '安装源',
129
133
  'update.registryDefault': '默认安装源',
@@ -239,9 +243,13 @@
239
243
  'update.loadingVersions': 'Reading versions from the registry…',
240
244
  'update.loading': 'Reading the plugin…',
241
245
  'update.chooseVersion': 'Choose',
246
+ 'update.hideVersions': 'Hide list',
247
+ 'update.versionsCount': '{count} versions',
242
248
  'update.versionsFailed': 'Could not read versions: {message}',
243
249
  'update.versionsEmpty': 'The registry returned no versions',
244
250
  'update.latest': 'latest',
251
+ 'update.currentTag': 'Current',
252
+ 'update.currentAndLatest': 'Current · latest',
245
253
  'update.retry': 'Retry',
246
254
  'update.registry': 'Registry',
247
255
  'update.registryDefault': 'Default registry',
@@ -415,18 +423,19 @@
415
423
 
416
424
  function PowerUpLineIcon({ size = 16 }) {
417
425
  return h(Icon, { size },
418
- h('rect', {
419
- x: '1.65', y: '1.65', width: '12.7', height: '12.7', rx: '3.8',
420
- fill: 'none', stroke: 'currentColor', strokeWidth: '1.3',
426
+ h('path', {
427
+ d: 'M4.4 6.9 8 3.3l3.6 3.6',
428
+ fill: 'none', stroke: 'currentColor', strokeWidth: '1.4',
429
+ strokeLinecap: 'round', strokeLinejoin: 'round',
421
430
  }),
422
431
  h('path', {
423
- d: 'M4.2 5.8 8 2.7l3.8 3.1M4.2 10.9 8 7.8l3.8 3.1',
424
- fill: 'none', stroke: 'currentColor', strokeWidth: '1.3',
432
+ d: 'M4.4 11.7 8 8.1l3.6 3.6',
433
+ fill: 'none', stroke: 'currentColor', strokeWidth: '1.4',
425
434
  strokeLinecap: 'round', strokeLinejoin: 'round',
426
435
  }),
427
436
  h('path', {
428
- d: 'M5.8 13.1h4.4', fill: 'none', stroke: 'currentColor',
429
- strokeWidth: '1.3', strokeLinecap: 'round',
437
+ d: 'M6.3 13.9h3.4', fill: 'none', stroke: 'currentColor',
438
+ strokeWidth: '1.4', strokeLinecap: 'round',
430
439
  }),
431
440
  );
432
441
  }
@@ -578,6 +587,16 @@
578
587
  );
579
588
  }
580
589
 
590
+ function ChevronDownIcon({ size = 12 }) {
591
+ return h(Icon, { size },
592
+ h('path', {
593
+ d: 'm4 6 4 4 4-4',
594
+ fill: 'none', stroke: 'currentColor', strokeWidth: '1.4',
595
+ strokeLinecap: 'round', strokeLinejoin: 'round',
596
+ }),
597
+ );
598
+ }
599
+
581
600
  function WarnIcon({ size = 16 }) {
582
601
  return h(Icon, { size },
583
602
  h('path', {
@@ -648,56 +667,89 @@
648
667
  @keyframes dsh-powerup-toast-in{from{opacity:0;transform:translate(-50%,5px)}to{opacity:1;transform:translate(-50%,0)}}
649
668
  .dsh-powerup-update-button{flex:none;display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:0;border-radius:var(--dsw-radius-sm,6px);background:transparent;color:var(--dsw-alias-label-caption);cursor:pointer}
650
669
  .dsh-powerup-update-button:hover{background:var(--dsw-alias-interactive-bg-hover,var(--dsw-alias-bg-layer-2));color:var(--dsw-alias-label-secondary)}
651
- .dsh-powerup-update-button:focus-visible{outline:2px solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:1px}
652
- .dsh-powerup-update-mask{position:fixed;inset:0;z-index:1200;display:flex;align-items:center;justify-content:center;padding:24px;background:color-mix(in srgb,var(--dsw-alias-bg-base) 62%,transparent);pointer-events:auto}
653
- .dsh-powerup-update-dialog{display:flex;flex-direction:column;width:min(560px,100%);max-height:min(760px,calc(100vh - 48px));border:1px solid var(--dsw-alias-border-l2);border-radius:14px;background:var(--dsw-alias-bg-overlay,var(--dsw-alias-bg-layer-1));box-shadow:var(--dsw-elevation-prominent,0 24px 64px rgba(15,23,42,.28));color:var(--dsw-alias-label-primary);font-size:13px;line-height:1.5;overflow:hidden}
654
- .dsh-powerup-update-head{display:flex;align-items:center;gap:11px;padding:16px 18px 12px;border-bottom:1px solid var(--dsw-alias-border-l1)}
655
- .dsh-powerup-update-icon{flex:none;display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:9px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary)}
670
+ .dsh-powerup-update-mask{position:fixed;inset:0;z-index:1200;display:flex;align-items:center;justify-content:center;padding:24px;background:var(--dsw-alias-bg-mask-1);backdrop-filter:var(--dsw-mask-blur,blur(3px));pointer-events:auto;animation:dsh-powerup-update-fade .16s ease-out}
671
+ @keyframes dsh-powerup-update-fade{from{opacity:0}to{opacity:1}}
672
+ .dsh-powerup-update-dialog{box-sizing:border-box;position:relative;display:flex;flex-direction:column;width:min(560px,100%);max-height:min(760px,calc(100vh - 48px));max-height:min(760px,calc(100dvh - 48px));border-radius:var(--dsw-radius-panel,14px);background:var(--dsw-alias-bg-layer-2);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px;overflow:hidden;animation:dsh-powerup-update-rise .18s cubic-bezier(.2,.8,.3,1)}
673
+ @keyframes dsh-powerup-update-rise{from{opacity:0;transform:translateY(6px) scale(.995)}to{opacity:1;transform:none}}
674
+ @media (prefers-reduced-motion:reduce){.dsh-powerup-update-mask,.dsh-powerup-update-dialog{animation:none}}
675
+ .dsh-powerup-update-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:22px 14px 12px 24px}
656
676
  .dsh-powerup-update-heading{flex:1 1 auto;min-width:0}
657
- .dsh-powerup-update-heading h2{margin:0;font-size:15px;font-weight:650;line-height:1.3}
658
- .dsh-powerup-update-heading p{margin:2px 0 0;color:var(--dsw-alias-label-tertiary);font-size:11.5px;line-height:1.4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
659
- .dsh-powerup-update-close{flex:none;width:26px;height:26px;padding:0;border:0;border-radius:7px;background:transparent;color:var(--dsw-alias-label-tertiary);font-size:18px;line-height:1;cursor:pointer}
660
- .dsh-powerup-update-close:hover{background:var(--dsw-alias-interactive-bg-hover,var(--dsw-alias-bg-layer-2));color:var(--dsw-alias-label-primary)}
661
- .dsh-powerup-update-close:focus-visible{outline:2px solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:1px}
662
- .dsh-powerup-update-body{display:flex;flex-direction:column;gap:14px;min-height:0;padding:16px 18px;overflow-y:auto;--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2)}
663
- .dsh-powerup-update-name{overflow-wrap:anywhere;color:var(--dsw-alias-label-tertiary);font-family:var(--dsw-font-family-code,ui-monospace,SFMono-Regular,Consolas,monospace);font-size:11.5px;line-height:1.4}
664
- .dsh-powerup-update-meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px;color:var(--dsw-alias-label-secondary);font-size:12px}
665
- .dsh-powerup-update-chip{padding:0 7px;border-radius:999px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-tertiary);font-size:10.5px;line-height:18px}
666
- .dsh-powerup-update-label{color:var(--dsw-alias-label-tertiary);font-size:11px;font-weight:600;letter-spacing:.04em;text-transform:uppercase}
667
- .dsh-powerup-update-field{display:flex;flex-direction:column;gap:6px}
668
- .dsh-powerup-update-row{display:flex;gap:8px}
669
- .dsh-powerup-update-input{flex:1 1 auto;min-width:0;height:38px;padding:0 12px;border:.5px solid var(--dsw-alias-border-l4);border-radius:8px;background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;outline:none}
677
+ .dsh-powerup-update-heading h2{margin:0;font-size:16px;line-height:24px;font-weight:500;color:var(--dsw-alias-label-primary)}
678
+ .dsh-powerup-update-heading p{margin:2px 0 0;color:var(--dsw-alias-label-tertiary);font-family:var(--dsw-font-family-code,ui-monospace,SFMono-Regular,Consolas,monospace);font-size:11.5px;line-height:18px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
679
+ .dsh-powerup-update-close{flex:none;display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:0;border-radius:var(--dsw-radius-sm,6px);background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:18px;line-height:1;cursor:pointer}
680
+ .dsh-powerup-update-close:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
681
+ .dsh-powerup-update-body{display:flex;flex-direction:column;gap:20px;min-height:0;margin-top:8px;padding:0 24px 4px;overflow-y:auto;--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2)}
682
+ .dsh-powerup-update-field{display:flex;flex-direction:column;gap:8px;min-width:0}
683
+ .dsh-powerup-update-label{display:block;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px;font-weight:500}
684
+ .dsh-powerup-update-note{margin:0;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;overflow-wrap:anywhere}
685
+ .dsh-powerup-update-name{color:var(--dsw-alias-label-tertiary);font-family:var(--dsw-font-family-code,ui-monospace,SFMono-Regular,Consolas,monospace);font-size:11.5px;line-height:18px;overflow-wrap:anywhere}
686
+ .dsh-powerup-update-summary{display:flex;flex-direction:column;gap:2px;min-width:0}
687
+ .dsh-powerup-update-list-state{display:flex;flex-direction:column;gap:10px;padding:12px}
688
+ .dsh-powerup-update-now{display:flex;align-items:center;gap:10px;min-width:0}
689
+ .dsh-powerup-update-now .label{flex:none;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}
690
+ .dsh-powerup-update-now code{display:inline-flex;align-items:center;min-height:22px;padding:0 8px;border:.5px solid var(--dsw-alias-border-l1);border-radius:var(--dsw-radius-sm,6px);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family-code,ui-monospace,SFMono-Regular,Consolas,monospace);font-size:11.5px;line-height:20px;font-variant-numeric:tabular-nums}
691
+ .dsh-powerup-update-row{display:flex;align-items:stretch;gap:8px}
692
+ .dsh-powerup-update-input{flex:1 1 auto;min-width:0;height:38px;padding:0 12px;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md,8px);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;line-height:20px;outline:none;transition:border-color .14s ease,box-shadow .14s ease}
693
+ .dsh-powerup-update-input::placeholder{color:var(--dsw-alias-label-caption)}
670
694
  .dsh-powerup-update-input:focus{border-color:var(--dsw-alias-state-business-primary);box-shadow:inset 0 0 0 .5px var(--dsw-alias-state-business-primary)}
671
- .dsh-powerup-update-toggle{flex:none;height:38px;padding:0 12px;border:.5px solid var(--dsw-alias-border-l3);border-radius:8px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary);font:inherit;font-size:12.5px;cursor:pointer}
672
- .dsh-powerup-update-toggle:hover{background:var(--dsw-alias-interactive-bg-hover,var(--dsw-alias-bg-layer-3));color:var(--dsw-alias-label-primary)}
673
- .dsh-powerup-update-toggle:focus-visible{outline:2px solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:1px}
674
- .dsh-powerup-update-list{display:flex;flex-direction:column;max-height:220px;overflow-y:auto;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;background:var(--dsw-alias-bg-layer-1);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2)}
675
- .dsh-powerup-update-version{display:flex;align-items:center;gap:8px;width:100%;padding:7px 11px;border:0;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:12.5px;text-align:left;cursor:pointer}
676
- .dsh-powerup-update-version:hover{background:var(--dsw-alias-interactive-bg-hover,var(--dsw-alias-bg-layer-2))}
677
- .dsh-powerup-update-version[aria-selected=true]{background:var(--dsw-alias-bg-layer-2)}
678
- .dsh-powerup-update-version:focus-visible{outline:2px solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:-2px}
679
- .dsh-powerup-update-tag{margin-left:auto;padding:0 6px;border-radius:999px;background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-tertiary);font-size:10px;line-height:17px}
680
- .dsh-powerup-update-status{display:flex;align-items:center;gap:8px;color:var(--dsw-alias-label-secondary);font-size:12.5px}
681
- .dsh-powerup-update-spinner{flex:none;width:14px;height:14px;border:2px solid var(--dsw-alias-border-l3);border-top-color:var(--dsw-alias-brand-primary);border-radius:50%;animation:dsh-powerup-spin .8s linear infinite}
695
+ .dsh-powerup-update-toggle{flex:none;display:inline-flex;align-items:center;gap:6px;height:38px;padding:0 12px;border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md,8px);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary);font:inherit;font-size:12.5px;line-height:18px;cursor:pointer;transition:background .14s ease,border-color .14s ease,color .14s ease}
696
+ .dsh-powerup-update-toggle:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
697
+ .dsh-powerup-update-toggle[aria-expanded=true]{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary)}
698
+ .dsh-powerup-update-toggle .chevron{display:inline-flex;color:var(--dsw-alias-label-tertiary);transition:transform .16s ease}
699
+ .dsh-powerup-update-toggle[aria-expanded=true] .chevron{transform:rotate(180deg);color:var(--dsw-alias-label-secondary)}
700
+ .dsh-powerup-update-list{display:flex;flex-direction:column;max-height:240px;overflow-y:auto;border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-lg,10px);background:var(--dsw-alias-bg-layer-1);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2)}
701
+ .dsh-powerup-update-list-head{position:sticky;top:0;z-index:1;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:7px 12px;border-bottom:.5px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}
702
+ .dsh-powerup-update-version{display:flex;align-items:center;gap:8px;width:100%;min-height:34px;padding:0 12px;border:0;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:12.5px;line-height:18px;text-align:left;cursor:pointer;font-variant-numeric:tabular-nums}
703
+ .dsh-powerup-update-version>span:first-child{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
704
+ .dsh-powerup-update-version:hover{background:var(--dsw-alias-interactive-bg-hover)}
705
+ .dsh-powerup-update-version[aria-selected=true]{background:var(--dsw-alias-interactive-bg-active)}
706
+ .dsh-powerup-update-version[data-current]{box-shadow:inset 2px 0 0 var(--dsw-alias-state-business-primary)}
707
+ .dsh-powerup-update-trailing{display:inline-flex;flex:none;align-items:center;gap:8px;margin-left:auto;white-space:nowrap}
708
+ .dsh-powerup-update-tag{padding:0 6px;border:.5px solid var(--dsw-alias-border-l2);border-radius:999px;background:transparent;color:var(--dsw-alias-label-tertiary);font-size:10px;line-height:16px;white-space:nowrap}
709
+ .dsh-powerup-update-tag.is-current{border-color:color-mix(in srgb,var(--dsw-alias-state-business-primary) 38%,transparent);background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 8%,transparent);color:var(--dsw-alias-state-business-primary)}
710
+ .dsh-powerup-update-check{display:inline-flex;color:var(--dsw-alias-state-business-primary)}
711
+ .dsh-powerup-update-status{display:flex;align-items:center;gap:10px;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:20px}
712
+ .dsh-powerup-update-spinner{flex:none;width:14px;height:14px;border:2px solid color-mix(in srgb,var(--dsw-alias-state-business-primary) 24%,transparent);border-top-color:var(--dsw-alias-state-business-primary);border-radius:50%;animation:dsh-powerup-spin .8s linear infinite}
682
713
  @keyframes dsh-powerup-spin{to{transform:rotate(360deg)}}
683
714
  @media (prefers-reduced-motion:reduce){.dsh-powerup-update-spinner{animation:none}}
684
- .dsh-powerup-update-log{margin:0;max-height:140px;overflow:auto;padding:8px 10px;border-radius:8px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary);font-family:var(--dsw-font-family-code,ui-monospace,SFMono-Regular,Consolas,monospace);font-size:11px;line-height:1.5;white-space:pre-wrap;overflow-wrap:anywhere}
685
- .dsh-powerup-update-error{display:flex;align-items:flex-start;gap:8px;padding:9px 11px;border-radius:8px;background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 12%,transparent);color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:1.5}
686
- .dsh-powerup-update-error svg{flex:none;margin-top:1px}
687
- .dsh-powerup-update-error span{min-width:0;overflow-wrap:anywhere}
688
- .dsh-powerup-update-note{margin:0;color:var(--dsw-alias-label-tertiary);font-size:11.5px;line-height:1.55}
689
- .dsh-powerup-update-registry{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
690
- .dsh-powerup-update-select{height:30px;max-width:100%;padding:0 8px;border:.5px solid var(--dsw-alias-border-l3);border-radius:7px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;outline:none}
691
- .dsh-powerup-update-select:focus-visible{outline:2px solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:1px}
692
- .dsh-powerup-update-foot{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:12px 18px 16px;border-top:1px solid var(--dsw-alias-border-l1)}
693
- .dsh-powerup-update-primary{height:32px;padding:0 14px;border:0;border-radius:8px;background:var(--dsw-alias-brand-primary);color:var(--dsw-alias-label-primary-foreground,var(--dsw-alias-bg-layer-1));font:inherit;font-size:12.5px;font-weight:600;cursor:pointer}
694
- .dsh-powerup-update-primary:hover:not(:disabled){opacity:.9}
695
- .dsh-powerup-update-primary:disabled{opacity:.5;cursor:default}
696
- .dsh-powerup-update-primary:focus-visible{outline:2px solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:2px}
697
- .dsh-powerup-update-ghost{height:32px;padding:0 14px;border:1px solid var(--dsw-alias-border-l3);border-radius:8px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:12.5px;cursor:pointer}
698
- .dsh-powerup-update-ghost:hover{background:var(--dsw-alias-interactive-bg-hover,var(--dsw-alias-bg-layer-2))}
699
- .dsh-powerup-update-ghost:focus-visible{outline:2px solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:2px}
700
- @media (max-width:680px){.dsh-powerup-page{padding:20px 16px 42px}.dsh-powerup-actions{grid-template-columns:minmax(0,1fr)}.dsh-powerup-hero-art{width:54px;height:54px}.dsh-powerup-hero h1{font-size:19px}.dsh-powerup-card-head{flex-wrap:wrap}.dsh-powerup-switch{margin-left:auto}.dsh-powerup-update-mask{padding:12px}.dsh-powerup-update-dialog{max-height:calc(100vh - 24px)}}
715
+ .dsh-powerup-update-log{margin:0;max-height:160px;overflow:auto;padding:10px 12px;border:.5px solid var(--dsw-alias-border-l1);border-radius:var(--dsw-radius-md,8px);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);font-family:var(--dsw-font-family-code,ui-monospace,SFMono-Regular,Consolas,monospace);font-size:11px;line-height:17px;white-space:pre-wrap;overflow-wrap:anywhere}
716
+ .dsh-powerup-update-notice{display:flex;align-items:flex-start;gap:8px;padding:10px 12px;border:.5px solid transparent;border-radius:var(--dsw-radius-md,8px);font-size:12.5px;line-height:18px;color:var(--dsw-alias-label-primary)}
717
+ .dsh-powerup-update-notice svg{flex:none;margin-top:2px}
718
+ .dsh-powerup-update-notice span{min-width:0;overflow-wrap:anywhere}
719
+ .dsh-powerup-update-notice-copy{display:flex;flex-direction:column;gap:2px;min-width:0}
720
+ .dsh-powerup-update-notice-title{font-weight:500;color:var(--dsw-alias-label-primary);overflow-wrap:anywhere}
721
+ .dsh-powerup-update-notice.error{border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 30%,transparent);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 8%,transparent)}
722
+ .dsh-powerup-update-notice.error svg{color:var(--dsw-alias-state-error-primary)}
723
+ .dsh-powerup-update-notice.warn{border-color:color-mix(in srgb,var(--dsw-alias-state-warn-primary) 30%,transparent);background:var(--dsw-alias-state-warn-tertiary)}
724
+ .dsh-powerup-update-notice.warn svg{color:var(--dsw-alias-state-warn-primary)}
725
+ .dsh-powerup-update-notice.success{border-color:color-mix(in srgb,var(--dsw-alias-state-success-primary) 28%,transparent);background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 8%,transparent)}
726
+ .dsh-powerup-update-notice.success svg{color:var(--dsw-alias-state-success-primary)}
727
+ .dsh-powerup-update-registry{display:flex;flex-direction:column;gap:8px}
728
+ .dsh-powerup-update-select{position:relative}
729
+ .dsh-powerup-update-select-trigger{display:flex;align-items:center;gap:10px;width:100%;height:38px;padding:0 12px;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md,8px);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;line-height:20px;text-align:left;cursor:pointer;transition:border-color .14s ease,box-shadow .14s ease}
730
+ .dsh-powerup-update-select-trigger:hover{background:var(--dsw-alias-bg-layer-2)}
731
+ .dsh-powerup-update-select-trigger[aria-expanded=true]{border-color:var(--dsw-alias-state-business-primary);box-shadow:inset 0 0 0 .5px var(--dsw-alias-state-business-primary)}
732
+ .dsh-powerup-update-select-value{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
733
+ .dsh-powerup-update-select-host{flex:none;color:var(--dsw-alias-label-tertiary);font-size:11.5px}
734
+ .dsh-powerup-update-select-trigger .chevron{flex:none;display:inline-flex;color:var(--dsw-alias-label-tertiary);transition:transform .16s ease}
735
+ .dsh-powerup-update-select-trigger[aria-expanded=true] .chevron{transform:rotate(180deg)}
736
+ .dsh-powerup-update-select-menu{display:flex;flex-direction:column;padding:4px;border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-lg,10px);background:var(--dsw-alias-bg-layer-2);box-shadow:var(--dsw-elevation-prominent)}
737
+ .dsh-powerup-update-option{display:flex;align-items:flex-start;gap:10px;width:100%;padding:8px 10px;border:0;border-radius:var(--dsw-radius-md,8px);background:transparent;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer}
738
+ .dsh-powerup-update-option:hover{background:var(--dsw-alias-interactive-bg-hover)}
739
+ .dsh-powerup-update-option[aria-selected=true]{background:var(--dsw-alias-interactive-bg-active)}
740
+ .dsh-powerup-update-option-copy{display:flex;flex:1 1 auto;flex-direction:column;gap:1px;min-width:0}
741
+ .dsh-powerup-update-option-title{color:var(--dsw-alias-label-primary);font-size:12.5px;line-height:18px}
742
+ .dsh-powerup-update-option-host{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px;overflow-wrap:anywhere}
743
+ .dsh-powerup-update-option .dsh-powerup-update-check{flex:none;margin-top:2px}
744
+ .dsh-powerup-update-foot{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:16px 24px 22px;border-top:.5px solid var(--dsw-alias-border-l1)}
745
+ .dsh-powerup-update-primary{height:36px;padding:0 14px;border:0;border-radius:var(--dsw-radius-md,8px);background:var(--dsw-alias-button-primary-fill,var(--dsw-alias-brand-primary));color:var(--dsw-alias-label-primary-foreground);font:inherit;font-size:14px;line-height:22px;cursor:pointer;transition:background .14s ease}
746
+ .dsh-powerup-update-primary:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover,var(--dsw-alias-brand-primary))}
747
+ .dsh-powerup-update-primary:disabled{opacity:.4;cursor:not-allowed}
748
+ .dsh-powerup-update-ghost{height:36px;padding:0 14px;border:0;border-radius:var(--dsw-radius-md,8px);background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:14px;line-height:22px;cursor:pointer}
749
+ .dsh-powerup-update-ghost:hover{background:var(--dsw-alias-interactive-bg-hover)}
750
+ .dsh-powerup-update-ghost:active{background:var(--dsw-alias-interactive-bg-active)}
751
+ .dsh-powerup-update-close:focus-visible,.dsh-powerup-update-toggle:focus-visible,.dsh-powerup-update-version:focus-visible,.dsh-powerup-update-select-trigger:focus-visible,.dsh-powerup-update-option:focus-visible,.dsh-powerup-update-primary:focus-visible,.dsh-powerup-update-ghost:focus-visible,.dsh-powerup-update-button:focus-visible{outline:var(--dsw-focus-ring-width,2px) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:1px}
752
+ @media (max-width:680px){.dsh-powerup-page{padding:20px 16px 42px}.dsh-powerup-actions{grid-template-columns:minmax(0,1fr)}.dsh-powerup-hero-art{width:54px;height:54px}.dsh-powerup-hero h1{font-size:19px}.dsh-powerup-card-head{flex-wrap:wrap}.dsh-powerup-switch{margin-left:auto}.dsh-powerup-update-mask{padding:12px}.dsh-powerup-update-dialog{max-height:calc(100dvh - 24px)}.dsh-powerup-update-head{padding:18px 12px 10px 18px}.dsh-powerup-update-body{padding:0 18px 4px}.dsh-powerup-update-foot{padding:14px 18px 18px}}
701
753
  `;
702
754
 
703
755
  function installStyles(ctx) {
@@ -1297,6 +1349,24 @@
1297
1349
  return list.sort(compareVersionsDesc);
1298
1350
  }
1299
1351
 
1352
+ /**
1353
+ * Which status a version row carries. The installed and the latest
1354
+ * version can be the same; that row gets one combined tag instead of two
1355
+ * chips sharing the trailing space.
1356
+ * @param {string} version
1357
+ * @param {string | null | undefined} current
1358
+ * @param {string | null | undefined} latest
1359
+ * @returns {'current-latest' | 'current' | 'latest' | null}
1360
+ */
1361
+ function versionTagKind(version, current, latest) {
1362
+ const isCurrent = typeof current === 'string' && current !== '' && version === current;
1363
+ const isLatest = typeof latest === 'string' && latest !== '' && version === latest;
1364
+ if (isCurrent && isLatest) return 'current-latest';
1365
+ if (isCurrent) return 'current';
1366
+ if (isLatest) return 'latest';
1367
+ return null;
1368
+ }
1369
+
1300
1370
  /**
1301
1371
  * Read the versions the registry publishes for one package. The
1302
1372
  * abbreviated metadata keeps the response small; both npm and npmmirror
@@ -1446,6 +1516,7 @@
1446
1516
  const abortRef = useRef(null);
1447
1517
  const buttonsRef = useRef(new Set());
1448
1518
  const inputRef = useRef(null);
1519
+ const registryRef = useRef(null);
1449
1520
  const versionSeq = useRef(0);
1450
1521
  const tRef = useRef((key, params) => translateCurrent(key, params));
1451
1522
  tRef.current = (key, params) => translateCurrent(key, params);
@@ -1536,6 +1607,7 @@
1536
1607
  versionsRegistry: null,
1537
1608
  version: '',
1538
1609
  listOpen: true,
1610
+ registryOpen: false,
1539
1611
  error: null,
1540
1612
  formError: null,
1541
1613
  log: '',
@@ -1628,18 +1700,39 @@
1628
1700
  }
1629
1701
  }, [view === null ? null : view.phase]);
1630
1702
 
1631
- // Escape closes a dialog that is not in the middle of an operation.
1703
+ // Escape closes the innermost popover first: registry menu, then the
1704
+ // version list, then the dialog itself.
1632
1705
  useEffect(() => {
1633
1706
  if (view === null) return undefined;
1634
1707
  const onKeyDown = (event) => {
1635
1708
  if (event.key !== 'Escape') return;
1636
1709
  event.stopPropagation();
1710
+ if (view.registryOpen === true) {
1711
+ setView((current) => current === null ? current : { ...current, registryOpen: false });
1712
+ return;
1713
+ }
1714
+ if (view.phase === 'choose' && view.listOpen === true) {
1715
+ setView((current) => current === null ? current : { ...current, listOpen: false });
1716
+ return;
1717
+ }
1637
1718
  close();
1638
1719
  };
1639
1720
  document.addEventListener('keydown', onKeyDown, true);
1640
1721
  return () => document.removeEventListener('keydown', onKeyDown, true);
1641
1722
  }, [view, close]);
1642
1723
 
1724
+ // A click outside the custom registry select closes only its menu.
1725
+ useEffect(() => {
1726
+ if (view === null || view.registryOpen !== true) return undefined;
1727
+ const onPointerDown = (event) => {
1728
+ const root = registryRef.current;
1729
+ if (root !== null && event.target instanceof Node && root.contains(event.target)) return;
1730
+ setView((current) => current === null ? current : { ...current, registryOpen: false });
1731
+ };
1732
+ document.addEventListener('pointerdown', onPointerDown, true);
1733
+ return () => document.removeEventListener('pointerdown', onPointerDown, true);
1734
+ }, [view === null ? null : view.registryOpen]);
1735
+
1643
1736
  // Show pnpm output while an installation runs.
1644
1737
  useEffect(() => {
1645
1738
  if (remote === undefined || remote === null || typeof remote.$on !== 'function') return undefined;
@@ -1673,7 +1766,7 @@
1673
1766
  if (current === null) return;
1674
1767
  const choice = current.choices.find((item) => item.key === key);
1675
1768
  if (choice === undefined) return;
1676
- setView((state) => state === null ? state : { ...state, registryKey: key, formError: null });
1769
+ setView((state) => state === null ? state : { ...state, registryKey: key, registryOpen: false, formError: null });
1677
1770
  loadVersions(token, current.name, choice, current.choices, true);
1678
1771
  };
1679
1772
 
@@ -1822,12 +1915,23 @@
1822
1915
  supported ? h('button', { key: 'now', type: 'button', className: 'dsh-powerup-update-primary', disabled: view.restarting === true, onClick: restartNow }, view.restarting === true ? t('update.restarting') : t('update.restartNow')) : null,
1823
1916
  ].filter(Boolean);
1824
1917
  }
1825
- if (view.phase === 'restarting') return [];
1918
+ if (view.phase === 'restarting' || view.phase === 'working' || view.phase === 'loading') return [];
1826
1919
  return [
1827
1920
  h('button', { key: 'done', type: 'button', className: 'dsh-powerup-update-primary', onClick: close }, view.phase === 'done' ? t('update.doneButton') : t('update.close')),
1828
1921
  ];
1829
1922
  })();
1830
1923
 
1924
+ /** One tinted notice: the success/warn/error states share this chrome. */
1925
+ const notice = (tone, icon, title, message) => h('div', { className: `dsh-powerup-update-notice ${tone}` },
1926
+ icon,
1927
+ h('div', { className: 'dsh-powerup-update-notice-copy' },
1928
+ title === null || title === undefined ? null : h('span', { className: 'dsh-powerup-update-notice-title' }, title),
1929
+ message === null || message === undefined ? null : h('span', null, message),
1930
+ ),
1931
+ );
1932
+
1933
+ const currentChoice = view.choices.find((item) => item.key === view.registryKey) ?? view.choices[0];
1934
+
1831
1935
  const body = (() => {
1832
1936
  if (view.phase === 'loading') {
1833
1937
  return h('div', { className: 'dsh-powerup-update-status' },
@@ -1836,22 +1940,73 @@
1836
1940
  );
1837
1941
  }
1838
1942
  if (view.phase === 'self') {
1839
- return [
1840
- h('p', { className: 'dsh-powerup-update-note' }, t('update.selfDesc')),
1841
- ];
1943
+ return notice('warn', h(WarnIcon, { size: 15 }), t('update.selfTitle'), t('update.selfDesc'));
1842
1944
  }
1843
1945
  if (view.phase === 'blocked') {
1844
- return h('div', { className: 'dsh-powerup-update-error' },
1845
- h(WarnIcon, { size: 15 }),
1846
- h('span', null, view.error ?? t('update.notRemovable')),
1847
- );
1946
+ return notice('error', h(WarnIcon, { size: 15 }), t('update.unsupportedTitle'), view.error ?? t('update.notRemovable'));
1848
1947
  }
1849
1948
  if (view.phase === 'choose') {
1949
+ const rows = (() => {
1950
+ if (view.versionsState === 'loading') {
1951
+ return [h('div', { key: 'state', className: 'dsh-powerup-update-list-state' },
1952
+ h('div', { className: 'dsh-powerup-update-status' },
1953
+ h('span', { className: 'dsh-powerup-update-spinner', 'aria-hidden': 'true' }),
1954
+ t('update.loadingVersions'),
1955
+ ),
1956
+ )];
1957
+ }
1958
+ if (view.versionsState === 'error') {
1959
+ return [h('div', { key: 'state', className: 'dsh-powerup-update-list-state' },
1960
+ notice('error', h(WarnIcon, { size: 14 }), null, t('update.versionsFailed', { message: view.versionsError ?? '' })),
1961
+ h('button', {
1962
+ type: 'button',
1963
+ className: 'dsh-powerup-update-ghost',
1964
+ onClick: () => loadVersions(tokenRef.current, view.name, currentChoice, view.choices, false),
1965
+ }, t('update.retry')),
1966
+ )];
1967
+ }
1968
+ if ((view.versions ?? []).length === 0) {
1969
+ return [h('div', { key: 'state', className: 'dsh-powerup-update-list-state' },
1970
+ h('p', { className: 'dsh-powerup-update-note' }, t('update.versionsEmpty')),
1971
+ )];
1972
+ }
1973
+ return [
1974
+ h('div', { key: 'head', className: 'dsh-powerup-update-list-head' },
1975
+ h('span', null, t('update.versionsCount', { count: view.versions.length })),
1976
+ view.versionsRegistry === null || view.versionsRegistry === undefined
1977
+ ? null
1978
+ : h('span', { title: view.versionsRegistry.hint }, view.versionsRegistry.hint),
1979
+ ),
1980
+ ...view.versions.map((version) => {
1981
+ const tagKind = versionTagKind(version, view.currentVersion, view.latest);
1982
+ return h('button', {
1983
+ key: version,
1984
+ type: 'button',
1985
+ role: 'option',
1986
+ className: 'dsh-powerup-update-version',
1987
+ 'aria-selected': version === view.version ? 'true' : 'false',
1988
+ 'data-current': version === view.currentVersion ? '' : undefined,
1989
+ onClick: () => chooseVersion(version),
1990
+ },
1991
+ h('span', null, version),
1992
+ h('span', { className: 'dsh-powerup-update-trailing' },
1993
+ tagKind === null ? null : h('span', {
1994
+ className: `dsh-powerup-update-tag${tagKind === 'latest' ? '' : ' is-current'}`,
1995
+ }, t(tagKind === 'current-latest' ? 'update.currentAndLatest' : tagKind === 'current' ? 'update.currentTag' : 'update.latest')),
1996
+ version === view.version ? h('span', { className: 'dsh-powerup-update-check' }, h(CheckIcon, { size: 13 })) : null,
1997
+ ),
1998
+ );
1999
+ }),
2000
+ ];
2001
+ })();
1850
2002
  return [
1851
- h('div', { key: 'name', className: 'dsh-powerup-update-name' }, view.name),
1852
- h('div', { key: 'meta', className: 'dsh-powerup-update-meta' },
1853
- h('span', null, `${t('update.current')} ${view.currentVersion ?? '—'}`),
1854
- view.installed === false ? h('span', { className: 'dsh-powerup-update-chip' }, t('update.installedChip')) : null,
2003
+ h('div', { key: 'summary', className: 'dsh-powerup-update-summary' },
2004
+ h('div', { className: 'dsh-powerup-update-now' },
2005
+ h('span', { className: 'label' }, t('update.current')),
2006
+ h('code', null, view.currentVersion ?? '—'),
2007
+ view.installed === false ? h('span', { className: 'dsh-powerup-update-note' }, t('update.installedChip')) : null,
2008
+ ),
2009
+ h('span', { className: 'dsh-powerup-update-name' }, view.name),
1855
2010
  ),
1856
2011
  h('div', { key: 'version', className: 'dsh-powerup-update-field' },
1857
2012
  h('label', { className: 'dsh-powerup-update-label', htmlFor: 'dsh-powerup-update-version' }, t('update.versionLabel')),
@@ -1874,49 +2029,48 @@
1874
2029
  type: 'button',
1875
2030
  className: 'dsh-powerup-update-toggle',
1876
2031
  'aria-expanded': showVersions ? 'true' : 'false',
2032
+ 'aria-controls': 'dsh-powerup-update-versions',
1877
2033
  onClick: () => setView((current) => current === null ? current : { ...current, listOpen: !(current.listOpen === true) }),
1878
- }, t('update.chooseVersion')),
2034
+ },
2035
+ showVersions ? t('update.hideVersions') : t('update.chooseVersion'),
2036
+ h('span', { className: 'chevron' }, h(ChevronDownIcon, { size: 12 })),
2037
+ ),
1879
2038
  ),
1880
- view.formError === null || view.formError === undefined ? null : h('p', { className: 'dsh-powerup-update-error' }, h(WarnIcon, { size: 14 }), h('span', null, view.formError)),
2039
+ view.formError === null || view.formError === undefined
2040
+ ? null
2041
+ : notice('error', h(WarnIcon, { size: 14 }), null, view.formError),
1881
2042
  ),
1882
- showVersions ? h('div', { key: 'versions', className: 'dsh-powerup-update-list' }, (() => {
1883
- if (view.versionsState === 'loading') {
1884
- return h('div', { className: 'dsh-powerup-update-status' },
1885
- h('span', { className: 'dsh-powerup-update-spinner', 'aria-hidden': 'true' }),
1886
- t('update.loadingVersions'),
1887
- );
1888
- }
1889
- if (view.versionsState === 'error') {
1890
- return h('div', { className: 'dsh-powerup-update-version' },
1891
- h('span', null, t('update.versionsFailed', { message: view.versionsError ?? '' })),
1892
- h('button', {
1893
- type: 'button',
1894
- className: 'dsh-powerup-update-ghost',
1895
- onClick: () => loadVersions(tokenRef.current, view.name, view.choices.find((item) => item.key === view.registryKey) ?? view.choices[0], view.choices, false),
1896
- }, t('update.retry')),
1897
- );
1898
- }
1899
- if ((view.versions ?? []).length === 0) {
1900
- return h('div', { className: 'dsh-powerup-update-version' }, t('update.versionsEmpty'));
1901
- }
1902
- return view.versions.map((version) => h('button', {
1903
- key: version,
1904
- type: 'button',
1905
- className: 'dsh-powerup-update-version',
1906
- 'aria-selected': version === view.version ? 'true' : 'false',
1907
- onClick: () => chooseVersion(version),
1908
- },
1909
- h('span', null, version),
1910
- version === view.latest ? h('span', { className: 'dsh-powerup-update-tag' }, t('update.latest')) : null,
1911
- ));
1912
- })()) : null,
1913
- h('div', { key: 'registry', className: 'dsh-powerup-update-registry' },
2043
+ showVersions ? h('div', { key: 'versions', id: 'dsh-powerup-update-versions', className: 'dsh-powerup-update-list', role: 'listbox', 'aria-label': t('update.versionLabel') }, rows) : null,
2044
+ h('div', { key: 'registry', className: 'dsh-powerup-update-field' },
1914
2045
  h('span', { className: 'dsh-powerup-update-label' }, t('update.registry')),
1915
- h('select', {
1916
- className: 'dsh-powerup-update-select',
1917
- value: view.registryKey,
1918
- onChange: (event) => chooseRegistry(event.target.value),
1919
- }, view.choices.map((choice) => h('option', { key: choice.key, value: choice.key }, `${choice.label} · ${choice.hint}`))),
2046
+ h('div', { className: 'dsh-powerup-update-select', ref: registryRef },
2047
+ h('button', {
2048
+ type: 'button',
2049
+ className: 'dsh-powerup-update-select-trigger',
2050
+ 'aria-haspopup': 'listbox',
2051
+ 'aria-expanded': view.registryOpen === true ? 'true' : 'false',
2052
+ onClick: () => setView((current) => current === null ? current : { ...current, registryOpen: !(current.registryOpen === true) }),
2053
+ },
2054
+ h('span', { className: 'dsh-powerup-update-select-value' }, currentChoice?.label ?? ''),
2055
+ h('span', { className: 'dsh-powerup-update-select-host' }, currentChoice?.hint ?? ''),
2056
+ h('span', { className: 'chevron' }, h(ChevronDownIcon, { size: 12 })),
2057
+ ),
2058
+ view.registryOpen === true ? h('div', { className: 'dsh-powerup-update-select-menu', role: 'listbox', 'aria-label': t('update.registry') },
2059
+ view.choices.map((choice) => h('button', {
2060
+ key: choice.key,
2061
+ type: 'button',
2062
+ role: 'option',
2063
+ className: 'dsh-powerup-update-option',
2064
+ 'aria-selected': choice.key === view.registryKey ? 'true' : 'false',
2065
+ onClick: () => chooseRegistry(choice.key),
2066
+ },
2067
+ h('span', { className: 'dsh-powerup-update-option-copy' },
2068
+ h('span', { className: 'dsh-powerup-update-option-title' }, choice.label),
2069
+ h('span', { className: 'dsh-powerup-update-option-host' }, choice.hint),
2070
+ ),
2071
+ choice.key === view.registryKey ? h('span', { className: 'dsh-powerup-update-check' }, h(CheckIcon, { size: 13 })) : null,
2072
+ ))) : null,
2073
+ ),
1920
2074
  view.versionsRegistry === null || view.versionsRegistry === undefined
1921
2075
  ? null
1922
2076
  : h('span', { className: 'dsh-powerup-update-note' }, t('update.registryFrom', { registry: view.versionsRegistry.hint })),
@@ -1934,7 +2088,9 @@
1934
2088
  h('span', { className: 'dsh-powerup-update-spinner', 'aria-hidden': 'true' }),
1935
2089
  label,
1936
2090
  ),
1937
- h('div', { key: 'name', className: 'dsh-powerup-update-name' }, view.name),
2091
+ h('div', { key: 'summary', className: 'dsh-powerup-update-summary' },
2092
+ h('span', { className: 'dsh-powerup-update-name' }, view.name),
2093
+ ),
1938
2094
  view.log === '' ? null : h('div', { key: 'log', className: 'dsh-powerup-update-field' },
1939
2095
  h('span', { className: 'dsh-powerup-update-label' }, t('update.log')),
1940
2096
  h('pre', { className: 'dsh-powerup-update-log' }, view.log),
@@ -1943,26 +2099,34 @@
1943
2099
  }
1944
2100
  if (view.phase === 'enable') {
1945
2101
  return [
1946
- h('div', { key: 'title', className: 'dsh-powerup-update-meta' },
1947
- h(CheckIcon, { size: 15 }),
1948
- h('span', null, t('update.enableTitle')),
2102
+ notice('success', h(CheckIcon, { size: 15 }), t('update.enableTitle'), t('update.enableDesc')),
2103
+ h('div', { key: 'summary', className: 'dsh-powerup-update-summary' },
2104
+ h('span', { className: 'dsh-powerup-update-name' }, view.name),
2105
+ h('div', { className: 'dsh-powerup-update-now' },
2106
+ h('span', { className: 'label' }, t('update.versionLabel')),
2107
+ h('code', null, view.installedVersion ?? '—'),
2108
+ ),
1949
2109
  ),
1950
- h('p', { key: 'desc', className: 'dsh-powerup-update-note' }, t('update.enableDesc')),
1951
- h('div', { key: 'name', className: 'dsh-powerup-update-name' }, `${view.name} · ${view.installedVersion ?? ''}`),
1952
- view.enableError === null || view.enableError === undefined ? null : h('div', { key: 'error', className: 'dsh-powerup-update-error' }, h(WarnIcon, { size: 14 }), h('span', null, t('update.enableFailed', { message: view.enableError }))),
2110
+ view.enableError === null || view.enableError === undefined
2111
+ ? null
2112
+ : notice('error', h(WarnIcon, { size: 14 }), t('update.errorTitle'), t('update.enableFailed', { message: view.enableError })),
1953
2113
  ];
1954
2114
  }
1955
2115
  if (view.phase === 'restart') {
1956
2116
  const supported = view.restart?.supported === true;
1957
2117
  return [
1958
- h('div', { key: 'title', className: 'dsh-powerup-update-meta' },
1959
- h(CheckIcon, { size: 15 }),
1960
- h('span', null, t('update.restartTitle')),
2118
+ notice('success', h(CheckIcon, { size: 15 }), t('update.restartTitle'), t('update.restartDesc')),
2119
+ h('div', { key: 'summary', className: 'dsh-powerup-update-summary' },
2120
+ h('span', { className: 'dsh-powerup-update-name' }, view.name),
2121
+ h('div', { className: 'dsh-powerup-update-now' },
2122
+ h('span', { className: 'label' }, t('update.versionLabel')),
2123
+ h('code', null, view.installedVersion ?? '—'),
2124
+ ),
1961
2125
  ),
1962
- h('p', { key: 'desc', className: 'dsh-powerup-update-note' }, t('update.restartDesc')),
1963
- h('div', { key: 'name', className: 'dsh-powerup-update-name' }, `${view.name} · ${view.installedVersion ?? ''}`),
1964
- supported ? null : h('p', { key: 'unsupported', className: 'dsh-powerup-update-note' }, t('update.restartUnsupported', { reason: view.restart?.reason ?? '' })),
1965
- view.restartError === null || view.restartError === undefined ? null : h('div', { key: 'error', className: 'dsh-powerup-update-error' }, h(WarnIcon, { size: 14 }), h('span', null, t('update.restartFailed', { message: view.restartError }))),
2126
+ supported ? null : notice('warn', h(WarnIcon, { size: 14 }), null, t('update.restartUnsupported', { reason: view.restart?.reason ?? '' })),
2127
+ view.restartError === null || view.restartError === undefined
2128
+ ? null
2129
+ : notice('error', h(WarnIcon, { size: 14 }), t('update.errorTitle'), t('update.restartFailed', { message: view.restartError })),
1966
2130
  ];
1967
2131
  }
1968
2132
  if (view.phase === 'restarting') {
@@ -1973,8 +2137,7 @@
1973
2137
  }
1974
2138
  if (view.phase === 'done') {
1975
2139
  return [
1976
- h('div', { key: 'title', className: 'dsh-powerup-update-meta' }, h(CheckIcon, { size: 15 }), h('span', null, t('update.doneTitle'))),
1977
- h('p', { key: 'desc', className: 'dsh-powerup-update-note' }, view.enabled === false
2140
+ notice('success', h(CheckIcon, { size: 15 }), t('update.doneTitle'), view.enabled === false
1978
2141
  ? t('update.doneDisabled', { name: view.name, version: view.installedVersion ?? '' })
1979
2142
  : t('update.doneInstalled', { name: view.name, version: view.installedVersion ?? '' })),
1980
2143
  view.restartSkipped === true ? h('p', { key: 'restart', className: 'dsh-powerup-update-note' }, t('update.doneRestart')) : null,
@@ -1982,9 +2145,8 @@
1982
2145
  }
1983
2146
  if (view.phase === 'error') {
1984
2147
  return [
1985
- h('div', { key: 'title', className: 'dsh-powerup-update-error' }, h(WarnIcon, { size: 15 }), h('span', null, t('update.errorTitle'))),
1986
- h('p', { key: 'message', className: 'dsh-powerup-update-note' }, view.error ?? t('update.unknown')),
1987
- h('div', { key: 'name', className: 'dsh-powerup-update-name' }, view.name),
2148
+ notice('error', h(WarnIcon, { size: 15 }), t('update.errorTitle'), view.error ?? t('update.unknown')),
2149
+ h('span', { key: 'name', className: 'dsh-powerup-update-name' }, view.name),
1988
2150
  ];
1989
2151
  }
1990
2152
  return null;
@@ -2003,9 +2165,8 @@
2003
2165
  'aria-labelledby': 'dsh-powerup-update-title',
2004
2166
  },
2005
2167
  h('div', { className: 'dsh-powerup-update-head' },
2006
- h('span', { className: 'dsh-powerup-update-icon' }, h(UpdateIcon, { size: 15 })),
2007
2168
  h('div', { className: 'dsh-powerup-update-heading' },
2008
- h('h2', { id: 'dsh-powerup-update-title' }, view.phase === 'self' ? t('update.selfTitle') : t('update.title')),
2169
+ h('h2', { id: 'dsh-powerup-update-title' }, t('update.title')),
2009
2170
  h('p', { title }, title),
2010
2171
  ),
2011
2172
  canClose ? h('button', { type: 'button', className: 'dsh-powerup-update-close', 'aria-label': t('update.close'), onClick: close }, '×') : null,
@@ -2394,6 +2555,7 @@
2394
2555
  buildRowItems,
2395
2556
  buildSessionItems,
2396
2557
  sortVersions,
2558
+ versionTagKind,
2397
2559
  compareVersionsDesc,
2398
2560
  buildRegistryChoices,
2399
2561
  pickRegistryChoice,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@restregular/dsh-powerup",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Power-Up — small, opt-in upgrades for DeepSeek Harness. Adds a right-click action menu to the Trajectory ledger and an update control for third-party plugins installed from the Plugins page, with version lookup, uninstall-and-reinstall through the Add plugin path, and an optional DSH restart. · 为 DeepSeek Harness 提供小型增强:在轨迹页面右键记录即可复制、引用、查看详情或从该记录 Fork;并在插件页为第三方已安装插件提供带版本查询的更新按钮,沿用「添加插件」的安装流程,并可重启 DSH 使更改生效。",
5
5
  "icon": "./icon.svg",
6
6
  "type": "module",