dsh-skill-hub 0.3.26 → 0.3.28

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 (70) hide show
  1. package/CONTRIBUTING.md +1 -1
  2. package/README.md +11 -3
  3. package/README.zh.md +11 -3
  4. package/lib/client.js +310 -39
  5. package/lib/client.js.map +1 -1
  6. package/lib/index.js +790 -15
  7. package/lib/types/client/api.d.ts +8 -1
  8. package/lib/types/client/locales/common.d.ts +4 -0
  9. package/lib/types/client/locales/market.d.ts +10 -0
  10. package/lib/types/client/locales/sources.d.ts +3 -0
  11. package/lib/types/client/locales.d.ts +17 -0
  12. package/lib/types/client/panel/ForeignImportDialog.d.ts +15 -0
  13. package/lib/types/client/panel/PanelDialogs.d.ts +2 -0
  14. package/lib/types/client/panel/dialogs.d.ts +11 -1
  15. package/lib/types/client/panel/useSkillHub.d.ts +1 -0
  16. package/lib/types/protocol/api.d.ts +2 -0
  17. package/lib/types/protocol/catalog.d.ts +39 -1
  18. package/lib/types/protocol/foreign.d.ts +51 -0
  19. package/lib/types/protocol/sources.d.ts +13 -0
  20. package/lib/types/protocol.d.ts +3 -1
  21. package/lib/types/repo/install.d.ts +4 -0
  22. package/lib/types/routes/deps.d.ts +11 -0
  23. package/lib/types/routes/foreign.d.ts +10 -0
  24. package/lib/types/routes/helpers.d.ts +1 -1
  25. package/lib/types/skillfs/audit.d.ts +58 -0
  26. package/lib/types/skillfs/foreign.d.ts +51 -0
  27. package/lib/types/skillfs/hash.d.ts +24 -0
  28. package/lib/types/skillfs.d.ts +2 -0
  29. package/lib/types/store/store.d.ts +6 -0
  30. package/package.json +23 -21
  31. package/src/client/api.ts +14 -0
  32. package/src/client/locales/common.ts +8 -0
  33. package/src/client/locales/market.ts +20 -0
  34. package/src/client/locales/sources.ts +6 -0
  35. package/src/client/panel/ForeignImportDialog.tsx +130 -0
  36. package/src/client/panel/PanelDialogs.tsx +4 -1
  37. package/src/client/panel/SkillHubPanel.tsx +34 -4
  38. package/src/client/panel/SourceStatusBadge.tsx +23 -13
  39. package/src/client/panel/dialogs.tsx +14 -3
  40. package/src/client/panel/panel.module.css +6 -0
  41. package/src/client/panel/useSkillHub.ts +1 -1
  42. package/src/index.ts +2 -2
  43. package/src/protocol/api.ts +2 -0
  44. package/src/protocol/catalog.ts +56 -0
  45. package/src/protocol/foreign.ts +47 -0
  46. package/src/protocol/sources.ts +13 -0
  47. package/src/protocol.test.ts +59 -0
  48. package/src/protocol.ts +3 -0
  49. package/src/repo/install.ts +34 -0
  50. package/src/repo.test.ts +55 -0
  51. package/src/routes/catalog-data.ts +2 -0
  52. package/src/routes/deps.ts +15 -0
  53. package/src/routes/foreign.ts +127 -0
  54. package/src/routes/helpers.ts +1 -0
  55. package/src/routes/repo-import.ts +4 -1
  56. package/src/routes/sources.ts +53 -3
  57. package/src/routes.test.ts +162 -3
  58. package/src/routes.ts +2 -0
  59. package/src/skillfs/audit.test.ts +182 -0
  60. package/src/skillfs/audit.ts +229 -0
  61. package/src/skillfs/foreign.test.ts +121 -0
  62. package/src/skillfs/foreign.ts +198 -0
  63. package/src/skillfs/hash.test.ts +129 -0
  64. package/src/skillfs/hash.ts +112 -0
  65. package/src/skillfs/scan.ts +17 -0
  66. package/src/skillfs.test.ts +37 -0
  67. package/src/skillfs.ts +2 -0
  68. package/src/store/migrate.ts +7 -1
  69. package/src/store/store.ts +36 -3
  70. package/src/store.test.ts +24 -0
