@industry-theme/agent-panels 0.2.22 → 0.2.24

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.
@@ -2618,7 +2618,6 @@ const __iconNode = [
2618
2618
  ]
2619
2619
  ];
2620
2620
  const Zap = createLucideIcon("zap", __iconNode);
2621
- const EMPTY_SKILLS_ARRAY = [];
2622
2621
  const determineSkillSource = (path2) => {
2623
2622
  if (path2.includes(".agent/skills/")) {
2624
2623
  return { source: "project-universal", priority: 1 };
@@ -2758,15 +2757,15 @@ const parseSkillContent = async (content2, path2, fileTree, fileSystemAdapter, i
2758
2757
  }
2759
2758
  const structure = analyzeSkillStructure(fileTree, path2);
2760
2759
  const { source: source2, priority } = determineSkillSource(path2);
2761
- let metadata;
2760
+ let metadata = void 0;
2762
2761
  if (!isBrowserMode && fileSystemAdapter && structure.skillFolderPath) {
2763
2762
  try {
2764
2763
  const metadataPath = `${structure.skillFolderPath}/.metadata.json`;
2765
2764
  const metadataContent = await fileSystemAdapter.readFile(metadataPath);
2766
2765
  metadata = JSON.parse(metadataContent);
2767
- console.log("[useSkillsData] Loaded metadata for skill:", skillDirName, metadata);
2766
+ console.log("[skillsUtils] Loaded metadata for skill:", skillDirName, metadata);
2768
2767
  } catch (error) {
2769
- console.debug("[useSkillsData] No metadata file for skill:", skillDirName);
2768
+ console.debug("[skillsUtils] No metadata file for skill:", skillDirName);
2770
2769
  }
2771
2770
  }
2772
2771
  const frontmatterValidation = validateFrontmatter(content2);
@@ -2785,6 +2784,7 @@ const parseSkillContent = async (content2, path2, fileTree, fileSystemAdapter, i
2785
2784
  frontmatterValidation
2786
2785
  };
2787
2786
  };
2787
+ const EMPTY_SKILLS_ARRAY$1 = [];
2788
2788
  const getDeduplicationKey = (skill) => {
2789
2789
  var _a, _b, _c;
2790
2790
  if (((_a = skill.metadata) == null ? void 0 : _a.owner) && ((_b = skill.metadata) == null ? void 0 : _b.repo) && ((_c = skill.metadata) == null ? void 0 : _c.skillPath)) {
@@ -2859,14 +2859,14 @@ const useSkillsData = ({
2859
2859
  context
2860
2860
  }) => {
2861
2861
  var _a, _b, _c;
2862
- const [skills, setSkills] = useState(EMPTY_SKILLS_ARRAY);
2862
+ const [skills, setSkills] = useState(EMPTY_SKILLS_ARRAY$1);
2863
2863
  const [isLoading, setIsLoading] = useState(true);
2864
2864
  const [error, setError] = useState(null);
2865
2865
  const fileTreeSlice = context.getSlice("fileTree");
2866
2866
  const fileTree = fileTreeSlice == null ? void 0 : fileTreeSlice.data;
2867
2867
  const fileTreeSha = fileTree == null ? void 0 : fileTree.sha;
2868
2868
  const globalSkillsSlice = context.getSlice("globalSkills");
2869
- const globalSkills = ((_a = globalSkillsSlice == null ? void 0 : globalSkillsSlice.data) == null ? void 0 : _a.skills) ?? EMPTY_SKILLS_ARRAY;
2869
+ const globalSkills = ((_a = globalSkillsSlice == null ? void 0 : globalSkillsSlice.data) == null ? void 0 : _a.skills) ?? EMPTY_SKILLS_ARRAY$1;
2870
2870
  const globalSkillsCount = globalSkills.length;
2871
2871
  const repoPath = (_b = context.currentScope.repository) == null ? void 0 : _b.path;
2872
2872
  const fileSystem = (_c = context.adapters) == null ? void 0 : _c.fileSystem;
@@ -3002,16 +3002,35 @@ const abbreviateSourceName = (source2) => {
3002
3002
  const SkillCard = ({
3003
3003
  skill,
3004
3004
  onClick,
3005
- isSelected = false
3005
+ isSelected = false,
3006
+ filterContext
3006
3007
  }) => {
3007
3008
  var _a, _b, _c, _d, _e2, _f, _g, _h;
3008
3009
  const { theme: theme2 } = useTheme();
3009
3010
  const sourceConfig = getSourceConfig$1(skill.source);
3010
3011
  const [pathCopied, setPathCopied] = React2__default.useState(false);
3012
+ const getPathToCopy = () => {
3013
+ if (!filterContext || !skill.installedLocations || skill.installedLocations.length <= 1) {
3014
+ return skill.path;
3015
+ }
3016
+ if (filterContext === "project") {
3017
+ const projectInstallation = skill.installedLocations.find(
3018
+ (loc) => loc.source === "project-universal" || loc.source === "project-claude" || loc.source === "project-other"
3019
+ );
3020
+ return (projectInstallation == null ? void 0 : projectInstallation.path) || skill.path;
3021
+ } else if (filterContext === "global") {
3022
+ const globalInstallation = skill.installedLocations.find(
3023
+ (loc) => loc.source === "global-universal" || loc.source === "global-claude"
3024
+ );
3025
+ return (globalInstallation == null ? void 0 : globalInstallation.path) || skill.path;
3026
+ }
3027
+ return skill.path;
3028
+ };
3011
3029
  const handleCopyPath = async (e) => {
3012
3030
  e.stopPropagation();
3013
3031
  try {
3014
- await navigator.clipboard.writeText(skill.path);
3032
+ const pathToCopy = getPathToCopy();
3033
+ await navigator.clipboard.writeText(pathToCopy);
3015
3034
  setPathCopied(true);
3016
3035
  setTimeout(() => setPathCopied(false), 2e3);
3017
3036
  } catch (err) {
@@ -3068,7 +3087,7 @@ const SkillCard = ({
3068
3087
  }
3069
3088
  ),
3070
3089
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "4px", alignItems: "center", flexWrap: "wrap" }, children: [
3071
- /* @__PURE__ */ jsxs(
3090
+ !filterContext && /* @__PURE__ */ jsxs(
3072
3091
  "div",
3073
3092
  {
3074
3093
  style: {
@@ -3092,8 +3111,12 @@ const SkillCard = ({
3092
3111
  }
3093
3112
  ),
3094
3113
  ((_a = skill.metadata) == null ? void 0 : _a.owner) && ((_b = skill.metadata) == null ? void 0 : _b.repo) && /* @__PURE__ */ jsxs(
3095
- "div",
3114
+ "a",
3096
3115
  {
3116
+ href: skill.metadata.installedFrom || `https://github.com/${skill.metadata.owner}/${skill.metadata.repo}`,
3117
+ target: "_blank",
3118
+ rel: "noopener noreferrer",
3119
+ onClick: (e) => e.stopPropagation(),
3097
3120
  style: {
3098
3121
  display: "inline-flex",
3099
3122
  alignItems: "center",
@@ -3106,13 +3129,25 @@ const SkillCard = ({
3106
3129
  color: theme2.colors.textSecondary,
3107
3130
  fontWeight: 500,
3108
3131
  fontFamily: theme2.fonts.monospace,
3109
- width: "fit-content"
3132
+ width: "fit-content",
3133
+ textDecoration: "none",
3134
+ cursor: "pointer",
3135
+ transition: "all 0.2s ease"
3110
3136
  },
3111
- title: `From: ${skill.metadata.installedFrom}
3137
+ title: `Click to open: ${skill.metadata.installedFrom || `https://github.com/${skill.metadata.owner}/${skill.metadata.repo}`}
3112
3138
  Installed: ${skill.metadata.installedAt ? new Date(skill.metadata.installedAt).toLocaleString() : "Unknown"}`,
3139
+ onMouseEnter: (e) => {
3140
+ e.currentTarget.style.backgroundColor = `${theme2.colors.textSecondary}25`;
3141
+ e.currentTarget.style.borderColor = `${theme2.colors.textSecondary}50`;
3142
+ },
3143
+ onMouseLeave: (e) => {
3144
+ e.currentTarget.style.backgroundColor = `${theme2.colors.textSecondary}15`;
3145
+ e.currentTarget.style.borderColor = `${theme2.colors.textSecondary}30`;
3146
+ },
3113
3147
  children: [
3114
3148
  /* @__PURE__ */ jsx(Github, { size: 10 }),
3115
3149
  /* @__PURE__ */ jsxs("span", { children: [
3150
+ "From ",
3116
3151
  skill.metadata.owner,
3117
3152
  "/",
3118
3153
  skill.metadata.repo
@@ -3145,8 +3180,21 @@ Installed: ${skill.metadata.installedAt ? new Date(skill.metadata.installedAt).t
3145
3180
  }
3146
3181
  ),
3147
3182
  skill.installedLocations && skill.installedLocations.length > 1 && (() => {
3148
- const otherLocations = skill.installedLocations.filter((loc) => loc.path !== skill.path).map((loc) => abbreviateSourceName(loc.source));
3149
- const uniqueLocations = Array.from(new Set(otherLocations));
3183
+ let otherLocations = [];
3184
+ if (filterContext === "project") {
3185
+ otherLocations = skill.installedLocations.filter(
3186
+ (loc) => loc.source === "global-universal" || loc.source === "global-claude"
3187
+ );
3188
+ } else if (filterContext === "global") {
3189
+ otherLocations = skill.installedLocations.filter(
3190
+ (loc) => loc.source === "project-universal" || loc.source === "project-claude" || loc.source === "project-other"
3191
+ );
3192
+ } else {
3193
+ otherLocations = skill.installedLocations.filter((loc) => loc.path !== skill.path);
3194
+ }
3195
+ if (otherLocations.length === 0) return null;
3196
+ const locationNames = otherLocations.map((loc) => abbreviateSourceName(loc.source));
3197
+ const uniqueLocations = Array.from(new Set(locationNames));
3150
3198
  const locationText = uniqueLocations.join(", ");
3151
3199
  return /* @__PURE__ */ jsxs(
3152
3200
  "div",
@@ -3165,7 +3213,7 @@ Installed: ${skill.metadata.installedAt ? new Date(skill.metadata.installedAt).t
3165
3213
  width: "fit-content"
3166
3214
  },
3167
3215
  title: `Also installed in:
3168
- ${skill.installedLocations.filter((loc) => loc.path !== skill.path).map((loc) => `${abbreviateSourceName(loc.source)}: ${loc.path}`).join("\n")}`,
3216
+ ${otherLocations.map((loc) => `${abbreviateSourceName(loc.source)}: ${loc.path}`).join("\n")}`,
3169
3217
  children: [
3170
3218
  /* @__PURE__ */ jsx(Package, { size: 10 }),
3171
3219
  /* @__PURE__ */ jsxs("span", { children: [
@@ -3323,7 +3371,7 @@ ${skill.installedLocations.filter((loc) => loc.path !== skill.path).map((loc) =>
3323
3371
  transition: "all 0.2s ease",
3324
3372
  border: `1px solid ${pathCopied ? theme2.colors.success : "transparent"}`
3325
3373
  },
3326
- title: pathCopied ? "Copied!" : "Click to copy path",
3374
+ title: pathCopied ? "Copied!" : `Click to copy: ${getPathToCopy()}`,
3327
3375
  onMouseEnter: (e) => {
3328
3376
  if (!pathCopied) {
3329
3377
  e.currentTarget.style.background = theme2.colors.backgroundTertiary || theme2.colors.border;
@@ -3334,7 +3382,7 @@ ${skill.installedLocations.filter((loc) => loc.path !== skill.path).map((loc) =>
3334
3382
  e.currentTarget.style.background = theme2.colors.backgroundSecondary;
3335
3383
  }
3336
3384
  },
3337
- children: pathCopied ? "Copied!" : skill.path
3385
+ children: pathCopied ? "Copied!" : getPathToCopy()
3338
3386
  }
3339
3387
  )
3340
3388
  ]
@@ -3344,13 +3392,14 @@ ${skill.installedLocations.filter((loc) => loc.path !== skill.path).map((loc) =>
3344
3392
  const SkillsListPanel = ({
3345
3393
  context,
3346
3394
  events,
3347
- browseMode = false
3395
+ browseMode = false,
3396
+ supportsRefresh = false
3348
3397
  }) => {
3349
3398
  const { theme: theme2 } = useTheme();
3350
3399
  const panelRef = useRef(null);
3351
3400
  const [selectedSkillId, setSelectedSkillId] = useState(null);
3352
3401
  const [searchQuery, setSearchQuery] = useState("");
3353
- const [skillFilter, setSkillFilter] = useState("all");
3402
+ const [skillFilter, setSkillFilter] = useState("project");
3354
3403
  const [isRefreshing, setIsRefreshing] = useState(false);
3355
3404
  const { skills, isLoading, error, refreshSkills } = useSkillsData({ context });
3356
3405
  gt("skills-list", events, () => {
@@ -3378,13 +3427,23 @@ const SkillsListPanel = ({
3378
3427
  const filteredSkills = useMemo(() => {
3379
3428
  let filtered = skills;
3380
3429
  if (skillFilter === "project") {
3381
- filtered = filtered.filter(
3382
- (skill) => skill.source === "project-universal" || skill.source === "project-claude" || skill.source === "project-other"
3383
- );
3430
+ filtered = filtered.filter((skill) => {
3431
+ if (skill.installedLocations && skill.installedLocations.length > 0) {
3432
+ return skill.installedLocations.some(
3433
+ (loc) => loc.source === "project-universal" || loc.source === "project-claude" || loc.source === "project-other"
3434
+ );
3435
+ }
3436
+ return skill.source === "project-universal" || skill.source === "project-claude" || skill.source === "project-other";
3437
+ });
3384
3438
  } else if (skillFilter === "global") {
3385
- filtered = filtered.filter(
3386
- (skill) => skill.source === "global-universal" || skill.source === "global-claude"
3387
- );
3439
+ filtered = filtered.filter((skill) => {
3440
+ if (skill.installedLocations && skill.installedLocations.length > 0) {
3441
+ return skill.installedLocations.some(
3442
+ (loc) => loc.source === "global-universal" || loc.source === "global-claude"
3443
+ );
3444
+ }
3445
+ return skill.source === "global-universal" || skill.source === "global-claude";
3446
+ });
3388
3447
  }
3389
3448
  if (searchQuery.trim()) {
3390
3449
  const query = searchQuery.toLowerCase().trim();
@@ -3412,7 +3471,7 @@ const SkillsListPanel = ({
3412
3471
  });
3413
3472
  }
3414
3473
  };
3415
- const handleRefresh = async () => {
3474
+ const handleRefresh = () => {
3416
3475
  setIsRefreshing(true);
3417
3476
  if (events) {
3418
3477
  events.emit({
@@ -3423,11 +3482,9 @@ const SkillsListPanel = ({
3423
3482
  payload: {}
3424
3483
  });
3425
3484
  }
3426
- try {
3427
- await refreshSkills();
3428
- } finally {
3485
+ setTimeout(() => {
3429
3486
  setIsRefreshing(false);
3430
- }
3487
+ }, 800);
3431
3488
  };
3432
3489
  return /* @__PURE__ */ jsxs(
3433
3490
  "div",
@@ -3574,7 +3631,7 @@ const SkillsListPanel = ({
3574
3631
  ]
3575
3632
  }
3576
3633
  ),
3577
- /* @__PURE__ */ jsx(
3634
+ supportsRefresh && /* @__PURE__ */ jsx(
3578
3635
  "button",
3579
3636
  {
3580
3637
  onClick: handleRefresh,
@@ -3584,7 +3641,7 @@ const SkillsListPanel = ({
3584
3641
  border: `1px solid ${theme2.colors.border}`,
3585
3642
  borderRadius: theme2.radii[1],
3586
3643
  padding: "8px",
3587
- cursor: isRefreshing ? "wait" : "pointer",
3644
+ cursor: isRefreshing || isLoading ? "default" : "pointer",
3588
3645
  display: "flex",
3589
3646
  alignItems: "center",
3590
3647
  justifyContent: "center",
@@ -3616,33 +3673,12 @@ const SkillsListPanel = ({
3616
3673
  gap: "8px"
3617
3674
  },
3618
3675
  children: [
3619
- /* @__PURE__ */ jsx(
3620
- "button",
3621
- {
3622
- onClick: () => setSkillFilter("all"),
3623
- style: {
3624
- padding: "8px 16px",
3625
- fontSize: theme2.fontSizes[1],
3626
- fontFamily: theme2.fonts.body,
3627
- border: `1px solid ${skillFilter === "all" ? theme2.colors.primary : theme2.colors.border}`,
3628
- borderRadius: theme2.radii[1],
3629
- background: skillFilter === "all" ? `${theme2.colors.primary}15` : theme2.colors.backgroundSecondary,
3630
- color: skillFilter === "all" ? theme2.colors.primary : theme2.colors.text,
3631
- cursor: "pointer",
3632
- display: "flex",
3633
- alignItems: "center",
3634
- gap: "6px",
3635
- fontWeight: skillFilter === "all" ? 600 : 400,
3636
- transition: "all 0.2s ease"
3637
- },
3638
- children: "All Skills"
3639
- }
3640
- ),
3641
3676
  /* @__PURE__ */ jsx(
3642
3677
  "button",
3643
3678
  {
3644
3679
  onClick: () => setSkillFilter("project"),
3645
3680
  style: {
3681
+ flex: 1,
3646
3682
  padding: "8px 16px",
3647
3683
  fontSize: theme2.fontSizes[1],
3648
3684
  fontFamily: theme2.fonts.body,
@@ -3653,6 +3689,7 @@ const SkillsListPanel = ({
3653
3689
  cursor: "pointer",
3654
3690
  display: "flex",
3655
3691
  alignItems: "center",
3692
+ justifyContent: "center",
3656
3693
  gap: "6px",
3657
3694
  fontWeight: skillFilter === "project" ? 600 : 400,
3658
3695
  transition: "all 0.2s ease"
@@ -3665,6 +3702,7 @@ const SkillsListPanel = ({
3665
3702
  {
3666
3703
  onClick: () => setSkillFilter("global"),
3667
3704
  style: {
3705
+ flex: 1,
3668
3706
  padding: "8px 16px",
3669
3707
  fontSize: theme2.fontSizes[1],
3670
3708
  fontFamily: theme2.fonts.body,
@@ -3675,6 +3713,7 @@ const SkillsListPanel = ({
3675
3713
  cursor: "pointer",
3676
3714
  display: "flex",
3677
3715
  alignItems: "center",
3716
+ justifyContent: "center",
3678
3717
  gap: "6px",
3679
3718
  fontWeight: skillFilter === "global" ? 600 : 400,
3680
3719
  transition: "all 0.2s ease"
@@ -3748,6 +3787,425 @@ const SkillsListPanel = ({
3748
3787
  ] })
3749
3788
  ]
3750
3789
  }
3790
+ ) : /* @__PURE__ */ jsx(
3791
+ "div",
3792
+ {
3793
+ style: {
3794
+ display: "grid",
3795
+ gridTemplateColumns: "repeat(auto-fill, minmax(250px, 1fr))",
3796
+ gap: "16px",
3797
+ padding: "4px"
3798
+ },
3799
+ children: filteredSkills.map((skill) => /* @__PURE__ */ jsx(
3800
+ SkillCard,
3801
+ {
3802
+ skill,
3803
+ onClick: handleSkillClick,
3804
+ isSelected: selectedSkillId === skill.id,
3805
+ filterContext: skillFilter
3806
+ },
3807
+ skill.id
3808
+ ))
3809
+ }
3810
+ )
3811
+ }
3812
+ ),
3813
+ /* @__PURE__ */ jsx("style", { children: `
3814
+ @keyframes spin {
3815
+ to { transform: rotate(360deg); }
3816
+ }
3817
+ ` })
3818
+ ]
3819
+ }
3820
+ );
3821
+ };
3822
+ const EMPTY_SKILLS_ARRAY = [];
3823
+ const useSkillsBrowseData = ({
3824
+ context
3825
+ }) => {
3826
+ var _a, _b;
3827
+ const [skills, setSkills] = useState(EMPTY_SKILLS_ARRAY);
3828
+ const [isLoading, setIsLoading] = useState(true);
3829
+ const [error, setError] = useState(null);
3830
+ const fileTreeSlice = context.getSlice("fileTree");
3831
+ const fileTree = fileTreeSlice == null ? void 0 : fileTreeSlice.data;
3832
+ const fileTreeSha = fileTree == null ? void 0 : fileTree.sha;
3833
+ const repoPath = (_a = context.currentScope.repository) == null ? void 0 : _a.path;
3834
+ const fileSystem = (_b = context.adapters) == null ? void 0 : _b.fileSystem;
3835
+ const lastLoadedSha = useRef(void 0);
3836
+ const loadSkills = useCallback(async () => {
3837
+ if (fileTreeSha === lastLoadedSha.current) {
3838
+ console.log("[useSkillsBrowseData] Skipping reload - data unchanged (SHA:", fileTreeSha, ")");
3839
+ return;
3840
+ }
3841
+ console.log("[useSkillsBrowseData] Loading skills from GitHub repo - SHA:", fileTreeSha);
3842
+ setIsLoading(true);
3843
+ setError(null);
3844
+ try {
3845
+ let repoSkills = [];
3846
+ if (fileTree && (fileSystem == null ? void 0 : fileSystem.readFile) && repoPath) {
3847
+ const isGithubRepo = !repoPath.startsWith("/");
3848
+ if (!isGithubRepo) {
3849
+ console.warn("[useSkillsBrowseData] Not a GitHub repo, skipping skill load");
3850
+ setSkills(EMPTY_SKILLS_ARRAY);
3851
+ lastLoadedSha.current = fileTreeSha;
3852
+ setIsLoading(false);
3853
+ return;
3854
+ }
3855
+ console.log("[useSkillsBrowseData] GitHub repo detected:", repoPath);
3856
+ const skillPaths = findSkillFiles(fileTree, true);
3857
+ console.log("[useSkillsBrowseData] Found skill paths:", skillPaths);
3858
+ const skillPromises = skillPaths.map(async (skillPath) => {
3859
+ try {
3860
+ const content2 = await fileSystem.readFile(skillPath);
3861
+ return parseSkillContent(content2, skillPath, fileTree, fileSystem, true);
3862
+ } catch (err) {
3863
+ console.error(`[useSkillsBrowseData] Failed to read skill at ${skillPath}:`, err);
3864
+ return null;
3865
+ }
3866
+ });
3867
+ repoSkills = (await Promise.all(skillPromises)).filter(
3868
+ (skill) => skill !== null
3869
+ );
3870
+ }
3871
+ console.log("[useSkillsBrowseData] Total skills loaded:", repoSkills.length);
3872
+ setSkills(repoSkills);
3873
+ lastLoadedSha.current = fileTreeSha;
3874
+ } catch (err) {
3875
+ const errorMessage = err instanceof Error ? err.message : "Failed to load skills";
3876
+ setError(errorMessage);
3877
+ console.error("[useSkillsBrowseData] Error loading skills:", err);
3878
+ } finally {
3879
+ setIsLoading(false);
3880
+ }
3881
+ }, [fileTree, fileTreeSha, repoPath, fileSystem]);
3882
+ const refreshSkills = useCallback(async () => {
3883
+ lastLoadedSha.current = void 0;
3884
+ await loadSkills();
3885
+ }, [loadSkills]);
3886
+ useEffect(() => {
3887
+ loadSkills();
3888
+ }, [loadSkills]);
3889
+ return {
3890
+ skills,
3891
+ isLoading,
3892
+ error,
3893
+ refreshSkills
3894
+ };
3895
+ };
3896
+ const SkillsBrowsePanel = ({
3897
+ context,
3898
+ events,
3899
+ supportsRefresh = false
3900
+ }) => {
3901
+ const { theme: theme2 } = useTheme();
3902
+ const panelRef = useRef(null);
3903
+ const [selectedSkillId, setSelectedSkillId] = useState(null);
3904
+ const [searchQuery, setSearchQuery] = useState("");
3905
+ const [isRefreshing, setIsRefreshing] = useState(false);
3906
+ const { skills, isLoading, error, refreshSkills } = useSkillsBrowseData({ context });
3907
+ gt("skills-browse", events, () => {
3908
+ var _a;
3909
+ return (_a = panelRef.current) == null ? void 0 : _a.focus();
3910
+ });
3911
+ useEffect(() => {
3912
+ const unsubscribeInstalled = events.on("skill:installed", () => {
3913
+ console.log("[SkillsBrowsePanel] Skill installed, refreshing...");
3914
+ refreshSkills();
3915
+ });
3916
+ const unsubscribeUninstalled = events.on("skill:uninstalled", () => {
3917
+ console.log("[SkillsBrowsePanel] Skill uninstalled, refreshing...");
3918
+ refreshSkills();
3919
+ });
3920
+ return () => {
3921
+ unsubscribeInstalled();
3922
+ unsubscribeUninstalled();
3923
+ };
3924
+ }, [events, refreshSkills]);
3925
+ const filteredSkills = useMemo(() => {
3926
+ let filtered = skills;
3927
+ if (searchQuery.trim()) {
3928
+ const query = searchQuery.toLowerCase().trim();
3929
+ filtered = filtered.filter((skill) => {
3930
+ var _a, _b;
3931
+ if (skill.name.toLowerCase().includes(query)) return true;
3932
+ if ((_a = skill.description) == null ? void 0 : _a.toLowerCase().includes(query)) return true;
3933
+ if ((_b = skill.capabilities) == null ? void 0 : _b.some((cap2) => cap2.toLowerCase().includes(query)))
3934
+ return true;
3935
+ if (skill.path.toLowerCase().includes(query)) return true;
3936
+ return false;
3937
+ });
3938
+ }
3939
+ return filtered;
3940
+ }, [skills, searchQuery]);
3941
+ const handleSkillClick = (skill) => {
3942
+ setSelectedSkillId(skill.id);
3943
+ if (events) {
3944
+ events.emit({
3945
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3946
+ type: "skill:selected",
3947
+ source: "skills-browse-panel",
3948
+ timestamp: Date.now(),
3949
+ payload: { skillId: skill.id, skill }
3950
+ });
3951
+ }
3952
+ };
3953
+ const handleRefresh = () => {
3954
+ setIsRefreshing(true);
3955
+ if (events) {
3956
+ events.emit({
3957
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3958
+ type: "skills:refresh",
3959
+ source: "skills-browse-panel",
3960
+ timestamp: Date.now(),
3961
+ payload: {}
3962
+ });
3963
+ }
3964
+ setTimeout(() => {
3965
+ setIsRefreshing(false);
3966
+ }, 800);
3967
+ };
3968
+ return /* @__PURE__ */ jsxs(
3969
+ "div",
3970
+ {
3971
+ ref: panelRef,
3972
+ tabIndex: -1,
3973
+ style: {
3974
+ padding: "clamp(12px, 3vw, 20px)",
3975
+ fontFamily: theme2.fonts.body,
3976
+ height: "100%",
3977
+ boxSizing: "border-box",
3978
+ display: "flex",
3979
+ flexDirection: "column",
3980
+ gap: "16px",
3981
+ overflow: "hidden",
3982
+ backgroundColor: theme2.colors.background,
3983
+ color: theme2.colors.text,
3984
+ outline: "none"
3985
+ },
3986
+ children: [
3987
+ /* @__PURE__ */ jsxs(
3988
+ "div",
3989
+ {
3990
+ style: {
3991
+ flexShrink: 0,
3992
+ display: "flex",
3993
+ alignItems: "center",
3994
+ justifyContent: "space-between",
3995
+ gap: "12px",
3996
+ flexWrap: "wrap"
3997
+ },
3998
+ children: [
3999
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "12px" }, children: [
4000
+ /* @__PURE__ */ jsx(
4001
+ "h2",
4002
+ {
4003
+ style: {
4004
+ margin: 0,
4005
+ fontSize: theme2.fontSizes[4],
4006
+ color: theme2.colors.text
4007
+ },
4008
+ children: /* @__PURE__ */ jsx(
4009
+ "a",
4010
+ {
4011
+ href: "https://agentskills.io/",
4012
+ target: "_blank",
4013
+ rel: "noopener noreferrer",
4014
+ style: {
4015
+ color: "inherit",
4016
+ textDecoration: "none"
4017
+ },
4018
+ onMouseEnter: (e) => e.currentTarget.style.textDecoration = "underline",
4019
+ onMouseLeave: (e) => e.currentTarget.style.textDecoration = "none",
4020
+ children: "Browse Skills"
4021
+ }
4022
+ )
4023
+ }
4024
+ ),
4025
+ !isLoading && /* @__PURE__ */ jsxs(
4026
+ "span",
4027
+ {
4028
+ style: {
4029
+ fontSize: theme2.fontSizes[1],
4030
+ color: theme2.colors.textSecondary,
4031
+ background: theme2.colors.backgroundSecondary,
4032
+ padding: "4px 10px",
4033
+ borderRadius: theme2.radii[1]
4034
+ },
4035
+ children: [
4036
+ filteredSkills.length,
4037
+ " ",
4038
+ filteredSkills.length === 1 ? "skill" : "skills"
4039
+ ]
4040
+ }
4041
+ )
4042
+ ] }),
4043
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "12px", flex: "1 1 200px", maxWidth: "400px" }, children: [
4044
+ /* @__PURE__ */ jsxs(
4045
+ "div",
4046
+ {
4047
+ style: {
4048
+ position: "relative",
4049
+ flex: 1,
4050
+ minWidth: "150px"
4051
+ },
4052
+ children: [
4053
+ /* @__PURE__ */ jsx(
4054
+ Search,
4055
+ {
4056
+ size: 16,
4057
+ color: theme2.colors.textSecondary,
4058
+ style: {
4059
+ position: "absolute",
4060
+ left: "10px",
4061
+ top: "50%",
4062
+ transform: "translateY(-50%)",
4063
+ pointerEvents: "none"
4064
+ }
4065
+ }
4066
+ ),
4067
+ /* @__PURE__ */ jsx(
4068
+ "input",
4069
+ {
4070
+ type: "text",
4071
+ placeholder: "Search skills...",
4072
+ value: searchQuery,
4073
+ onChange: (e) => setSearchQuery(e.target.value),
4074
+ style: {
4075
+ width: "100%",
4076
+ padding: "8px 32px 8px 32px",
4077
+ fontSize: theme2.fontSizes[1],
4078
+ fontFamily: theme2.fonts.body,
4079
+ border: `1px solid ${theme2.colors.border}`,
4080
+ borderRadius: theme2.radii[2],
4081
+ background: theme2.colors.backgroundSecondary,
4082
+ color: theme2.colors.text,
4083
+ outline: "none",
4084
+ boxSizing: "border-box"
4085
+ }
4086
+ }
4087
+ ),
4088
+ searchQuery && /* @__PURE__ */ jsx(
4089
+ "button",
4090
+ {
4091
+ onClick: () => setSearchQuery(""),
4092
+ style: {
4093
+ position: "absolute",
4094
+ right: "6px",
4095
+ top: "50%",
4096
+ transform: "translateY(-50%)",
4097
+ background: "transparent",
4098
+ border: "none",
4099
+ padding: "4px",
4100
+ cursor: "pointer",
4101
+ display: "flex",
4102
+ alignItems: "center",
4103
+ justifyContent: "center",
4104
+ color: theme2.colors.textSecondary
4105
+ },
4106
+ "aria-label": "Clear search",
4107
+ children: /* @__PURE__ */ jsx(X, { size: 14 })
4108
+ }
4109
+ )
4110
+ ]
4111
+ }
4112
+ ),
4113
+ supportsRefresh && /* @__PURE__ */ jsx(
4114
+ "button",
4115
+ {
4116
+ onClick: handleRefresh,
4117
+ disabled: isRefreshing || isLoading,
4118
+ style: {
4119
+ background: theme2.colors.backgroundSecondary,
4120
+ border: `1px solid ${theme2.colors.border}`,
4121
+ borderRadius: theme2.radii[1],
4122
+ padding: "8px",
4123
+ cursor: isRefreshing || isLoading ? "default" : "pointer",
4124
+ display: "flex",
4125
+ alignItems: "center",
4126
+ justifyContent: "center",
4127
+ transition: "all 0.2s ease"
4128
+ },
4129
+ title: "Refresh skills",
4130
+ children: /* @__PURE__ */ jsx(
4131
+ RefreshCw,
4132
+ {
4133
+ size: 16,
4134
+ color: theme2.colors.textSecondary,
4135
+ style: {
4136
+ animation: isRefreshing ? "spin 1s linear infinite" : "none"
4137
+ }
4138
+ }
4139
+ )
4140
+ }
4141
+ )
4142
+ ] })
4143
+ ]
4144
+ }
4145
+ ),
4146
+ error && /* @__PURE__ */ jsxs(
4147
+ "div",
4148
+ {
4149
+ style: {
4150
+ flexShrink: 0,
4151
+ padding: "12px",
4152
+ background: `${theme2.colors.error}20`,
4153
+ border: `1px solid ${theme2.colors.error}`,
4154
+ borderRadius: theme2.radii[2],
4155
+ display: "flex",
4156
+ alignItems: "center",
4157
+ gap: "8px",
4158
+ color: theme2.colors.error,
4159
+ fontSize: theme2.fontSizes[1]
4160
+ },
4161
+ children: [
4162
+ /* @__PURE__ */ jsx(CircleAlert, { size: 16 }),
4163
+ /* @__PURE__ */ jsx("span", { children: error })
4164
+ ]
4165
+ }
4166
+ ),
4167
+ /* @__PURE__ */ jsx(
4168
+ "div",
4169
+ {
4170
+ style: {
4171
+ flex: 1,
4172
+ overflowY: "auto",
4173
+ minHeight: 0
4174
+ },
4175
+ children: isLoading ? /* @__PURE__ */ jsx(
4176
+ "div",
4177
+ {
4178
+ style: {
4179
+ height: "100%",
4180
+ display: "flex",
4181
+ alignItems: "center",
4182
+ justifyContent: "center",
4183
+ color: theme2.colors.textSecondary,
4184
+ fontSize: theme2.fontSizes[2]
4185
+ },
4186
+ children: "Loading skills from repository..."
4187
+ }
4188
+ ) : filteredSkills.length === 0 ? /* @__PURE__ */ jsxs(
4189
+ "div",
4190
+ {
4191
+ style: {
4192
+ height: "100%",
4193
+ display: "flex",
4194
+ flexDirection: "column",
4195
+ alignItems: "center",
4196
+ justifyContent: "center",
4197
+ gap: "16px",
4198
+ color: theme2.colors.textSecondary,
4199
+ padding: "24px"
4200
+ },
4201
+ children: [
4202
+ /* @__PURE__ */ jsx(FileCode, { size: 48, color: theme2.colors.border }),
4203
+ /* @__PURE__ */ jsxs("div", { style: { textAlign: "center" }, children: [
4204
+ /* @__PURE__ */ jsx("p", { style: { margin: 0, fontSize: theme2.fontSizes[2] }, children: searchQuery ? "No skills match your search" : "No skills found in this repository" }),
4205
+ /* @__PURE__ */ jsx("p", { style: { margin: "8px 0 0 0", fontSize: theme2.fontSizes[1] }, children: searchQuery ? "Try a different search term" : "This repository does not contain any SKILL.md files" })
4206
+ ] })
4207
+ ]
4208
+ }
3751
4209
  ) : /* @__PURE__ */ jsx(
3752
4210
  "div",
3753
4211
  {
@@ -51051,6 +51509,31 @@ const panels = [
51051
51509
  console.log("Skills List Panel unmounting");
51052
51510
  }
51053
51511
  },
51512
+ {
51513
+ metadata: {
51514
+ id: "industry-theme.skills-browse",
51515
+ name: "Browse Skills",
51516
+ icon: "🔍",
51517
+ version: "0.1.0",
51518
+ author: "Principal ADE",
51519
+ description: "Browse Agent Skills from GitHub repositories",
51520
+ slices: ["fileTree"]
51521
+ // Only needs fileTree, not globalSkills
51522
+ },
51523
+ component: SkillsBrowsePanel,
51524
+ // Optional: Called when this specific panel is mounted
51525
+ onMount: async (context) => {
51526
+ var _a;
51527
+ console.log(
51528
+ "Skills Browse Panel mounted",
51529
+ (_a = context.currentScope.repository) == null ? void 0 : _a.path
51530
+ );
51531
+ },
51532
+ // Optional: Called when this specific panel is unmounted
51533
+ onUnmount: async (_context) => {
51534
+ console.log("Skills Browse Panel unmounting");
51535
+ }
51536
+ },
51054
51537
  {
51055
51538
  metadata: {
51056
51539
  id: "industry-theme.skill-detail",
@@ -51134,6 +51617,7 @@ const onPackageUnload = async () => {
51134
51617
  console.log("Panel package unloading - Agent Panels Extension");
51135
51618
  };
51136
51619
  export {
51620
+ SkillsBrowsePanel,
51137
51621
  onPackageLoad,
51138
51622
  onPackageUnload,
51139
51623
  panels