package/lib/client.js CHANGED
@@ -49,7 +49,9 @@ window.__ModuleLoader__.load({
49
49
  sourceTrashClear: "/api/skill-hub/sources/trash/clear",
50
50
  diagnosticFix: "/api/skill-hub/diagnostic/fix",
51
51
  marketSourceVersions: "/api/skill-hub/market/source/versions",
52
- marketStats: "/api/skill-hub/market/stats"
52
+ marketStats: "/api/skill-hub/market/stats",
53
+ foreign: "/api/skill-hub/foreign",
54
+ foreignImport: "/api/skill-hub/foreign/import"
53
55
  };
54
56
  //#endregion
55
57
  //#region src/protocol/config.ts
@@ -287,6 +289,15 @@ window.__ModuleLoader__.load({
287
289
  sources() {
288
290
  return this.get(SKILL_HUB_API.sources);
289
291
  }
292
+ /** 列出其他 agent 用户级技能目录里的可收编技能(只读扫描)。 */
293
+ listForeignSkills() {
294
+ return this.get(SKILL_HUB_API.foreign);
295
+ }
296
+ /** 收编所选外部技能到 ~/.dsh/skills。 */
297
+ importForeignSkills(items) {
298
+ const payload = { items };
299
+ return this.post(SKILL_HUB_API.foreignImport, payload);
300
+ }
290
301
  /** 检查指定(或全部)来源的上游更新。 */
291
302
  checkSources(repo) {
292
303
  const payload = repo !== void 0 ? { repo } : {};
@@ -343,6 +354,10 @@ window.__ModuleLoader__.load({
343
354
  "legend.hint": "每个技能最多一个圆点;无圆点 = 不可被调用。",
344
355
  "panel.disabled": "已禁用",
345
356
  "panel.diagnostics": "发现诊断",
357
+ "panel.auditBadge": "审计",
358
+ "panel.announcement": "公告预算 {chars} 字符 ≈ {tokens} tokens · {skills} 个技能",
359
+ "panel.announcementOver": "超出建议上限 {budget} 字符,排在后面的技能可能不触发",
360
+ "panel.announcementHint": "技能目录的第一层(name + description)常驻在 system prompt 里。建议不超 {budget} 字符 —— 超出后客户端会截断尾部条目,表现为「装了却不触发」。",
346
361
  "panel.empty": "没有匹配的技能。",
347
362
  "panel.emptyAll": "本地还没有技能。点击「新建技能」创建第一个。",
348
363
  "panel.loading": "读取中…",
@@ -391,6 +406,10 @@ window.__ModuleLoader__.load({
391
406
  "legend.hint": "At most one dot per skill; no dot = not invocable.",
392
407
  "panel.disabled": "Disabled",
393
408
  "panel.diagnostics": "Discovery diagnostics",
409
+ "panel.auditBadge": "audit",
410
+ "panel.announcement": "Announcement budget: {chars} chars ≈ {tokens} tokens · {skills} skills",
411
+ "panel.announcementOver": "over the suggested {budget}-char cap — later skills may stop triggering",
412
+ "panel.announcementHint": "The first progressive-disclosure layer (name + description) sits in the system prompt. Stay under {budget} chars: past it, clients truncate the tail and skills silently stop triggering.",
394
413
  "panel.empty": "No matching skills.",
395
414
  "panel.emptyAll": "No skills installed yet. Create the first one.",
396
415
  "panel.loading": "Loading…",
@@ -534,7 +553,17 @@ window.__ModuleLoader__.load({
534
553
  "repo.root.self": "仓库根",
535
554
  "repo.root.skills": "skills",
536
555
  "repo.root.designTemplates": "design-templates",
537
- "repo.root.generic": "{root}"
556
+ "repo.root.generic": "{root}",
557
+ "foreign.open": "从其他 Agent 导入",
558
+ "foreign.title": "从其他 Agent 导入",
559
+ "foreign.text": "读取 Claude Code / Codex / Cursor 等工具的用户级技能目录(只读),把所选技能复制到 ~/.dsh/skills。原目录不受影响。",
560
+ "foreign.empty": "没有在这些工具的技能目录里发现技能。",
561
+ "foreign.exists": "已存在",
562
+ "foreign.import": "导入所选({count})",
563
+ "foreign.importing": "导入中…",
564
+ "foreign.skipped": "{count} 个因同名已存在被跳过。",
565
+ "foreign.importedBanner": "已导入 {count} 个技能。",
566
+ "foreign.importedReplacedBanner": "已导入 {count} 个技能,另有 {replaced} 个同名占位被移入回收站(可恢复)。"
538
567
  };
539
568
  const enMarket = {
540
569
  "market.syncHint": "Sync to the latest upstream and report local skills that can update",
@@ -615,7 +644,17 @@ window.__ModuleLoader__.load({
615
644
  "repo.root.self": "Repo root",
616
645
  "repo.root.skills": "Skills",
617
646
  "repo.root.designTemplates": "Templates",
618
- "repo.root.generic": "{root}"
647
+ "repo.root.generic": "{root}",
648
+ "foreign.open": "Import from another agent",
649
+ "foreign.title": "Import from another agent",
650
+ "foreign.text": "Reads the user-level skill folders of Claude Code / Codex / Cursor and friends (read-only) and copies the selected skills into ~/.dsh/skills. The originals are left untouched.",
651
+ "foreign.empty": "No skills found in those tool folders.",
652
+ "foreign.exists": "exists",
653
+ "foreign.import": "Import {count}",
654
+ "foreign.importing": "Importing…",
655
+ "foreign.skipped": "{count} skipped because the name already exists.",
656
+ "foreign.importedBanner": "Imported {count} skill(s).",
657
+ "foreign.importedReplacedBanner": "Imported {count} skill(s); {replaced} same-name placeholder(s) moved to trash (restorable)."
619
658
  };
620
659
  //#endregion
621
660
  //#region src/client/locales/settings.ts
@@ -834,6 +873,9 @@ window.__ModuleLoader__.load({
834
873
  "source.checking": "检查中…",
835
874
  "source.upToDate": "已是最新",
836
875
  "source.updated": "有更新 {count} 个",
876
+ "source.localModified": "本地改动 {count} 个",
877
+ "source.localModifiedBadge": "本地已改",
878
+ "source.localModifiedHint": "这些技能的磁盘内容与导入/同步时不一致(你自己改过)。同步会覆盖它们。",
837
879
  "source.deleted": "上游已删除 {count} 个",
838
880
  "source.error": "检查失败",
839
881
  "source.throttled": "刚刚检查过",
@@ -867,6 +909,9 @@ window.__ModuleLoader__.load({
867
909
  "source.checking": "Checking…",
868
910
  "source.upToDate": "Up to date",
869
911
  "source.updated": "{count} updates",
912
+ "source.localModified": "{count} edited locally",
913
+ "source.localModifiedBadge": "edited",
914
+ "source.localModifiedHint": "These skills no longer match what was imported or synced — you changed them on disk. Syncing overwrites them.",
870
915
  "source.deleted": "{count} deleted upstream",
871
916
  "source.error": "Check failed",
872
917
  "source.throttled": "Checked recently",
@@ -2809,7 +2854,7 @@ window.__ModuleLoader__.load({
2809
2854
  }
2810
2855
  //#endregion
2811
2856
  //#region \0dsh-css:/Users/huanyi/Documents/personal/tools/dsh-skill-hub/src/client/panel/panel.module.css.mjs
2812
- const css = "._6VtqdG_panel{-webkit-font-smoothing:antialiased;--hub-model:#2f81f7;--hub-user:#3fb950;--hub-accent:var(--dsw-alias-state-business-primary,#2f81f7);--hub-text:var(--dsw-alias-label-primary,currentColor);--hub-text-2:var(--dsw-alias-label-secondary,#61666b);--hub-text-3:var(--dsw-alias-label-tertiary,#81858c);--hub-text-4:var(--dsw-alias-label-caption,#adb2b8);--hub-surface:var(--dsw-alias-bg-module-platform,#8080800f);--hub-hover:var(--dsw-alias-interactive-bg-hover,#80808014);--hub-active:var(--dsw-alias-interactive-bg-active,#80808029);--hub-border:var(--dsw-alias-border-l2,#80808021);--hub-border-2:var(--dsw-alias-border-l3,#80808033);--hub-danger:var(--dsw-alias-state-error-primary,#d1242f);--hub-success:var(--dsw-alias-state-success-primary,#3fb950);--hub-warn:var(--dsw-alias-state-warn-primary,#d29922);--hub-on-accent:var(--dsw-alias-label-primary-foreground,#fff);--hub-skeleton:var(--dsw-alias-bg-skeleton,#8080801a);flex-direction:column;gap:14px;max-width:720px;margin:0 auto;padding:28px 20px 44px;font-family:-apple-system,BlinkMacSystemFont,SF Pro Text,Helvetica Neue,sans-serif;display:flex}._6VtqdG_header{flex-wrap:wrap;align-items:baseline;gap:10px;display:flex}._6VtqdG_title{letter-spacing:-.02em;margin:0;font-size:24px;font-weight:700}._6VtqdG_hint{color:var(--hub-text-3);font-size:12px}._6VtqdG_actions{gap:8px;margin-left:auto;display:flex}._6VtqdG_segmented{background:var(--hub-hover);border-radius:9px;gap:2px;padding:2px;display:flex}._6VtqdG_segBtn{color:var(--hub-text-2);cursor:pointer;background:0 0;border:none;border-radius:7px;padding:5px 13px;font-size:12px;transition:background .15s,opacity .15s}._6VtqdG_segBtn:hover{color:var(--hub-text)}._6VtqdG_segBtnActive{background:var(--hub-active);opacity:1;font-weight:600}._6VtqdG_search{background:var(--hub-surface);width:100%;color:inherit;border:none;border-radius:10px;outline:none;padding:10px 14px;font-size:13px;transition:background .15s}._6VtqdG_search::placeholder{opacity:.45}._6VtqdG_search:focus{background:var(--hub-active)}._6VtqdG_section{background:var(--hub-surface);border-radius:12px;flex-direction:column;margin-top:4px;display:flex;overflow:hidden;box-shadow:0 1px 2px #00000008,0 4px 12px #0000000a}._6VtqdG_sectionTitle{margin:14px 16px 2px;font-size:13px;font-weight:700}._6VtqdG_groupHead{box-sizing:border-box;align-items:center;gap:8px;min-height:44px;padding:10px 14px;display:flex}._6VtqdG_groupTitle{color:var(--hub-text);flex:1;align-items:center;gap:6px;min-width:0;font-size:13px;font-weight:600;line-height:1;display:inline-flex}._6VtqdG_groupOps{flex-wrap:wrap;flex:none;align-items:center;gap:6px;display:inline-flex}._6VtqdG_opBtn{background:var(--hub-hover);color:inherit;cursor:pointer;border:none;border-radius:999px;padding:3px 11px;font-size:11px;transition:background .15s}._6VtqdG_opBtn:hover{background:var(--hub-active)}._6VtqdG_opBtn:disabled{opacity:.4;cursor:default}._6VtqdG_row{cursor:pointer;background:0 0;align-items:center;gap:12px;padding:10px 14px;transition:background .12s;display:flex}._6VtqdG_row:hover{background:var(--hub-hover)}._6VtqdG_row:focus-visible{outline:2px solid var(--hub-accent);outline-offset:-2px}._6VtqdG_rowStatic{cursor:default}._6VtqdG_rowStatic:hover{background:0 0}._6VtqdG_row+._6VtqdG_row{border-top:.5px solid var(--hub-border)}._6VtqdG_rowMain{flex:1;min-width:0}._6VtqdG_rowName{align-items:center;gap:5px;font-size:13.5px;display:flex}._6VtqdG_rowNameText{font-weight:600}._6VtqdG_rowDesc{color:var(--hub-text-3);white-space:nowrap;text-overflow:ellipsis;margin-top:1px;font-size:12.5px;overflow:hidden}._6VtqdG_badges{flex:none;align-items:center;gap:6px;display:flex}._6VtqdG_badge{border:.5px solid var(--hub-border-2);color:var(--hub-text-2);white-space:nowrap;border-radius:999px;padding:1px 7px;font-size:10.5px}._6VtqdG_badgeReadonly{opacity:.5}._6VtqdG_switch{border:1px solid var(--hub-border-2);background:var(--dsw-alias-bg-module-platform,#8080804d);cursor:pointer;border-radius:999px;flex:none;width:36px;height:21px;padding:2px;transition:background .18s}._6VtqdG_switch:disabled{opacity:.5;cursor:default}._6VtqdG_switchOn{background:var(--dsw-alias-state-business-primary,#34c759)}._6VtqdG_switchThumb{background:#fff;border-radius:50%;width:17px;height:17px;transition:transform .18s;display:block;transform:translate(0);box-shadow:0 1px 2px #00000040}._6VtqdG_switchOn ._6VtqdG_switchThumb{transform:translate(15px)}._6VtqdG_empty{color:var(--hub-text-3);text-align:center;padding:20px 0;font-size:13px}._6VtqdG_diagRow{border-left:3px solid var(--hub-warn);background:#d299220f;padding:9px 14px;font-size:12px}._6VtqdG_diagPath{color:var(--hub-text-2);word-break:break-all;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px}._6VtqdG_diagReason{color:var(--hub-text-3);margin-top:1px}._6VtqdG_updateLink{color:inherit;font-weight:600;text-decoration:underline}._6VtqdG_errorBanner{color:var(--hub-danger);white-space:pre-wrap;word-break:break-all;background:#d1242f12;border-radius:10px;align-items:flex-start;gap:10px;padding:10px 14px;font-size:12.5px;display:flex}._6VtqdG_successBanner{color:var(--hub-success);white-space:pre-wrap;word-break:break-all;background:#3fb95014;border-radius:10px;align-items:flex-start;gap:10px;padding:10px 14px;font-size:12.5px;display:flex}._6VtqdG_detailHead{flex-wrap:wrap;align-items:center;gap:10px;display:flex}._6VtqdG_back{background:var(--hub-hover);color:inherit;cursor:pointer;border:none;border-radius:8px;padding:6px 12px;font-size:12.5px}._6VtqdG_back:hover{background:var(--hub-active)}._6VtqdG_detailName{letter-spacing:-.01em;font-size:19px;font-weight:700}._6VtqdG_detailMeta{color:var(--hub-text-3);flex-direction:column;gap:4px;font-size:12px;display:flex}._6VtqdG_detailMetaLine{word-break:break-all}._6VtqdG_detailContent{white-space:pre-wrap;word-break:break-word;background:var(--hub-surface);border-radius:12px;max-height:62vh;padding:14px 16px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:1.6;overflow:auto}._6VtqdG_form{background:var(--hub-surface);border-radius:12px;flex-direction:column;gap:10px;padding:14px 16px;display:flex;box-shadow:0 1px 2px #00000008,0 4px 12px #0000000a}._6VtqdG_formRow{flex-direction:column;gap:5px;display:flex}._6VtqdG_formLabel{color:var(--hub-text-3);font-size:12px}._6VtqdG_input,._6VtqdG_select{background:var(--hub-surface);color:inherit;border:none;border-radius:9px;outline:none;padding:9px 12px;font-size:13px}._6VtqdG_input:focus,._6VtqdG_select:focus{background:var(--hub-active)}._6VtqdG_buttons{align-items:center;gap:8px;display:flex}._6VtqdG_button{cursor:pointer;background:var(--hub-hover);color:inherit;border:none;border-radius:8px;padding:6px 13px;font-size:12.5px;transition:background .15s}._6VtqdG_button:hover{background:var(--hub-active)}._6VtqdG_primary{background:var(--hub-accent);color:var(--hub-on-accent)}._6VtqdG_primary:hover{background:var(--hub-accent);opacity:.92}._6VtqdG_primary:disabled{opacity:.45;cursor:default}._6VtqdG_danger{background:var(--hub-danger);color:var(--hub-on-accent)}._6VtqdG_danger:hover{background:var(--hub-danger);opacity:.92}._6VtqdG_danger:disabled{opacity:.45;cursor:default}._6VtqdG_formError{color:var(--hub-danger)}._6VtqdG_formSuccess{color:var(--hub-success)}._6VtqdG_dot{vertical-align:middle;border-radius:50%;width:7px;height:7px;margin-left:5px;display:inline-block}._6VtqdG_dotModel{background:var(--hub-model)}._6VtqdG_dotUser{background:var(--hub-user)}._6VtqdG_displayName{color:var(--hub-text-3);white-space:nowrap;text-overflow:ellipsis;flex-shrink:1;min-width:0;max-width:160px;margin-left:6px;font-size:11px;font-weight:400;overflow:hidden}._6VtqdG_legend{color:var(--hub-text-3);flex-wrap:wrap;align-items:center;gap:12px;padding:2px 2px 0;font-size:11.5px;display:flex}._6VtqdG_legendItem{align-items:center;gap:4px;display:inline-flex}._6VtqdG_legendItem ._6VtqdG_dot{margin-left:0}._6VtqdG_legendHint{opacity:.8}._6VtqdG_badgeSource,._6VtqdG_badgeCount{background:var(--hub-hover);opacity:.72;border:none}._6VtqdG_disclosure{min-width:0;color:inherit;cursor:pointer;text-align:left;background:0 0;border:none;flex:1;align-items:center;gap:7px;min-height:24px;padding:2px 0;display:flex}._6VtqdG_disclosure:hover ._6VtqdG_groupTitle{opacity:1}._6VtqdG_chevron{opacity:.55;border-bottom:1.5px solid;border-right:1.5px solid;flex:none;align-self:center;width:8px;height:8px;margin-right:2px;transition:transform .15s;transform:rotate(45deg)translateY(-1px)}._6VtqdG_chevronCollapsed{transform:rotate(-45deg)translateY(-1px)}._6VtqdG_headerCount{color:var(--hub-text-3);white-space:nowrap;margin-left:2px;font-size:12px}._6VtqdG_pluginVersion{color:var(--hub-text-4);white-space:nowrap;font-variant-numeric:tabular-nums;margin-left:6px;font-size:12px;font-weight:500}._6VtqdG_subbar{flex-wrap:wrap;align-items:center;gap:8px;display:flex}._6VtqdG_legendToggle{background:var(--hub-hover);width:22px;height:22px;color:inherit;cursor:pointer;opacity:.55;border:none;border-radius:50%;flex:none;font-size:12px;line-height:1;transition:opacity .15s,background .15s}._6VtqdG_legendToggle:hover{opacity:1}._6VtqdG_legendToggleActive{opacity:1;background:var(--hub-active)}._6VtqdG_filterBar{flex-wrap:wrap;align-items:center;gap:8px;display:flex}._6VtqdG_filterBar ._6VtqdG_formLabel{margin:0}._6VtqdG_useCount{color:var(--hub-warn);vertical-align:1px;background:#d299221f;border-radius:999px;margin-left:6px;padding:0 6px;font-size:11px;font-weight:700;line-height:1.6;display:inline-block}._6VtqdG_useTime{color:var(--hub-text-4);white-space:nowrap;margin-left:auto;font-size:11px}._6VtqdG_switchMixed{background:#2f81f773;background:color-mix(in srgb, var(--hub-accent) 45%, transparent)}._6VtqdG_switchMixed ._6VtqdG_switchThumb{transform:translate(7.5px);box-shadow:0 1px 2px #00000040}._6VtqdG_groupTitleInner{align-items:baseline;display:inline-flex}._6VtqdG_sourceLink{color:inherit;opacity:.9;border-bottom:1px dotted;font-weight:600;text-decoration:none}._6VtqdG_sourceLink:hover{opacity:1}._6VtqdG_statusBadges{flex:none;align-items:center;gap:4px;display:inline-flex}._6VtqdG_statusBadge{border:.5px solid var(--hub-border-2);opacity:.8;white-space:nowrap;background:var(--hub-hover);border-radius:999px;padding:1px 7px;font-size:10.5px}._6VtqdG_statusOk{color:var(--hub-success);background:0 0;border-color:currentColor}._6VtqdG_statusUpdated{color:var(--hub-warn);background:#d2992214;border-color:currentColor}._6VtqdG_statusError{color:var(--hub-danger);background:#d1242f14;border-color:currentColor}._6VtqdG_statusWrap{cursor:pointer;background:0 0;border:none;align-items:center;gap:4px;padding:0;font-family:inherit;display:inline-flex}._6VtqdG_statusWrap:hover ._6VtqdG_statusBadge{opacity:1}._6VtqdG_statusButton{cursor:pointer;font-family:inherit}._6VtqdG_statusButton:hover{opacity:1}._6VtqdG_opDanger{color:var(--hub-danger);background:#d1242f1a}._6VtqdG_opDanger:hover{background:#d1242f2e}._6VtqdG_iconBtn{border-radius:999px;justify-content:center;align-items:center;width:24px;height:24px;padding:0;display:inline-flex}._6VtqdG_sourceCard{background:var(--hub-surface);border-radius:12px;flex-direction:column;gap:4px;padding:12px 14px;font-size:12px;display:flex}._6VtqdG_sourceCardTitle{flex-wrap:wrap;align-items:center;gap:8px;display:flex}._6VtqdG_dialogOverlay{z-index:50;-webkit-backdrop-filter:blur(2px);background:#00000059;justify-content:center;align-items:center;padding:24px;display:flex;position:fixed;inset:0}._6VtqdG_dialog{background:var(--dsw-alias-bg-layer-1,#f5f5f7);min-width:min(320px,100%);max-width:380px;color:var(--dsw-alias-label-primary,#1d1d1f);border-radius:14px;padding:18px 18px 14px;box-shadow:0 12px 40px #00000047,0 2px 8px #00000029}._6VtqdG_dialogTitle{letter-spacing:-.01em;margin:0 0 8px;font-size:15px;font-weight:700}._6VtqdG_dialogText{color:var(--hub-text-3);margin:0 0 10px;font-size:12.5px;line-height:1.5}._6VtqdG_dialogList{flex-direction:column;gap:5px;max-height:200px;margin:0 0 14px;padding:0;list-style:none;display:flex;overflow:auto}._6VtqdG_dialogList li{opacity:.85;word-break:break-all;font-size:12.5px}._6VtqdG_dialogActions{justify-content:flex-end;gap:8px;display:flex}._6VtqdG_filterBar ._6VtqdG_search{flex:1;min-width:160px}._6VtqdG_filterBar ._6VtqdG_formLabel{flex:none}._6VtqdG_filterBar ._6VtqdG_select{flex:none;max-width:150px}._6VtqdG_filterBar ._6VtqdG_segmented{flex:none}._6VtqdG_titleIcon{vertical-align:-2px;opacity:.8;margin-right:2px;display:inline-block}._6VtqdG_grow{flex:1}._6VtqdG_hintLine{color:var(--hub-text-3);margin:0;font-size:11.5px}._6VtqdG_hintPadded{margin:6px 12px 2px}._6VtqdG_hintInline{margin:4px 2px}._6VtqdG_rowMuted{cursor:default;opacity:.55}._6VtqdG_actionsPadded{padding:8px 12px}._6VtqdG_actionsTop{margin-top:8px}._6VtqdG_groupTime{margin-left:6px}._6VtqdG_sectionHeadRow{align-items:center;gap:8px;display:flex}._6VtqdG_sectionTitleFill{flex:1}._6VtqdG_dialogSelect{width:100%;margin-bottom:12px}._6VtqdG_dialogRow{align-items:center;gap:8px;display:flex}._6VtqdG_workspaceBox{align-items:center;gap:6px;display:inline-flex}._6VtqdG_workspaceInput{width:200px;padding:6px 10px;font-size:12px}._6VtqdG_projectNest{border-left:1px solid var(--dsw-alias-border-l1,#80808024);flex-direction:column;margin:2px 0 0 14px;display:flex}._6VtqdG_dragHandle{cursor:grab;opacity:.28;letter-spacing:0;user-select:none;flex:none;justify-content:center;align-self:center;align-items:center;width:8px;height:16px;padding:0 1px;font-size:10px;display:inline-flex;overflow:hidden}._6VtqdG_dragHandle:active{cursor:grabbing}._6VtqdG_dragging{opacity:.45}._6VtqdG_dragOver{outline:2px dashed var(--hub-accent);outline-offset:-2px;background:#2f81f712}._6VtqdG_scanList{border:.5px solid var(--hub-border-2);background:var(--hub-surface);border-radius:12px;max-height:360px;margin-top:8px;overflow:auto}._6VtqdG_scanProgressTrack{background:var(--hub-surface);border-radius:4px;flex:1;height:6px;overflow:hidden}._6VtqdG_scanProgressFill{background:var(--hub-accent);height:100%;transition:width .2s}._6VtqdG_filterPanel{background:var(--hub-surface);border-radius:10px;flex-wrap:wrap;align-items:center;gap:12px;padding:10px 12px;display:flex}._6VtqdG_filterField{align-items:center;gap:6px;display:inline-flex}._6VtqdG_filterField ._6VtqdG_formLabel{margin:0}._6VtqdG_filterField ._6VtqdG_select{max-width:150px}._6VtqdG_listTools{justify-content:flex-end;align-items:center;gap:8px;padding:0 2px;display:flex}._6VtqdG_opBtn:focus-visible,._6VtqdG_button:focus-visible,._6VtqdG_segBtn:focus-visible,._6VtqdG_disclosure:focus-visible,._6VtqdG_switch:focus-visible,._6VtqdG_legendToggle:focus-visible,._6VtqdG_back:focus-visible,._6VtqdG_statusWrap:focus-visible,._6VtqdG_input:focus-visible,._6VtqdG_select:focus-visible,._6VtqdG_search:focus-visible,._6VtqdG_sourceLink:focus-visible{outline:2px solid var(--hub-accent);outline-offset:2px}._6VtqdG_opBtn{padding:4px 12px}._6VtqdG_segBtn{padding:6px 13px}._6VtqdG_iconBtn,._6VtqdG_legendToggle{width:28px;height:28px}._6VtqdG_dragHandle{opacity:.45;width:16px}._6VtqdG_dragHandle:hover{opacity:1}._6VtqdG_skeleton{background:var(--hub-surface);border-radius:12px;flex-direction:column;gap:8px;padding:14px;display:flex}._6VtqdG_skeletonRow{background:var(--hub-skeleton);border-radius:7px;height:14px;animation:1.4s ease-in-out infinite _6VtqdG_hubPulse}._6VtqdG_skeletonRow:nth-child(2){width:82%}._6VtqdG_skeletonRow:nth-child(3){width:64%}@keyframes _6VtqdG_hubPulse{0%,to{opacity:.55}50%{opacity:1}}@media (prefers-reduced-motion:reduce){._6VtqdG_panel *,._6VtqdG_panel :before,._6VtqdG_panel :after{transition-duration:.01ms!important;animation-duration:.01ms!important;animation-iteration-count:1!important}}";
2857
+ const css = "._6VtqdG_panel{-webkit-font-smoothing:antialiased;--hub-model:#2f81f7;--hub-user:#3fb950;--hub-accent:var(--dsw-alias-state-business-primary,#2f81f7);--hub-text:var(--dsw-alias-label-primary,currentColor);--hub-text-2:var(--dsw-alias-label-secondary,#61666b);--hub-text-3:var(--dsw-alias-label-tertiary,#81858c);--hub-text-4:var(--dsw-alias-label-caption,#adb2b8);--hub-surface:var(--dsw-alias-bg-module-platform,#8080800f);--hub-hover:var(--dsw-alias-interactive-bg-hover,#80808014);--hub-active:var(--dsw-alias-interactive-bg-active,#80808029);--hub-border:var(--dsw-alias-border-l2,#80808021);--hub-border-2:var(--dsw-alias-border-l3,#80808033);--hub-danger:var(--dsw-alias-state-error-primary,#d1242f);--hub-success:var(--dsw-alias-state-success-primary,#3fb950);--hub-warn:var(--dsw-alias-state-warn-primary,#d29922);--hub-on-accent:var(--dsw-alias-label-primary-foreground,#fff);--hub-skeleton:var(--dsw-alias-bg-skeleton,#8080801a);flex-direction:column;gap:14px;max-width:720px;margin:0 auto;padding:28px 20px 44px;font-family:-apple-system,BlinkMacSystemFont,SF Pro Text,Helvetica Neue,sans-serif;display:flex}._6VtqdG_header{flex-wrap:wrap;align-items:baseline;gap:10px;display:flex}._6VtqdG_title{letter-spacing:-.02em;margin:0;font-size:24px;font-weight:700}._6VtqdG_hint{color:var(--hub-text-3);font-size:12px}._6VtqdG_actions{gap:8px;margin-left:auto;display:flex}._6VtqdG_segmented{background:var(--hub-hover);border-radius:9px;gap:2px;padding:2px;display:flex}._6VtqdG_segBtn{color:var(--hub-text-2);cursor:pointer;background:0 0;border:none;border-radius:7px;padding:5px 13px;font-size:12px;transition:background .15s,opacity .15s}._6VtqdG_segBtn:hover{color:var(--hub-text)}._6VtqdG_segBtnActive{background:var(--hub-active);opacity:1;font-weight:600}._6VtqdG_search{background:var(--hub-surface);width:100%;color:inherit;border:none;border-radius:10px;outline:none;padding:10px 14px;font-size:13px;transition:background .15s}._6VtqdG_search::placeholder{opacity:.45}._6VtqdG_search:focus{background:var(--hub-active)}._6VtqdG_section{background:var(--hub-surface);border-radius:12px;flex-direction:column;margin-top:4px;display:flex;overflow:hidden;box-shadow:0 1px 2px #00000008,0 4px 12px #0000000a}._6VtqdG_sectionTitle{margin:14px 16px 2px;font-size:13px;font-weight:700}._6VtqdG_groupHead{box-sizing:border-box;align-items:center;gap:8px;min-height:44px;padding:10px 14px;display:flex}._6VtqdG_groupTitle{color:var(--hub-text);flex:1;align-items:center;gap:6px;min-width:0;font-size:13px;font-weight:600;line-height:1;display:inline-flex}._6VtqdG_groupOps{flex-wrap:wrap;flex:none;align-items:center;gap:6px;display:inline-flex}._6VtqdG_opBtn{background:var(--hub-hover);color:inherit;cursor:pointer;border:none;border-radius:999px;padding:3px 11px;font-size:11px;transition:background .15s}._6VtqdG_opBtn:hover{background:var(--hub-active)}._6VtqdG_opBtn:disabled{opacity:.4;cursor:default}._6VtqdG_row{cursor:pointer;background:0 0;align-items:center;gap:12px;padding:10px 14px;transition:background .12s;display:flex}._6VtqdG_row:hover{background:var(--hub-hover)}._6VtqdG_row:focus-visible{outline:2px solid var(--hub-accent);outline-offset:-2px}._6VtqdG_rowStatic{cursor:default}._6VtqdG_rowStatic:hover{background:0 0}._6VtqdG_row+._6VtqdG_row{border-top:.5px solid var(--hub-border)}._6VtqdG_rowMain{flex:1;min-width:0}._6VtqdG_rowName{align-items:center;gap:5px;font-size:13.5px;display:flex}._6VtqdG_rowNameText{font-weight:600}._6VtqdG_rowDesc{color:var(--hub-text-3);white-space:nowrap;text-overflow:ellipsis;margin-top:1px;font-size:12.5px;overflow:hidden}._6VtqdG_badges{flex:none;align-items:center;gap:6px;display:flex}._6VtqdG_badge{border:.5px solid var(--hub-border-2);color:var(--hub-text-2);white-space:nowrap;border-radius:999px;padding:1px 7px;font-size:10.5px}._6VtqdG_badgeReadonly{opacity:.5}._6VtqdG_switch{border:1px solid var(--hub-border-2);background:var(--dsw-alias-bg-module-platform,#8080804d);cursor:pointer;border-radius:999px;flex:none;width:36px;height:21px;padding:2px;transition:background .18s}._6VtqdG_switch:disabled{opacity:.5;cursor:default}._6VtqdG_switchOn{background:var(--dsw-alias-state-business-primary,#34c759)}._6VtqdG_switchThumb{background:#fff;border-radius:50%;width:17px;height:17px;transition:transform .18s;display:block;transform:translate(0);box-shadow:0 1px 2px #00000040}._6VtqdG_switchOn ._6VtqdG_switchThumb{transform:translate(15px)}._6VtqdG_empty{color:var(--hub-text-3);text-align:center;padding:20px 0;font-size:13px}._6VtqdG_diagRow{border-left:3px solid var(--hub-warn);background:#d299220f;padding:9px 14px;font-size:12px}._6VtqdG_diagRowBlock{border-left-color:var(--hub-danger);background:#d1242f0f}._6VtqdG_auditBadge{color:var(--hub-danger);vertical-align:1px;background:#d1242f1f;border-radius:4px;margin-right:6px;padding:0 5px;font-size:11px;font-weight:700;display:inline-block}._6VtqdG_diagPath{color:var(--hub-text-2);word-break:break-all;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px}._6VtqdG_diagReason{color:var(--hub-text-3);margin-top:1px}._6VtqdG_updateLink{color:inherit;font-weight:600;text-decoration:underline}._6VtqdG_errorBanner{color:var(--hub-danger);white-space:pre-wrap;word-break:break-all;background:#d1242f12;border-radius:10px;align-items:flex-start;gap:10px;padding:10px 14px;font-size:12.5px;display:flex}._6VtqdG_successBanner{color:var(--hub-success);white-space:pre-wrap;word-break:break-all;background:#3fb95014;border-radius:10px;align-items:flex-start;gap:10px;padding:10px 14px;font-size:12.5px;display:flex}._6VtqdG_detailHead{flex-wrap:wrap;align-items:center;gap:10px;display:flex}._6VtqdG_back{background:var(--hub-hover);color:inherit;cursor:pointer;border:none;border-radius:8px;padding:6px 12px;font-size:12.5px}._6VtqdG_back:hover{background:var(--hub-active)}._6VtqdG_detailName{letter-spacing:-.01em;font-size:19px;font-weight:700}._6VtqdG_detailMeta{color:var(--hub-text-3);flex-direction:column;gap:4px;font-size:12px;display:flex}._6VtqdG_detailMetaLine{word-break:break-all}._6VtqdG_detailContent{white-space:pre-wrap;word-break:break-word;background:var(--hub-surface);border-radius:12px;max-height:62vh;padding:14px 16px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:1.6;overflow:auto}._6VtqdG_form{background:var(--hub-surface);border-radius:12px;flex-direction:column;gap:10px;padding:14px 16px;display:flex;box-shadow:0 1px 2px #00000008,0 4px 12px #0000000a}._6VtqdG_formRow{flex-direction:column;gap:5px;display:flex}._6VtqdG_formLabel{color:var(--hub-text-3);font-size:12px}._6VtqdG_input,._6VtqdG_select{background:var(--hub-surface);color:inherit;border:none;border-radius:9px;outline:none;padding:9px 12px;font-size:13px}._6VtqdG_input:focus,._6VtqdG_select:focus{background:var(--hub-active)}._6VtqdG_buttons{align-items:center;gap:8px;display:flex}._6VtqdG_button{cursor:pointer;background:var(--hub-hover);color:inherit;border:none;border-radius:8px;padding:6px 13px;font-size:12.5px;transition:background .15s}._6VtqdG_button:hover{background:var(--hub-active)}._6VtqdG_primary{background:var(--hub-accent);color:var(--hub-on-accent)}._6VtqdG_primary:hover{background:var(--hub-accent);opacity:.92}._6VtqdG_primary:disabled{opacity:.45;cursor:default}._6VtqdG_danger{background:var(--hub-danger);color:var(--hub-on-accent)}._6VtqdG_danger:hover{background:var(--hub-danger);opacity:.92}._6VtqdG_danger:disabled{opacity:.45;cursor:default}._6VtqdG_formError{color:var(--hub-danger)}._6VtqdG_formSuccess{color:var(--hub-success)}._6VtqdG_dot{vertical-align:middle;border-radius:50%;width:7px;height:7px;margin-left:5px;display:inline-block}._6VtqdG_dotModel{background:var(--hub-model)}._6VtqdG_dotUser{background:var(--hub-user)}._6VtqdG_displayName{color:var(--hub-text-3);white-space:nowrap;text-overflow:ellipsis;flex-shrink:1;min-width:0;max-width:160px;margin-left:6px;font-size:11px;font-weight:400;overflow:hidden}._6VtqdG_legend{color:var(--hub-text-3);flex-wrap:wrap;align-items:center;gap:12px;padding:2px 2px 0;font-size:11.5px;display:flex}._6VtqdG_legendItem{align-items:center;gap:4px;display:inline-flex}._6VtqdG_legendItem ._6VtqdG_dot{margin-left:0}._6VtqdG_legendHint{opacity:.8}._6VtqdG_badgeSource,._6VtqdG_badgeCount{background:var(--hub-hover);opacity:.72;border:none}._6VtqdG_disclosure{min-width:0;color:inherit;cursor:pointer;text-align:left;background:0 0;border:none;flex:1;align-items:center;gap:7px;min-height:24px;padding:2px 0;display:flex}._6VtqdG_disclosure:hover ._6VtqdG_groupTitle{opacity:1}._6VtqdG_chevron{opacity:.55;border-bottom:1.5px solid;border-right:1.5px solid;flex:none;align-self:center;width:8px;height:8px;margin-right:2px;transition:transform .15s;transform:rotate(45deg)translateY(-1px)}._6VtqdG_chevronCollapsed{transform:rotate(-45deg)translateY(-1px)}._6VtqdG_headerCount{color:var(--hub-text-3);white-space:nowrap;margin-left:2px;font-size:12px}._6VtqdG_pluginVersion{color:var(--hub-text-4);white-space:nowrap;font-variant-numeric:tabular-nums;margin-left:6px;font-size:12px;font-weight:500}._6VtqdG_subbar{flex-wrap:wrap;align-items:center;gap:8px;display:flex}._6VtqdG_legendToggle{background:var(--hub-hover);width:22px;height:22px;color:inherit;cursor:pointer;opacity:.55;border:none;border-radius:50%;flex:none;font-size:12px;line-height:1;transition:opacity .15s,background .15s}._6VtqdG_legendToggle:hover{opacity:1}._6VtqdG_legendToggleActive{opacity:1;background:var(--hub-active)}._6VtqdG_filterBar{flex-wrap:wrap;align-items:center;gap:8px;display:flex}._6VtqdG_filterBar ._6VtqdG_formLabel{margin:0}._6VtqdG_useCount{color:var(--hub-warn);vertical-align:1px;background:#d299221f;border-radius:999px;margin-left:6px;padding:0 6px;font-size:11px;font-weight:700;line-height:1.6;display:inline-block}._6VtqdG_useTime{color:var(--hub-text-4);white-space:nowrap;margin-left:auto;font-size:11px}._6VtqdG_switchMixed{background:#2f81f773;background:color-mix(in srgb, var(--hub-accent) 45%, transparent)}._6VtqdG_switchMixed ._6VtqdG_switchThumb{transform:translate(7.5px);box-shadow:0 1px 2px #00000040}._6VtqdG_groupTitleInner{align-items:baseline;display:inline-flex}._6VtqdG_sourceLink{color:inherit;opacity:.9;border-bottom:1px dotted;font-weight:600;text-decoration:none}._6VtqdG_sourceLink:hover{opacity:1}._6VtqdG_statusBadges{flex:none;align-items:center;gap:4px;display:inline-flex}._6VtqdG_statusBadge{border:.5px solid var(--hub-border-2);opacity:.8;white-space:nowrap;background:var(--hub-hover);border-radius:999px;padding:1px 7px;font-size:10.5px}._6VtqdG_statusOk{color:var(--hub-success);background:0 0;border-color:currentColor}._6VtqdG_statusUpdated{color:var(--hub-warn);background:#d2992214;border-color:currentColor}._6VtqdG_statusError{color:var(--hub-danger);background:#d1242f14;border-color:currentColor}._6VtqdG_statusLocal{color:var(--hub-accent);background:#2f81f714;border-color:currentColor}._6VtqdG_statusWrap{cursor:pointer;background:0 0;border:none;align-items:center;gap:4px;padding:0;font-family:inherit;display:inline-flex}._6VtqdG_statusWrap:hover ._6VtqdG_statusBadge{opacity:1}._6VtqdG_statusButton{cursor:pointer;font-family:inherit}._6VtqdG_statusButton:hover{opacity:1}._6VtqdG_opDanger{color:var(--hub-danger);background:#d1242f1a}._6VtqdG_opDanger:hover{background:#d1242f2e}._6VtqdG_iconBtn{border-radius:999px;justify-content:center;align-items:center;width:24px;height:24px;padding:0;display:inline-flex}._6VtqdG_sourceCard{background:var(--hub-surface);border-radius:12px;flex-direction:column;gap:4px;padding:12px 14px;font-size:12px;display:flex}._6VtqdG_sourceCardTitle{flex-wrap:wrap;align-items:center;gap:8px;display:flex}._6VtqdG_dialogOverlay{z-index:50;-webkit-backdrop-filter:blur(2px);background:#00000059;justify-content:center;align-items:center;padding:24px;display:flex;position:fixed;inset:0}._6VtqdG_dialog{background:var(--dsw-alias-bg-layer-1,#f5f5f7);min-width:min(320px,100%);max-width:380px;color:var(--dsw-alias-label-primary,#1d1d1f);border-radius:14px;padding:18px 18px 14px;box-shadow:0 12px 40px #00000047,0 2px 8px #00000029}._6VtqdG_dialogTitle{letter-spacing:-.01em;margin:0 0 8px;font-size:15px;font-weight:700}._6VtqdG_dialogText{color:var(--hub-text-3);margin:0 0 10px;font-size:12.5px;line-height:1.5}._6VtqdG_dialogList{flex-direction:column;gap:5px;max-height:200px;margin:0 0 14px;padding:0;list-style:none;display:flex;overflow:auto}._6VtqdG_dialogList li{opacity:.85;word-break:break-all;font-size:12.5px}._6VtqdG_dialogActions{justify-content:flex-end;gap:8px;display:flex}._6VtqdG_filterBar ._6VtqdG_search{flex:1;min-width:160px}._6VtqdG_filterBar ._6VtqdG_formLabel{flex:none}._6VtqdG_filterBar ._6VtqdG_select{flex:none;max-width:150px}._6VtqdG_filterBar ._6VtqdG_segmented{flex:none}._6VtqdG_titleIcon{vertical-align:-2px;opacity:.8;margin-right:2px;display:inline-block}._6VtqdG_grow{flex:1}._6VtqdG_hintLine{color:var(--hub-text-3);margin:0;font-size:11.5px}._6VtqdG_hintPadded{margin:6px 12px 2px}._6VtqdG_hintInline{margin:4px 2px}._6VtqdG_rowMuted{cursor:default;opacity:.55}._6VtqdG_actionsPadded{padding:8px 12px}._6VtqdG_actionsTop{margin-top:8px}._6VtqdG_groupTime{margin-left:6px}._6VtqdG_sectionHeadRow{align-items:center;gap:8px;display:flex}._6VtqdG_sectionTitleFill{flex:1}._6VtqdG_dialogSelect{width:100%;margin-bottom:12px}._6VtqdG_dialogRow{align-items:center;gap:8px;display:flex}._6VtqdG_workspaceBox{align-items:center;gap:6px;display:inline-flex}._6VtqdG_workspaceInput{width:200px;padding:6px 10px;font-size:12px}._6VtqdG_projectNest{border-left:1px solid var(--dsw-alias-border-l1,#80808024);flex-direction:column;margin:2px 0 0 14px;display:flex}._6VtqdG_dragHandle{cursor:grab;opacity:.28;letter-spacing:0;user-select:none;flex:none;justify-content:center;align-self:center;align-items:center;width:8px;height:16px;padding:0 1px;font-size:10px;display:inline-flex;overflow:hidden}._6VtqdG_dragHandle:active{cursor:grabbing}._6VtqdG_dragging{opacity:.45}._6VtqdG_dragOver{outline:2px dashed var(--hub-accent);outline-offset:-2px;background:#2f81f712}._6VtqdG_scanList{border:.5px solid var(--hub-border-2);background:var(--hub-surface);border-radius:12px;max-height:360px;margin-top:8px;overflow:auto}._6VtqdG_scanProgressTrack{background:var(--hub-surface);border-radius:4px;flex:1;height:6px;overflow:hidden}._6VtqdG_scanProgressFill{background:var(--hub-accent);height:100%;transition:width .2s}._6VtqdG_filterPanel{background:var(--hub-surface);border-radius:10px;flex-wrap:wrap;align-items:center;gap:12px;padding:10px 12px;display:flex}._6VtqdG_filterField{align-items:center;gap:6px;display:inline-flex}._6VtqdG_filterField ._6VtqdG_formLabel{margin:0}._6VtqdG_filterField ._6VtqdG_select{max-width:150px}._6VtqdG_listTools{justify-content:flex-end;align-items:center;gap:8px;padding:0 2px;display:flex}._6VtqdG_opBtn:focus-visible,._6VtqdG_button:focus-visible,._6VtqdG_segBtn:focus-visible,._6VtqdG_disclosure:focus-visible,._6VtqdG_switch:focus-visible,._6VtqdG_legendToggle:focus-visible,._6VtqdG_back:focus-visible,._6VtqdG_statusWrap:focus-visible,._6VtqdG_input:focus-visible,._6VtqdG_select:focus-visible,._6VtqdG_search:focus-visible,._6VtqdG_sourceLink:focus-visible{outline:2px solid var(--hub-accent);outline-offset:2px}._6VtqdG_opBtn{padding:4px 12px}._6VtqdG_segBtn{padding:6px 13px}._6VtqdG_iconBtn,._6VtqdG_legendToggle{width:28px;height:28px}._6VtqdG_dragHandle{opacity:.45;width:16px}._6VtqdG_dragHandle:hover{opacity:1}._6VtqdG_skeleton{background:var(--hub-surface);border-radius:12px;flex-direction:column;gap:8px;padding:14px;display:flex}._6VtqdG_skeletonRow{background:var(--hub-skeleton);border-radius:7px;height:14px;animation:1.4s ease-in-out infinite _6VtqdG_hubPulse}._6VtqdG_skeletonRow:nth-child(2){width:82%}._6VtqdG_skeletonRow:nth-child(3){width:64%}@keyframes _6VtqdG_hubPulse{0%,to{opacity:.55}50%{opacity:1}}@media (prefers-reduced-motion:reduce){._6VtqdG_panel *,._6VtqdG_panel :before,._6VtqdG_panel :after{transition-duration:.01ms!important;animation-duration:.01ms!important;animation-iteration-count:1!important}}";
2813
2858
  const tagId = "dsh-skill-hub/panel.module.css";
2814
2859
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
2815
2860
  const tag = document.createElement("style");
@@ -2822,6 +2867,7 @@ window.__ModuleLoader__.load({
2822
2867
  "actions": "_6VtqdG_actions",
2823
2868
  "actionsPadded": "_6VtqdG_actionsPadded",
2824
2869
  "actionsTop": "_6VtqdG_actionsTop",
2870
+ "auditBadge": "_6VtqdG_auditBadge",
2825
2871
  "back": "_6VtqdG_back",
2826
2872
  "badge": "_6VtqdG_badge",
2827
2873
  "badgeCount": "_6VtqdG_badgeCount",
@@ -2841,6 +2887,7 @@ window.__ModuleLoader__.load({
2841
2887
  "diagPath": "_6VtqdG_diagPath",
2842
2888
  "diagReason": "_6VtqdG_diagReason",
2843
2889
  "diagRow": "_6VtqdG_diagRow",
2890
+ "diagRowBlock": "_6VtqdG_diagRowBlock",
2844
2891
  "dialog": "_6VtqdG_dialog",
2845
2892
  "dialogActions": "_6VtqdG_dialogActions",
2846
2893
  "dialogList": "_6VtqdG_dialogList",
@@ -2922,6 +2969,7 @@ window.__ModuleLoader__.load({
2922
2969
  "statusBadges": "_6VtqdG_statusBadges",
2923
2970
  "statusButton": "_6VtqdG_statusButton",
2924
2971
  "statusError": "_6VtqdG_statusError",
2972
+ "statusLocal": "_6VtqdG_statusLocal",
2925
2973
  "statusOk": "_6VtqdG_statusOk",
2926
2974
  "statusUpdated": "_6VtqdG_statusUpdated",
2927
2975
  "statusWrap": "_6VtqdG_statusWrap",
@@ -2957,41 +3005,48 @@ window.__ModuleLoader__.load({
2957
3005
  children: tt("source.check")
2958
3006
  });
2959
3007
  }
2960
- const badges = (() => {
2961
- if (check.error !== void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3008
+ const items = (() => {
3009
+ if (check.error !== void 0) return [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2962
3010
  className: panel_module_css_default.statusBadge + " " + panel_module_css_default.statusError,
2963
3011
  children: tt("source.error")
2964
- });
2965
- if (check.throttled === true) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3012
+ }, "error")];
3013
+ if (check.throttled === true) return [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2966
3014
  className: panel_module_css_default.statusBadge,
2967
3015
  children: tt("source.throttled")
2968
- });
2969
- if (check.unverified === true) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3016
+ }, "throttled")];
3017
+ if (check.unverified === true) return [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2970
3018
  className: panel_module_css_default.statusBadge,
2971
3019
  children: tt("source.unverified")
2972
- });
2973
- if (check.changed) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2974
- className: panel_module_css_default.statusBadges,
2975
- children: [check.updated.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2976
- className: panel_module_css_default.statusBadge + " " + panel_module_css_default.statusUpdated,
2977
- children: tt("source.updated", { count: check.updated.length })
2978
- }) : null, check.deleted.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2979
- className: panel_module_css_default.statusBadge + " " + panel_module_css_default.statusError,
2980
- children: tt("source.deleted", { count: check.deleted.length })
2981
- }) : null]
2982
- });
2983
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3020
+ }, "unverified")];
3021
+ if (check.changed) return [...check.updated.length > 0 ? [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3022
+ className: panel_module_css_default.statusBadge + " " + panel_module_css_default.statusUpdated,
3023
+ children: tt("source.updated", { count: check.updated.length })
3024
+ }, "updated")] : [], ...check.deleted.length > 0 ? [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3025
+ className: panel_module_css_default.statusBadge + " " + panel_module_css_default.statusError,
3026
+ children: tt("source.deleted", { count: check.deleted.length })
3027
+ }, "deleted")] : []];
3028
+ return [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2984
3029
  className: panel_module_css_default.statusBadge + " " + panel_module_css_default.statusOk,
2985
3030
  children: tt("source.upToDate")
2986
- });
3031
+ }, "ok")];
2987
3032
  })();
2988
- if (onCheck === void 0) return badges;
3033
+ const modified = check.localModified ?? [];
3034
+ if (modified.length > 0) items.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3035
+ className: panel_module_css_default.statusBadge + " " + panel_module_css_default.statusLocal,
3036
+ title: tt("source.localModifiedHint") + "\n" + modified.join(", "),
3037
+ children: tt("source.localModified", { count: modified.length })
3038
+ }, "local"));
3039
+ const combined = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3040
+ className: panel_module_css_default.statusBadges,
3041
+ children: items
3042
+ });
3043
+ if (onCheck === void 0) return combined;
2989
3044
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2990
3045
  type: "button",
2991
3046
  className: panel_module_css_default.statusWrap,
2992
3047
  title: tt("source.checkHint"),
2993
3048
  onClick: onCheck,
2994
- children: badges
3049
+ children: combined
2995
3050
  });
2996
3051
  }
2997
3052
  //#endregion
@@ -4338,7 +4393,8 @@ window.__ModuleLoader__.load({
4338
4393
  }
4339
4394
  /** Simple confirm dialog: title + text + optional skill list + cancel/confirm. */
4340
4395
  function ConfirmDialog(props) {
4341
- const { title, text, items, confirmLabel, danger, onCancel, onConfirm } = props;
4396
+ const { title, text, items, marked, confirmLabel, danger, onCancel, onConfirm } = props;
4397
+ const markedSet = new Set(marked ?? []);
4342
4398
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(DialogShell, {
4343
4399
  onClose: onCancel,
4344
4400
  children: [
@@ -4352,10 +4408,14 @@ window.__ModuleLoader__.load({
4352
4408
  }),
4353
4409
  items !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
4354
4410
  className: panel_module_css_default.dialogList,
4355
- children: items.map((name) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4411
+ children: items.map((name) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4356
4412
  className: panel_module_css_default.rowNameText,
4357
4413
  children: name
4358
- }) }, name))
4414
+ }), markedSet.has(name) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4415
+ className: panel_module_css_default.statusBadge + " " + panel_module_css_default.statusLocal,
4416
+ style: { marginLeft: 6 },
4417
+ children: tt("source.localModifiedBadge")
4418
+ }) : null] }, name))
4359
4419
  }) : null,
4360
4420
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4361
4421
  className: panel_module_css_default.dialogActions,
@@ -5349,7 +5409,7 @@ window.__ModuleLoader__.load({
5349
5409
  //#endregion
5350
5410
  //#region src/client/panel/PanelDialogs.tsx
5351
5411
  function PanelDialogs(props) {
5352
- const { conflictDialog, tags, collections, setConflictDialog, resolveConflict, confirmDialog, setConfirmDialog, runConfirmed, branchChoice, branchBusy, setBranchChoice, confirmBranchChoice, versionDialog, versionBusy, setVersionDialog, confirmVersionDialog, marketSyncDialog, syncBusy, setMarketSyncDialog, confirmMarketSync, deleteSkillDialog, setDeleteSkillDialog, runDeleteSkill, deleteGroupDialog, setDeleteGroupDialog, runDeleteGroup, confirmClearTrash, setConfirmClearTrash, clearTrash } = props;
5412
+ const { conflictDialog, tags, collections, setConflictDialog, resolveConflict, confirmDialog, setConfirmDialog, runConfirmed, sourceCheck, branchChoice, branchBusy, setBranchChoice, confirmBranchChoice, versionDialog, versionBusy, setVersionDialog, confirmVersionDialog, marketSyncDialog, syncBusy, setMarketSyncDialog, confirmMarketSync, deleteSkillDialog, setDeleteSkillDialog, runDeleteSkill, deleteGroupDialog, setDeleteGroupDialog, runDeleteGroup, confirmClearTrash, setConfirmClearTrash, clearTrash } = props;
5353
5413
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
5354
5414
  conflictDialog !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConflictDialog, {
5355
5415
  dialog: conflictDialog,
@@ -5369,6 +5429,7 @@ window.__ModuleLoader__.load({
5369
5429
  title: confirmDialog.kind === "sync" ? tt("source.syncConfirmTitle") : tt("source.deleteConfirmTitle"),
5370
5430
  text: confirmDialog.kind === "sync" ? tt("source.syncConfirmText") : tt("source.deleteConfirmText"),
5371
5431
  items: confirmDialog.skills,
5432
+ ...confirmDialog.kind === "sync" ? { marked: sourceCheck[confirmDialog.repo]?.localModified ?? [] } : {},
5372
5433
  confirmLabel: confirmDialog.kind === "sync" ? tt("source.sync") : tt("source.followDelete"),
5373
5434
  danger: confirmDialog.kind === "delete",
5374
5435
  onCancel: () => {
@@ -5479,6 +5540,169 @@ window.__ModuleLoader__.load({
5479
5540
  ] });
5480
5541
  }
5481
5542
  //#endregion
5543
+ //#region src/client/panel/ForeignImportDialog.tsx
5544
+ /**
5545
+ * 从其他 agent 导入:列出 Claude Code / Codex / Cursor / Gemini CLI 等技能目录里的
5546
+ * 技能,勾选后复制到本地可写根。
5547
+ *
5548
+ * 只读扫描 + 复制,不改动别家目录。已存在的同名技能不可选(导入会覆盖,
5549
+ * 那是用户在别处没预期的事)。
5550
+ */
5551
+ /** 一个技能在一组里的稳定键(同名技能可来自不同 agent)。 */
5552
+ function keyOf(skill) {
5553
+ return skill.agent + "/" + skill.name;
5554
+ }
5555
+ function ForeignImportDialog(props) {
5556
+ const { api, onClose, onImported } = props;
5557
+ const [skills, setSkills] = (0, react.useState)(null);
5558
+ const [error, setError] = (0, react.useState)(null);
5559
+ const [selected, setSelected] = (0, react.useState)(/* @__PURE__ */ new Set());
5560
+ const [busy, setBusy] = (0, react.useState)(false);
5561
+ const [message, setMessage] = (0, react.useState)(null);
5562
+ (0, react.useEffect)(() => {
5563
+ let alive = true;
5564
+ (async () => {
5565
+ try {
5566
+ const result = await api.listForeignSkills();
5567
+ if (alive) setSkills(result.skills);
5568
+ } catch (caught) {
5569
+ if (alive) setError(errorMessage(caught));
5570
+ }
5571
+ })();
5572
+ return () => {
5573
+ alive = false;
5574
+ };
5575
+ }, [api]);
5576
+ const toggle = (skill) => {
5577
+ if (skill.existing || busy) return;
5578
+ const next = new Set(selected);
5579
+ const key = keyOf(skill);
5580
+ if (next.has(key)) next.delete(key);
5581
+ else next.add(key);
5582
+ setSelected(next);
5583
+ };
5584
+ const run = async () => {
5585
+ if (selected.size === 0 || skills === null) return;
5586
+ setBusy(true);
5587
+ setError(null);
5588
+ setMessage(null);
5589
+ try {
5590
+ const items = skills.filter((skill) => selected.has(keyOf(skill))).map((skill) => ({
5591
+ agent: skill.agent,
5592
+ name: skill.name
5593
+ }));
5594
+ const result = await api.importForeignSkills(items);
5595
+ const replaced = result.replaced?.length ?? 0;
5596
+ if (result.failed.length > 0) {
5597
+ setError(result.failed.map((failure) => failure.name + ": " + failure.error).join("; "));
5598
+ if (result.imported.length > 0) onImported(result.imported, replaced);
5599
+ } else if (result.skipped.length > 0) {
5600
+ setMessage(tt("foreign.skipped", { count: result.skipped.length }));
5601
+ if (result.imported.length > 0) onImported(result.imported, replaced);
5602
+ } else {
5603
+ onImported(result.imported, replaced);
5604
+ onClose();
5605
+ }
5606
+ } catch (caught) {
5607
+ setError(errorMessage(caught));
5608
+ } finally {
5609
+ setBusy(false);
5610
+ }
5611
+ };
5612
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(DialogShell, {
5613
+ onClose,
5614
+ children: [
5615
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
5616
+ className: panel_module_css_default.dialogTitle,
5617
+ children: tt("foreign.title")
5618
+ }),
5619
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5620
+ className: panel_module_css_default.dialogText,
5621
+ children: tt("foreign.text")
5622
+ }),
5623
+ skills === null && error === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5624
+ className: panel_module_css_default.dialogText,
5625
+ children: tt("panel.loading")
5626
+ }) : null,
5627
+ skills !== null && skills.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5628
+ className: panel_module_css_default.dialogText,
5629
+ children: tt("foreign.empty")
5630
+ }) : null,
5631
+ skills !== null && skills.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
5632
+ className: panel_module_css_default.dialogList,
5633
+ style: {
5634
+ maxHeight: 320,
5635
+ overflowY: "auto"
5636
+ },
5637
+ children: skills.map((skill) => {
5638
+ const key = keyOf(skill);
5639
+ const disabled = skill.existing || busy;
5640
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
5641
+ style: {
5642
+ display: "flex",
5643
+ alignItems: "center",
5644
+ gap: 8,
5645
+ cursor: disabled ? "default" : "pointer"
5646
+ },
5647
+ children: [
5648
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
5649
+ type: "checkbox",
5650
+ disabled,
5651
+ checked: selected.has(key),
5652
+ onChange: () => {
5653
+ toggle(skill);
5654
+ }
5655
+ }),
5656
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5657
+ className: panel_module_css_default.rowNameText,
5658
+ children: skill.name
5659
+ }),
5660
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5661
+ className: panel_module_css_default.statusBadge,
5662
+ children: skill.agent
5663
+ }),
5664
+ skill.existing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5665
+ className: panel_module_css_default.statusBadge + " " + panel_module_css_default.statusLocal,
5666
+ children: tt("foreign.exists")
5667
+ }) : null
5668
+ ]
5669
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5670
+ className: panel_module_css_default.rowDesc,
5671
+ title: skill.description,
5672
+ children: skill.description
5673
+ })] }, key);
5674
+ })
5675
+ }) : null,
5676
+ message !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5677
+ className: panel_module_css_default.dialogText,
5678
+ children: message
5679
+ }) : null,
5680
+ error !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5681
+ className: panel_module_css_default.dialogText,
5682
+ style: { color: "var(--hub-danger)" },
5683
+ children: error
5684
+ }) : null,
5685
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5686
+ className: panel_module_css_default.dialogActions,
5687
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5688
+ type: "button",
5689
+ className: panel_module_css_default.button,
5690
+ onClick: onClose,
5691
+ children: tt("form.cancel")
5692
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5693
+ type: "button",
5694
+ className: panel_module_css_default.button + " " + panel_module_css_default.primary,
5695
+ disabled: selected.size === 0 || busy,
5696
+ onClick: () => {
5697
+ run();
5698
+ },
5699
+ children: busy ? tt("foreign.importing") : tt("foreign.import", { count: selected.size })
5700
+ })]
5701
+ })
5702
+ ]
5703
+ });
5704
+ }
5705
+ //#endregion
5482
5706
  //#region src/client/panel/hooks/shared.ts
5483
5707
  /**
5484
5708
  * 统一异步动作外壳:清错 → 执行 → 异常转错误条幅 → 收尾(忙碌开关)。
@@ -6949,7 +7173,8 @@ window.__ModuleLoader__.load({
6949
7173
  syncMarketSource: marketFlow.syncMarketSource,
6950
7174
  confirmMarketSync: marketFlow.confirmMarketSync,
6951
7175
  updateAll: marketFlow.updateAll,
6952
- create: catalogFlow.create
7176
+ create: catalogFlow.create,
7177
+ reloadCatalog: catalogFlow.load
6953
7178
  };
6954
7179
  }
6955
7180
  //#endregion
@@ -6972,9 +7197,11 @@ window.__ModuleLoader__.load({
6972
7197
  const hub = useSkillHub(props.api);
6973
7198
  /** 工作区输入草稿:回车才应用,避免每次按键都触发目录重拉。 */
6974
7199
  const [workspaceDraft, setWorkspaceDraft] = (0, react.useState)("");
7200
+ /** 「从其他 Agent 导入」弹窗开合。 */
7201
+ const [showForeign, setShowForeign] = (0, react.useState)(false);
6975
7202
  /** 「筛选」面板开合(来源 + 调用方式收进这里;搜索/排序/视图切换始终可见)。 */
6976
7203
  const [filtersOpen, setFiltersOpen] = (0, react.useState)(false);
6977
- const { catalog, loading, loadError, successBanner, updateState, detail, detailLoading, showForm, formName, formDesc, formRoot, formBusy, formMessage, hubConfig, tab, skillView, sourceFilter, sortKey, search, workspace, setWorkspace, sourcesState, tagBusy, batchBusy, sourceOptions, filtered, conflictDialog, confirmDialog, deleteSkillDialog, deleteGroupDialog, confirmClearTrash, branchChoice, branchBusy, marketSyncDialog, syncBusy, editingTag, editName, membersDraft, editSearch, uses, groupsState, sourceCheck, checkingSource, syncingSource, showLegend, editMode, setLoadError, setSuccessBanner, setDetail, setShowForm, setFormName, setFormDesc, setFormRoot, setFormMessage, setTab, setSkillView, setSourceFilter, setSortKey, setSearch, setConflictDialog, setConfirmDialog, setDeleteSkillDialog, setDeleteGroupDialog, setConfirmClearTrash, setBranchChoice, setMarketSyncDialog, setEditingTag, setEditName, setMembersDraft, setEditSearch, setShowLegend, setEditMode, checkUpdate, loadMarket, checkSources, requestSync, requestDelete, restoreTrash, clearTrash, runDeleteSkill, runDeleteGroup, runConfirmed, resolveConflict, confirmBranchChoice, confirmMarketSync, create, saveTag, deleteTag, enableDisabled } = hub;
7204
+ const { catalog, loading, loadError, successBanner, updateState, detail, detailLoading, showForm, formName, formDesc, formRoot, formBusy, formMessage, hubConfig, tab, skillView, sourceFilter, sortKey, search, workspace, setWorkspace, sourcesState, tagBusy, batchBusy, sourceOptions, filtered, conflictDialog, confirmDialog, deleteSkillDialog, deleteGroupDialog, confirmClearTrash, branchChoice, branchBusy, marketSyncDialog, syncBusy, editingTag, editName, membersDraft, editSearch, uses, groupsState, sourceCheck, checkingSource, syncingSource, showLegend, editMode, setLoadError, setSuccessBanner, setDetail, setShowForm, setFormName, setFormDesc, setFormRoot, setFormMessage, setTab, setSkillView, setSourceFilter, setSortKey, setSearch, setConflictDialog, setConfirmDialog, setDeleteSkillDialog, setDeleteGroupDialog, setConfirmClearTrash, setBranchChoice, setMarketSyncDialog, setEditingTag, setEditName, setMembersDraft, setEditSearch, setShowLegend, setEditMode, checkUpdate, loadMarket, checkSources, requestSync, requestDelete, restoreTrash, clearTrash, runDeleteSkill, runDeleteGroup, runConfirmed, resolveConflict, confirmBranchChoice, confirmMarketSync, create, saveTag, deleteTag, enableDisabled, reloadCatalog } = hub;
6978
7205
  const { shortenedCount, fixingPaths, clearListFilters } = hub;
6979
7206
  if (detail !== null) {
6980
7207
  const disabledRecord = catalog?.disabled.find((record) => record.name === detail.name);
@@ -7194,19 +7421,39 @@ window.__ModuleLoader__.load({
7194
7421
  title: tt("legend.hint"),
7195
7422
  children: "?"
7196
7423
  }),
7197
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7424
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7198
7425
  className: panel_module_css_default.actions,
7199
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7426
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7427
+ type: "button",
7428
+ className: panel_module_css_default.button,
7429
+ onClick: () => {
7430
+ setShowForeign(true);
7431
+ },
7432
+ children: tt("foreign.open")
7433
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7200
7434
  type: "button",
7201
7435
  className: panel_module_css_default.button + " " + panel_module_css_default.primary,
7202
7436
  onClick: () => {
7203
7437
  setShowForm((value) => !value);
7204
7438
  },
7205
7439
  children: tt("panel.new")
7206
- })
7440
+ })]
7207
7441
  })
7208
7442
  ]
7209
7443
  }),
7444
+ showForeign ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ForeignImportDialog, {
7445
+ api: props.api,
7446
+ onClose: () => {
7447
+ setShowForeign(false);
7448
+ },
7449
+ onImported: (imported, replaced) => {
7450
+ reloadCatalog();
7451
+ setSuccessBanner(tt(replaced > 0 ? "foreign.importedReplacedBanner" : "foreign.importedBanner", {
7452
+ count: imported.length,
7453
+ replaced
7454
+ }));
7455
+ }
7456
+ }) : null,
7210
7457
  showForm ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
7211
7458
  className: panel_module_css_default.form,
7212
7459
  onSubmit: (event) => {
@@ -7493,6 +7740,26 @@ window.__ModuleLoader__.load({
7493
7740
  children: tt("filter.shortened", { count: shortenedCount })
7494
7741
  }) : null]
7495
7742
  }) : null,
7743
+ catalog !== null && catalog.announcement !== void 0 && catalog.announcement.skills > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7744
+ className: panel_module_css_default.hintLine,
7745
+ style: {
7746
+ margin: "2px 2px 0",
7747
+ display: "flex",
7748
+ gap: 8,
7749
+ flexWrap: "wrap"
7750
+ },
7751
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7752
+ title: tt("panel.announcementHint", { budget: catalog.announcement.budget }),
7753
+ children: tt("panel.announcement", {
7754
+ chars: catalog.announcement.chars,
7755
+ tokens: catalog.announcement.approxTokens,
7756
+ skills: catalog.announcement.skills
7757
+ })
7758
+ }), catalog.announcement.overBudget ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7759
+ style: { color: "var(--hub-danger)" },
7760
+ children: tt("panel.announcementOver", { budget: catalog.announcement.budget })
7761
+ }) : null]
7762
+ }) : null,
7496
7763
  filtered.length === 0 && search.trim() !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7497
7764
  className: panel_module_css_default.empty,
7498
7765
  children: tt("panel.empty")
@@ -7545,8 +7812,8 @@ window.__ModuleLoader__.load({
7545
7812
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7546
7813
  className: panel_module_css_default.sectionTitle,
7547
7814
  children: tt("panel.diagnostics")
7548
- }), catalog.diagnostics.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7549
- className: panel_module_css_default.diagRow,
7815
+ }), catalog.diagnostics.map((entry, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7816
+ className: panel_module_css_default.diagRow + (entry.severity === "block" ? " " + panel_module_css_default.diagRowBlock : ""),
7550
7817
  style: {
7551
7818
  display: "flex",
7552
7819
  alignItems: "flex-start",
@@ -7557,9 +7824,12 @@ window.__ModuleLoader__.load({
7557
7824
  flex: 1,
7558
7825
  minWidth: 0
7559
7826
  },
7560
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7827
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7561
7828
  className: panel_module_css_default.diagPath,
7562
- children: entry.path
7829
+ children: [entry.kind === "security" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7830
+ className: panel_module_css_default.auditBadge,
7831
+ children: tt("panel.auditBadge")
7832
+ }) : null, entry.path]
7563
7833
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7564
7834
  className: panel_module_css_default.diagReason,
7565
7835
  children: entry.reason
@@ -7577,7 +7847,7 @@ window.__ModuleLoader__.load({
7577
7847
  },
7578
7848
  children: fixingPaths.has(entry.path) ? tt("diag.fixing") : tt("diag.fix")
7579
7849
  }) : null]
7580
- }, entry.path))]
7850
+ }, entry.path + "|" + String(index)))]
7581
7851
  }) : null
7582
7852
  ] }) : null,
7583
7853
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PanelDialogs, {
@@ -7589,6 +7859,7 @@ window.__ModuleLoader__.load({
7589
7859
  confirmDialog,
7590
7860
  setConfirmDialog,
7591
7861
  runConfirmed,
7862
+ sourceCheck,
7592
7863
  branchChoice,
7593
7864
  branchBusy,
7594
7865
  setBranchChoice,