@xopcai/xopc 0.0.52 → 0.0.54
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.
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agents-CLNe-mJX.js → agents-Cccit5xQ.js} +2 -2
- package/dist/gateway/static/root/assets/{agents-CLNe-mJX.js.map → agents-Cccit5xQ.js.map} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-c5XF02ek.js → apps-page-JMpsr3yK.js} +2 -2
- package/dist/gateway/static/root/assets/{apps-page-c5XF02ek.js.map → apps-page-JMpsr3yK.js.map} +1 -1
- package/dist/gateway/static/root/assets/{channels-settings-BTgdsBM4.js → channels-settings-jJX9xOyE.js} +2 -2
- package/dist/gateway/static/root/assets/{channels-settings-BTgdsBM4.js.map → channels-settings-jJX9xOyE.js.map} +1 -1
- package/dist/gateway/static/root/assets/{cron-dreaming-jobs-CiQJHx3s.js → cron-dreaming-jobs-DousYqF2.js} +2 -2
- package/dist/gateway/static/root/assets/{cron-dreaming-jobs-CiQJHx3s.js.map → cron-dreaming-jobs-DousYqF2.js.map} +1 -1
- package/dist/gateway/static/root/assets/{cron-page-DJOj7JWb.js → cron-page-CdYb690n.js} +2 -2
- package/dist/gateway/static/root/assets/{cron-page-DJOj7JWb.js.map → cron-page-CdYb690n.js.map} +1 -1
- package/dist/gateway/static/root/assets/{dist-BY3E71wk.js → dist-D8QibYZR.js} +2 -2
- package/dist/gateway/static/root/assets/{dist-BY3E71wk.js.map → dist-D8QibYZR.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-DzkYBiW-.js → extension-debug-page-DJ-puhUh.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-debug-page-DzkYBiW-.js.map → extension-debug-page-DJ-puhUh.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-yF0LIy5D.js → extension-page-DgDGH7uc.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-page-yF0LIy5D.js.map → extension-page-DgDGH7uc.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-CS_Y4y3w.js → extension-settings-page-BnQ2f4Fq.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-settings-page-CS_Y4y3w.js.map → extension-settings-page-BnQ2f4Fq.js.map} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-DD2LdM_Q.js → heartbeat-config-api-B9hxMalj.js} +2 -2
- package/dist/gateway/static/root/assets/{heartbeat-config-api-DD2LdM_Q.js.map → heartbeat-config-api-B9hxMalj.js.map} +1 -1
- package/dist/gateway/static/root/assets/{index-V5ZnG6RE.js → index-8IFT6i7x.js} +4 -4
- package/dist/gateway/static/root/assets/{index-V5ZnG6RE.js.map → index-8IFT6i7x.js.map} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-D79WclZL.js → logs-page-DNHn8mTk.js} +2 -2
- package/dist/gateway/static/root/assets/{logs-page-D79WclZL.js.map → logs-page-DNHn8mTk.js.map} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-R_QJy3OK.js → sessions-page-D3kE1tob.js} +2 -2
- package/dist/gateway/static/root/assets/{sessions-page-R_QJy3OK.js.map → sessions-page-D3kE1tob.js.map} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-CGaj_9Qb.js → settings-page-B4tuVOtd.js} +2 -2
- package/dist/gateway/static/root/assets/{settings-page-CGaj_9Qb.js.map → settings-page-B4tuVOtd.js.map} +1 -1
- package/dist/gateway/static/root/assets/{skills-page-UzbTgnVY.js → skills-page-Dgd20nUt.js} +2 -2
- package/dist/gateway/static/root/assets/{skills-page-UzbTgnVY.js.map → skills-page-Dgd20nUt.js.map} +1 -1
- package/dist/gateway/static/root/assets/{use-image-provider-credentials-DAx__u3a.js → use-image-provider-credentials-CqMkyIiU.js} +2 -2
- package/dist/gateway/static/root/assets/{use-image-provider-credentials-DAx__u3a.js.map → use-image-provider-credentials-CqMkyIiU.js.map} +1 -1
- package/dist/gateway/static/root/index.html +1 -1
- package/dist/package.js +1 -1
- package/dist/src/browser/providers/extension.js +37 -3
- package/dist/src/browser/providers/extension.js.map +1 -1
- package/dist/src/gateway/security/csp.d.ts +1 -0
- package/dist/src/gateway/security/csp.js +2 -0
- package/dist/src/gateway/security/csp.js.map +1 -1
- package/dist/src/gateway/service.js +13 -4
- package/dist/src/gateway/service.js.map +1 -1
- package/package.json +1 -1
package/dist/gateway/static/root/assets/{skills-page-UzbTgnVY.js.map → skills-page-Dgd20nUt.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"mappings":"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I,CACF,IAAM,EAAI,GAAM,kBACZ,GAA6B,SAAW,EACxC,EACJ,MAAM,GAAwB,CAC5B,OACA,UAAW,EACX,GAAI,EAAI,CAAE,SAAU,EAAG,CAAG,EAAE,CAC7B,CAAC,CACF,MAAM,EAAK,CAAE,OAAQ,GAAM,CAAC,CAC5B,EAAa,UAAW,EAAG,eAAe,CAC1C,EAAc,GAAM,CACpB,GAAW,OAAO,OACX,EAAG,CACV,EAAa,QAAS,aAAa,MAAQ,EAAE,QAAU,EAAG,aAAa,QAC/D,CACR,GAAwB,KAAK,IAGjC,CACE,GACA,EACA,EACA,EACA,EAAG,eACH,EAAG,4BACH,EAAG,aACJ,CACF,CAEK,GACJ,IAAiB,MACb,EAAG,UACH,IAAiB,SACf,EAAG,aACH,IAAiB,YACf,EAAG,gBACH,EAAG,YAEP,CAAE,aAAa,GAAa,CAGlC,MAAO,CACL,KACA,WACA,UACA,WACA,SACA,aACA,cACA,kBACA,kBACA,UACA,cACA,eACA,kBACA,wBACA,4BACA,eACA,iBACA,cACA,iBACA,cACA,gBACA,eACA,kBACA,aACA,gBACA,qBACA,kBACA,cACA,gBACA,gBACA,mBACA,cACA,iBACA,kBACA,oBACA,wBACA,0BACA,4BACA,8BACA,iBACA,eACA,iBACA,aACA,gBACA,aACA,iBACA,YACA,WACA,aACA,wBACA,wBACA,oBACA,mBACA,uBACA,eACA,qBACA,uBACA,uBACA,0BACA,mBACA,gBACA,iBACA,kBACA,qBACA,2BACA,eACA,gBArEsB,GAAS,WAAW,aAqE1C,CACA,iBACA,iBACA,mBACA,yBACA,iBACA,mBACA,qBACA,mBACA,oBACA,eACA,eACA,aACA,mBACA,0BACD,CCzxBH,SAAgB,IAAa,CAE3B,OAAO,SAAC,EAAD,CAAoB,GADhB,GACgB,CAAM","names":[],"ignoreList":[],"sources":["../../../../../web/src/features/skills/skill-card-icon.tsx","../../../../../web/src/features/skills/skills-page.utils.ts","../../../../../web/src/features/skills/skill-catalog-structured-preview.tsx","../../../../../web/src/features/skills/skills-page-header-end.tsx","../../../../../web/src/features/skills/skills-page-primitives.tsx","../../../../../web/src/features/skills/skills-page.constants.ts","../../../../../web/src/features/skills/skills-page-view.tsx","../../../../../web/src/features/skills/skill-upload-zip.ts","../../../../../web/src/features/skills/use-skills-page.ts","../../../../../web/src/features/skills/skills-page.tsx"],"sourcesContent":["import { cn } from '@/lib/cn';\n\n/** Pastel tile + saturated letter (light / dark pairs), stable per skill name hash. */\nconst SKILL_INITIAL_PALETTE: { light: string; dark: string }[] = [\n { light: 'bg-sky-100 text-sky-800', dark: 'dark:bg-sky-950/55 dark:text-sky-200' },\n { light: 'bg-violet-100 text-violet-800', dark: 'dark:bg-violet-950/55 dark:text-violet-200' },\n { light: 'bg-emerald-100 text-emerald-800', dark: 'dark:bg-emerald-950/55 dark:text-emerald-200' },\n { light: 'bg-orange-100 text-orange-800', dark: 'dark:bg-orange-950/55 dark:text-orange-200' },\n { light: 'bg-rose-100 text-rose-800', dark: 'dark:bg-rose-950/55 dark:text-rose-200' },\n { light: 'bg-amber-100 text-amber-900', dark: 'dark:bg-amber-950/55 dark:text-amber-200' },\n { light: 'bg-cyan-100 text-cyan-800', dark: 'dark:bg-cyan-950/55 dark:text-cyan-200' },\n { light: 'bg-indigo-100 text-indigo-800', dark: 'dark:bg-indigo-950/55 dark:text-indigo-200' },\n { light: 'bg-fuchsia-100 text-fuchsia-800', dark: 'dark:bg-fuchsia-950/55 dark:text-fuchsia-200' },\n { light: 'bg-teal-100 text-teal-800', dark: 'dark:bg-teal-950/55 dark:text-teal-200' },\n];\n\nfunction hashSkillNameKey(name: string): number {\n let h = 0;\n for (let i = 0; i < name.length; i += 1) {\n h = (Math.imul(31, h) + name.charCodeAt(i)) | 0;\n }\n return Math.abs(h);\n}\n\n/** First letter or digit (Unicode letters included); skips leading punctuation in slugs. */\nfunction skillInitialLetter(name: string): string {\n const t = name.trim();\n if (!t) return '?';\n const m = t.match(/[\\p{L}\\p{N}]/u);\n if (m) {\n const ch = m[0];\n return ch.toLocaleUpperCase('en-US');\n }\n return t[0];\n}\n\nexport function SkillCardIcon({ name, className }: { name: string; className?: string }) {\n const initial = skillInitialLetter(name);\n const pair = SKILL_INITIAL_PALETTE[hashSkillNameKey(name) % SKILL_INITIAL_PALETTE.length];\n return (\n <div\n className={cn(\n 'flex size-11 shrink-0 items-center justify-center rounded-xl font-semibold tracking-tight shadow-surface',\n 'text-[1.05rem] ring-1 ring-inset ring-black/[0.06] dark:ring-white/[0.1]',\n 'transition-[transform,box-shadow] duration-200 ease-out group-hover:ring-black/[0.1] dark:group-hover:ring-white/[0.14]',\n 'group-hover:-translate-y-px',\n pair.light,\n pair.dark,\n className,\n )}\n aria-hidden\n >\n {initial}\n </div>\n );\n}\n","import type { SkillCatalogEntry, SkillInstallSpecApi } from '@/features/skills/skill.types';\n\nconst SKILLHUB_PUBLIC_ORIGIN = 'https://skillhub.cn';\n\n/**\n * Public SkillHub web URL for a marketplace row `id` (canonical slug, e.g. `self-improving-agent` or `team--skill`).\n * Site shape: `https://skillhub.cn/skills/<slug>`.\n */\nexport function skillHubPublicSkillPageUrl(canonicalSlug: string): string | null {\n const id = canonicalSlug.trim();\n if (!id) return null;\n return `${SKILLHUB_PUBLIC_ORIGIN}/skills/${encodeURIComponent(id)}`;\n}\n\nexport function interpolate(template: string, params: Record<string, string | number>): string {\n return template.replace(/\\{\\{(\\w+)\\}\\}/g, (_, key) => String(params[key] ?? ''));\n}\n\nexport function installSpecSummary(spec: SkillInstallSpecApi): string {\n const parts = [spec.kind];\n if (spec.label?.trim()) parts.push(spec.label.trim());\n if (spec.package?.trim()) parts.push(spec.package.trim());\n if (spec.formula?.trim()) parts.push(spec.formula.trim());\n if (spec.module?.trim()) parts.push(spec.module.trim());\n if (spec.url?.trim()) parts.push(spec.url.trim());\n return parts.join(' · ');\n}\n\nexport function normalizeCatalogEntry(r: SkillCatalogEntry): SkillCatalogEntry {\n return {\n ...r,\n enabled: r.enabled ?? true,\n disableModelInvocation: r.disableModelInvocation ?? false,\n };\n}\n","import { type ReactNode } from 'react';\n\nimport { MarkdownView } from '@/components/markdown/markdown-view';\nimport { cn } from '@/lib/cn';\nimport type { SkillMarkdownPreviewPayload } from '@/features/skills/skill.types';\nimport { installSpecSummary } from '@/features/skills/skills-page.utils';\nimport type { MessageBundle } from '@/i18n/messages';\n\nexport type SkillsCopy = MessageBundle['skills'];\n\nfunction MetaRow({ label, children }: { label: string; children: ReactNode }) {\n if (children === null || children === undefined || children === false) return null;\n return (\n <div className=\"mt-3 border-t border-edge-subtle pt-3 dark:border-edge/60\">\n <div className=\"text-xs font-semibold uppercase tracking-wide text-fg-muted\">{label}</div>\n <div className=\"mt-1.5 min-w-0 text-sm text-fg\">{children}</div>\n </div>\n );\n}\n\nexport function SkillCatalogStructuredPreview({\n preview,\n sk,\n}: {\n preview: SkillMarkdownPreviewPayload;\n sk: SkillsCopy;\n}) {\n const meta = preview.metadata;\n const gate = preview.toolConditions;\n const hasToolGating =\n !!gate &&\n (gate.requiresTools.length > 0 ||\n gate.requiresToolsets.length > 0 ||\n gate.fallbackForTools.length > 0 ||\n gate.fallbackForToolsets.length > 0);\n const req = meta.requires;\n const hasRequires =\n req &&\n ((req.bins?.length ?? 0) > 0 || (req.env?.length ?? 0) > 0 || (req.anyBins?.length ?? 0) > 0);\n const installs = meta.install?.filter((s) => s && typeof s.kind === 'string') ?? [];\n const envNames = preview.requiredEnvVarNames?.filter((n) => n.trim()) ?? [];\n\n return (\n <div className=\"space-y-6\">\n <section aria-labelledby=\"skill-detail-summary-heading\">\n <h3\n id=\"skill-detail-summary-heading\"\n className=\"mb-2 text-xs font-semibold uppercase tracking-wide text-fg-muted\"\n >\n {sk.detailSummaryHeading}\n </h3>\n <div className=\"rounded-xl border border-edge bg-surface-base px-4 py-3 dark:bg-surface-hover/25\">\n {meta.emoji?.trim() ? (\n <p className=\"text-2xl leading-none\" aria-hidden>\n {meta.emoji.trim()}\n </p>\n ) : null}\n <p className={cn('text-sm leading-relaxed text-fg', meta.emoji?.trim() ? 'mt-2' : '')}>\n {preview.description}\n </p>\n {preview.disableModelInvocation ? (\n <p className=\"mt-3 rounded-lg border border-amber-200/80 bg-amber-50/90 px-3 py-2 text-xs leading-snug text-amber-950 dark:border-amber-900/50 dark:bg-amber-950/40 dark:text-amber-100\">\n {sk.detailNotInjectedNote}\n </p>\n ) : null}\n <MetaRow label={sk.detailHomepageLabel}>\n {meta.homepage?.trim() ? (\n <a\n href={meta.homepage.trim()}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"break-all text-accent underline-offset-2 hover:underline\"\n >\n {meta.homepage.trim()}\n </a>\n ) : null}\n </MetaRow>\n <MetaRow label={sk.detailPlatformsLabel}>\n {meta.os && meta.os.length > 0 ? (\n <span className=\"font-mono text-xs text-fg-muted\">{meta.os.join(', ')}</span>\n ) : null}\n </MetaRow>\n <MetaRow label={sk.detailRequiresLabel}>\n {hasRequires && req ? (\n <ul className=\"list-inside list-disc space-y-1 text-sm text-fg-muted\">\n {req.bins && req.bins.length > 0 ? (\n <li>\n <span className=\"text-fg\">{sk.detailRequiresBins}: </span>\n {req.bins.join(', ')}\n </li>\n ) : null}\n {req.env && req.env.length > 0 ? (\n <li>\n <span className=\"text-fg\">{sk.detailRequiresEnv}: </span>\n <span className=\"font-mono text-xs\">{req.env.join(', ')}</span>\n </li>\n ) : null}\n {req.anyBins && req.anyBins.length > 0 ? (\n <li>\n <span className=\"text-fg\">{sk.detailRequiresAnyBins}: </span>\n {req.anyBins.join(', ')}\n </li>\n ) : null}\n </ul>\n ) : null}\n </MetaRow>\n <MetaRow label={sk.detailInstallLabel}>\n {installs.length > 0 ? (\n <ul className=\"list-inside list-decimal space-y-1.5 text-sm text-fg-muted\">\n {installs.map((spec, i) => (\n <li key={spec.id || `${spec.kind}-${i}`} className=\"[overflow-wrap:anywhere]\">\n <span className=\"text-fg\">{installSpecSummary(spec)}</span>\n </li>\n ))}\n </ul>\n ) : null}\n </MetaRow>\n <MetaRow label={sk.detailToolGatingLabel}>\n {hasToolGating && gate ? (\n <ul className=\"mt-1 space-y-2 text-sm text-fg-muted\">\n {gate.requiresTools.length > 0 ? (\n <li>\n <span className=\"font-medium text-fg\">{sk.detailToolsRequiresList}: </span>\n {gate.requiresTools.join(', ')}\n </li>\n ) : null}\n {gate.requiresToolsets.length > 0 ? (\n <li>\n <span className=\"font-medium text-fg\">{sk.detailToolsetsRequiresList}: </span>\n {gate.requiresToolsets.join(', ')}\n </li>\n ) : null}\n {gate.fallbackForTools.length > 0 ? (\n <li>\n <span className=\"font-medium text-fg\">{sk.detailToolsFallbackList}: </span>\n {gate.fallbackForTools.join(', ')}\n </li>\n ) : null}\n {gate.fallbackForToolsets.length > 0 ? (\n <li>\n <span className=\"font-medium text-fg\">{sk.detailToolsetsFallbackList}: </span>\n {gate.fallbackForToolsets.join(', ')}\n </li>\n ) : null}\n </ul>\n ) : null}\n </MetaRow>\n <MetaRow label={sk.detailEnvVarsLabel}>\n {envNames.length > 0 ? (\n <span className=\"font-mono text-xs text-fg-muted\">{envNames.join(', ')}</span>\n ) : null}\n </MetaRow>\n </div>\n </section>\n <section aria-labelledby=\"skill-detail-instructions-heading\">\n <h3\n id=\"skill-detail-instructions-heading\"\n className=\"mb-2 text-xs font-semibold uppercase tracking-wide text-fg-muted\"\n >\n {sk.detailInstructionsHeading}\n </h3>\n {preview.bodyMarkdown.trim() ? (\n <div className=\"markdown-content min-w-0 break-words\">\n <MarkdownView content={preview.bodyMarkdown} />\n </div>\n ) : (\n <p className=\"text-sm italic text-fg-muted\">{sk.detailNoInstructionsBody}</p>\n )}\n </section>\n </div>\n );\n}\n","import { Plus, RefreshCw, Search } from 'lucide-react';\nimport { memo } from 'react';\n\nimport { Button } from '@/components/ui/button';\nimport { cn } from '@/lib/cn';\nimport type { MainTab } from '@/features/skills/skills-page.constants';\nimport type { SkillsCopy } from '@/features/skills/skill-catalog-structured-preview';\n\nexport const SkillsPageHeaderEnd = memo(function SkillsPageHeaderEnd({\n loading,\n onReloadClick,\n searchQuery,\n setSearchQuery,\n mainTab,\n sk,\n setPendingFile,\n setInstallOpen,\n}: {\n loading: boolean;\n onReloadClick: () => void;\n searchQuery: string;\n setSearchQuery: (v: string) => void;\n mainTab: MainTab;\n sk: SkillsCopy;\n setPendingFile: (f: File | null) => void;\n setInstallOpen: (v: boolean) => void;\n}) {\n return (\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center justify-end gap-2\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"h-9 w-9 shrink-0 p-0\"\n disabled={loading}\n title={sk.reloadRuntime}\n aria-label={sk.reloadDiskAria}\n onClick={() => void onReloadClick()}\n >\n <RefreshCw className={cn('size-4', loading && 'animate-spin')} strokeWidth={1.75} />\n </Button>\n <label className=\"relative flex min-h-9 min-w-0 max-w-sm cursor-text items-center rounded-pill border border-edge bg-surface-base py-1.5 pl-9 pr-3 shadow-surface dark:bg-surface-hover/40 sm:max-w-md\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-fg-disabled\"\n strokeWidth={1.75}\n aria-hidden\n />\n <input\n type=\"text\"\n role=\"searchbox\"\n enterKeyHint=\"search\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n placeholder={mainTab === 'marketplace' ? sk.marketplaceSearchPackages : sk.searchPlaceholder}\n autoComplete=\"off\"\n spellCheck={false}\n className=\"min-w-0 flex-1 appearance-none border-0 bg-transparent py-0.5 text-sm leading-normal text-fg caret-current placeholder:text-fg-disabled focus:border-0 focus:shadow-none focus:outline-none focus:ring-0 focus-visible:outline-none\"\n />\n </label>\n <Button\n type=\"button\"\n variant=\"primary\"\n className=\"shrink-0 gap-2\"\n onClick={() => {\n setPendingFile(null);\n setInstallOpen(true);\n }}\n >\n <Plus className=\"size-4\" strokeWidth={1.75} aria-hidden />\n {sk.installCta}\n </Button>\n </div>\n );\n});\n","import { cn } from '@/lib/cn';\n\nexport function SkillEnableSwitch({\n checked,\n onChange,\n}: {\n checked: boolean;\n onChange: (next: boolean) => void;\n}) {\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n className={cn(\n 'relative h-6 w-10 shrink-0 overflow-hidden rounded-full border border-edge p-0.5',\n 'transition-[border-color,background-color] duration-200 ease-out',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-surface-base',\n 'active:scale-[0.97] motion-reduce:transition-none motion-reduce:active:scale-100',\n checked ? 'bg-accent' : 'bg-surface-hover',\n )}\n onClick={() => onChange(!checked)}\n >\n <span\n className={cn(\n 'pointer-events-none absolute left-0.5 top-1/2 block size-4 -translate-y-1/2 rounded-full bg-surface-panel shadow-surface ring-1 ring-edge/40 dark:ring-edge/55',\n 'transition-transform duration-200 ease-out motion-reduce:transition-none',\n checked ? 'translate-x-5' : 'translate-x-0',\n )}\n aria-hidden\n />\n </button>\n );\n}\n\nexport function SkillListRowSkeleton() {\n const skel =\n 'animate-pulse motion-reduce:animate-none rounded-md bg-surface-hover dark:bg-surface-active/50';\n return (\n <div className=\"flex items-center gap-4 px-4 py-3.5\" aria-hidden>\n <div className={cn('size-11 shrink-0 rounded-xl', skel)} />\n <div className=\"min-w-0 flex-1 space-y-2\">\n <div className={cn('h-4 max-w-[10rem]', skel)} />\n <div className={cn('h-3 w-full max-w-xl rounded', skel)} />\n </div>\n <div className={cn('h-6 w-10 shrink-0 rounded-full', skel)} />\n </div>\n );\n}\n\n/** Taller row — matches marketplace cards (meta pills + install button) to avoid layout jump after fetch. */\nexport function MarketplaceSkillListRowSkeleton() {\n const skel =\n 'animate-pulse motion-reduce:animate-none rounded-md bg-surface-hover dark:bg-surface-active/50';\n return (\n <div className=\"flex items-center gap-4 px-4 py-3.5\" aria-hidden>\n <div className={cn('size-11 shrink-0 rounded-xl', skel)} />\n <div className=\"min-w-0 flex-1 space-y-2 pr-2\">\n <div className={cn('h-4 max-w-[12rem]', skel)} />\n <div className={cn('h-3 w-full max-w-xl rounded', skel)} />\n <div className=\"flex flex-wrap gap-1.5 pt-0.5\">\n <div className={cn('h-5 w-[5.5rem] rounded-md', skel)} />\n <div className={cn('h-5 w-16 rounded-md', skel)} />\n <div className={cn('h-5 w-14 rounded-md', skel)} />\n </div>\n </div>\n <div className={cn('h-9 min-w-[6.5rem] shrink-0 rounded-lg', skel)} />\n </div>\n );\n}\n","export type MainTab = 'builtin' | 'user' | 'marketplace';\nexport type SourceFilter = 'all' | 'global' | 'workspace' | 'extra';\n\nexport const MAIN_TAB_SET = new Set<MainTab>(['builtin', 'user', 'marketplace']);\nexport const SOURCE_FILTER_SET = new Set<SourceFilter>(['all', 'global', 'workspace', 'extra']);\n\n/** Hash query: which skills marketplace to browse (`store` | `skillhub`). */\nexport const MARKETPLACE_PROVIDER_PARAM = 'mprov';\n\nexport const SKILL_LIST_SKELETON_COUNT = 6;\n\n/** Category display order for consistent pill ordering on the built-in tab. */\nexport const BUILTIN_SKILL_CATEGORY_ORDER = [\n 'business',\n 'creative',\n 'documents',\n 'engineering',\n 'tools',\n] as const;\n","import * as Dialog from '@radix-ui/react-dialog';\nimport * as DropdownMenu from '@radix-ui/react-dropdown-menu';\nimport {\n ChevronDown,\n ChevronLeft,\n ChevronRight,\n ExternalLink,\n FileArchive,\n Funnel,\n Info,\n MoreVertical,\n Star,\n Trash2,\n X,\n} from 'lucide-react';\nimport { useLayoutEffect, useMemo } from 'react';\n\nimport { MarkdownView } from '@/components/markdown/markdown-view';\nimport { Button } from '@/components/ui/button';\nimport { cn } from '@/lib/cn';\nimport { interaction } from '@/lib/interaction';\nimport { SkillCardIcon } from '@/features/skills/skill-card-icon';\nimport { SkillCatalogStructuredPreview } from '@/features/skills/skill-catalog-structured-preview';\nimport { SkillsPageHeaderEnd } from '@/features/skills/skills-page-header-end';\nimport {\n MarketplaceSkillListRowSkeleton,\n SkillEnableSwitch,\n SkillListRowSkeleton,\n} from '@/features/skills/skills-page-primitives';\nimport { SKILL_LIST_SKELETON_COUNT } from '@/features/skills/skills-page.constants';\nimport { interpolate, skillHubPublicSkillPageUrl } from '@/features/skills/skills-page.utils';\nimport type { SkillsPageVm } from '@/features/skills/use-skills-page';\nimport { usePageHeaderStore } from '@/stores/page-header-store';\n\nexport function SkillsPageView({ vm }: { vm: SkillsPageVm }) {\n const {\n sk,\n hasToken,\n catalog,\n loading,\n error,\n uploading,\n searchQuery,\n setSearchQuery,\n actionFeedback,\n mainTab,\n setMainTab,\n setSourceFilter,\n builtinCategoryFilter,\n setBuiltinCategoryFilter,\n installOpen,\n setInstallOpen,\n pendingFile,\n setPendingFile,\n dropActive,\n setDropActive,\n confirmOpen,\n setConfirmOpen,\n confirmId,\n setConfirmId,\n togglingSkillName,\n enabledOverride,\n detailOpen,\n setDetailOpen,\n detailSource,\n setDetailSource,\n detailTitle,\n setDetailTitle,\n detailMarkdown,\n setDetailMarkdown,\n detailCatalogPreview,\n setDetailCatalogPreview,\n detailMarketplacePreview,\n setDetailMarketplacePreview,\n detailLoading,\n detailError,\n setDetailError,\n marketSort,\n setMarketSort,\n marketPage,\n setMarketPage,\n mpLoading,\n mpError,\n mpPayload,\n installingMarketName,\n marketCategoryId,\n setMarketCategoryId,\n mpCategories,\n mpCategoriesError,\n mpCategoriesLoading,\n marketBrowseProvider,\n setMarketBrowseProvider,\n builtinTabStats,\n userTabStats,\n detailEnabled,\n filteredCatalog,\n builtinCategories,\n categoryFilteredCatalog,\n filterLabel,\n inSettingsShell,\n categoryLabel,\n onReloadClick,\n openSkillDetail,\n openMarketplaceDetail,\n onSkillToggle,\n onInstallSubmit,\n onFileInputChange,\n onModalDragOver,\n onModalDragLeave,\n onModalDrop,\n sourceLabel,\n runDelete,\n onMarketInstall,\n isSkillInstalledByName,\n usingSkillInChatName,\n onUseSkillInChat,\n } = vm;\n\n const setPageHeader = usePageHeaderStore((s) => s.setPageHeader);\n const clearPageHeader = usePageHeaderStore((s) => s.clearPageHeader);\n\n const skillsHeaderEnd = useMemo(\n () => (\n <SkillsPageHeaderEnd\n loading={loading}\n onReloadClick={onReloadClick}\n searchQuery={searchQuery}\n setSearchQuery={setSearchQuery}\n mainTab={mainTab}\n sk={sk}\n setPendingFile={setPendingFile}\n setInstallOpen={setInstallOpen}\n />\n ),\n [\n loading,\n onReloadClick,\n searchQuery,\n setSearchQuery,\n mainTab,\n sk,\n setPendingFile,\n setInstallOpen,\n ],\n );\n\n useLayoutEffect(() => {\n if (!hasToken || inSettingsShell) {\n clearPageHeader();\n return () => clearPageHeader();\n }\n setPageHeader({\n startExtra: null,\n main: null,\n end: skillsHeaderEnd,\n });\n return () => clearPageHeader();\n }, [clearPageHeader, hasToken, inSettingsShell, setPageHeader, skillsHeaderEnd]);\n\n if (!hasToken) {\n return (\n <div className=\"mx-auto w-full max-w-app-main px-4 py-16 text-center text-sm text-fg-muted sm:px-8\">\n {sk.needToken}\n </div>\n );\n }\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col overflow-y-auto bg-surface-panel\">\n <div className=\"mx-auto flex w-full max-w-app-main flex-col gap-6 px-4 py-6 sm:px-8\">\n {actionFeedback ? (\n <div\n role=\"status\"\n aria-live=\"polite\"\n className={cn(\n 'rounded-xl border px-3 py-2 text-sm',\n actionFeedback.kind === 'success'\n ? 'border-emerald-200 bg-emerald-50 text-emerald-800 dark:border-emerald-900/40 dark:bg-emerald-950/40 dark:text-emerald-200'\n : 'border-red-200 bg-red-50 text-red-800 dark:border-red-900/50 dark:bg-red-950/40 dark:text-red-200',\n )}\n >\n {actionFeedback.message}\n </div>\n ) : error ? (\n <div\n className=\"rounded-xl border border-edge bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-edge dark:bg-red-950/40 dark:text-red-300\"\n role=\"alert\"\n >\n {error}\n </div>\n ) : null}\n\n <header className=\"flex flex-col gap-4\">\n <div className=\"min-w-0\">\n <h1 className=\"text-xl font-semibold tracking-tight text-fg\">{sk.title}</h1>\n <p className=\"mt-1 max-w-2xl text-sm text-fg-muted\">{sk.tagline}</p>\n </div>\n </header>\n\n {inSettingsShell ? (\n <div className=\"flex flex-col gap-3 border-b border-edge-subtle pb-4 dark:border-edge-subtle sm:flex-row sm:flex-wrap sm:items-center sm:justify-end\">\n {skillsHeaderEnd}\n </div>\n ) : null}\n\n <section className=\"flex flex-col gap-4\">\n <div className=\"flex flex-col gap-3 border-b border-edge-subtle pb-3 sm:flex-row sm:items-center sm:justify-between dark:border-edge-subtle\">\n <div\n className=\"flex flex-wrap gap-x-1 gap-y-1\"\n role=\"tablist\"\n aria-label={sk.skillsNavAria}\n >\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mainTab === 'marketplace'}\n className={cn(\n 'relative max-w-full rounded-md px-3 py-2 text-left text-sm font-medium transition-colors sm:text-center',\n mainTab === 'marketplace' ? 'text-fg' : 'text-fg-muted hover:text-fg',\n mainTab === 'marketplace' &&\n 'after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent',\n )}\n onClick={() => setMainTab('marketplace')}\n >\n {sk.tabMarketplace}\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mainTab === 'builtin'}\n className={cn(\n 'relative rounded-md px-3 py-2 text-sm font-medium transition-colors',\n mainTab === 'builtin' ? 'text-fg' : 'text-fg-muted hover:text-fg',\n mainTab === 'builtin' &&\n 'after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent',\n )}\n onClick={() => setMainTab('builtin')}\n >\n {sk.tabBuiltin}\n <span className=\"ml-1 tabular-nums text-fg-muted\">\n ({builtinTabStats.enabled}/{builtinTabStats.total})\n </span>\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mainTab === 'user'}\n className={cn(\n 'relative rounded-md px-3 py-2 text-sm font-medium transition-colors',\n mainTab === 'user' ? 'text-fg' : 'text-fg-muted hover:text-fg',\n mainTab === 'user' &&\n 'after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent',\n )}\n onClick={() => setMainTab('user')}\n >\n {sk.tabUser}\n <span className=\"ml-1 tabular-nums text-fg-muted\">\n ({userTabStats.enabled}/{userTabStats.total})\n </span>\n </button>\n </div>\n <div\n className={cn(\n 'flex min-h-9 min-w-0 items-center gap-2',\n mainTab === 'user'\n ? 'flex-nowrap overflow-x-auto pb-0.5 sm:justify-end'\n : 'flex-wrap sm:justify-end',\n )}\n >\n {mainTab === 'user' ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n 'inline-flex h-9 min-h-9 min-w-[9rem] shrink-0 items-center gap-1.5 rounded-lg border border-edge bg-surface-panel px-2.5 text-xs font-medium text-fg shadow-surface',\n interaction.transition,\n interaction.focusRingPanel,\n )}\n >\n <Funnel className=\"size-3.5 text-fg-muted\" strokeWidth={1.75} aria-hidden />\n <span>{filterLabel}</span>\n <ChevronDown className=\"size-3.5 text-fg-subtle\" strokeWidth={1.75} aria-hidden />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n className=\"z-50 min-w-[10rem] rounded-xl border border-edge bg-surface-panel p-1 shadow-popover dark:border-edge\"\n sideOffset={6}\n align=\"end\"\n >\n {(['all', 'global', 'workspace', 'extra'] as const).map((key) => (\n <DropdownMenu.Item\n key={key}\n className={cn(\n 'cursor-pointer rounded-lg px-3 py-2 text-sm text-fg outline-none',\n 'hover:bg-surface-hover data-[highlighted]:bg-surface-hover',\n )}\n onSelect={() => setSourceFilter(key)}\n >\n {key === 'all'\n ? sk.filterAll\n : key === 'global'\n ? sk.filterGlobal\n : key === 'workspace'\n ? sk.filterWorkspace\n : sk.filterExtra}\n </DropdownMenu.Item>\n ))}\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n ) : null}\n {mainTab === 'marketplace' ? (\n <>\n <div\n className=\"inline-flex h-9 shrink-0 rounded-lg border border-edge bg-surface-panel p-0.5 shadow-surface\"\n role=\"group\"\n aria-label={sk.marketplaceBrowseSwitchAria}\n >\n {(['skillhub', 'store'] as const).map((id) => {\n const selected = marketBrowseProvider === id;\n return (\n <button\n key={id}\n type=\"button\"\n className={cn(\n 'rounded-md px-2.5 py-1.5 text-xs font-medium transition-colors',\n interaction.focusRingPanel,\n selected\n ? 'bg-fg text-surface-panel dark:bg-fg dark:text-surface-base'\n : 'text-fg-muted hover:text-fg',\n )}\n aria-pressed={selected}\n onClick={() => setMarketBrowseProvider(id)}\n >\n {id === 'skillhub' ? sk.marketplaceBrowseSkillhub : sk.marketplaceBrowseStore}\n </button>\n );\n })}\n </div>\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n 'inline-flex h-9 min-h-9 min-w-[9rem] shrink-0 items-center gap-1.5 rounded-lg border border-edge bg-surface-panel px-2.5 text-xs font-medium text-fg shadow-surface',\n interaction.transition,\n interaction.focusRingPanel,\n )}\n >\n <Funnel className=\"size-3.5 text-fg-muted\" strokeWidth={1.75} aria-hidden />\n <span>\n {marketSort === 'newest' ? sk.marketplaceSortNewest : sk.marketplaceSortDownloads}\n </span>\n <ChevronDown className=\"size-3.5 text-fg-subtle\" strokeWidth={1.75} aria-hidden />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n className=\"z-50 min-w-[10rem] rounded-xl border border-edge bg-surface-panel p-1 shadow-popover dark:border-edge\"\n sideOffset={6}\n align=\"end\"\n >\n <DropdownMenu.Item\n className={cn(\n 'cursor-pointer rounded-lg px-3 py-2 text-sm text-fg outline-none',\n 'hover:bg-surface-hover data-[highlighted]:bg-surface-hover',\n )}\n onSelect={() => setMarketSort('downloads')}\n >\n {sk.marketplaceSortDownloads}\n </DropdownMenu.Item>\n <DropdownMenu.Item\n className={cn(\n 'cursor-pointer rounded-lg px-3 py-2 text-sm text-fg outline-none',\n 'hover:bg-surface-hover data-[highlighted]:bg-surface-hover',\n )}\n onSelect={() => setMarketSort('newest')}\n >\n {sk.marketplaceSortNewest}\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n </>\n ) : null}\n {mainTab === 'builtin' ? (\n <div className=\"h-9 min-w-[9rem] shrink-0\" aria-hidden />\n ) : null}\n </div>\n </div>\n\n {mainTab === 'marketplace' ? (\n <>\n <div\n className={cn(\n '-mx-1 flex min-h-[2.75rem] items-center gap-2 overflow-x-auto px-1 pb-1 pt-0.5 [scrollbar-width:thin]',\n !mpCategoriesLoading && mpCategories.length === 0 && 'min-h-0 pb-0 pt-0',\n )}\n role={mpCategories.length > 0 || mpCategoriesLoading ? 'tablist' : undefined}\n aria-label={\n mpCategories.length > 0 || mpCategoriesLoading ? sk.marketplaceCategoriesAria : undefined\n }\n >\n {mpCategories.length > 0 ? (\n <>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={marketCategoryId === ''}\n className={cn(\n 'shrink-0 rounded-full border px-3 py-1.5 text-xs font-medium transition-colors',\n interaction.focusRingPanel,\n marketCategoryId === ''\n ? 'border-fg bg-fg text-surface-panel dark:border-fg dark:bg-fg dark:text-surface-base'\n : 'border-edge bg-surface-panel text-fg-muted hover:border-edge-strong hover:text-fg dark:border-edge dark:bg-surface-hover/40',\n )}\n onClick={() => setMarketCategoryId('')}\n >\n {sk.marketplaceCategoryAll}\n </button>\n {mpCategories.map((c) => {\n const selected = marketCategoryId === c.id;\n return (\n <button\n key={c.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={selected}\n className={cn(\n 'max-w-[14rem] shrink-0 truncate rounded-full border px-3 py-1.5 text-xs font-medium transition-colors',\n interaction.focusRingPanel,\n selected\n ? 'border-fg bg-fg text-surface-panel dark:border-fg dark:bg-fg dark:text-surface-base'\n : 'border-edge bg-surface-panel text-fg-muted hover:border-edge-strong hover:text-fg dark:border-edge dark:bg-surface-hover/40',\n )}\n title={c.label}\n onClick={() => setMarketCategoryId(c.id)}\n >\n {c.label}\n </button>\n );\n })}\n </>\n ) : mpCategoriesLoading ? (\n <div className=\"flex gap-2 px-1\" aria-hidden>\n {Array.from({ length: 5 }, (_, i) => (\n <div\n key={i}\n className=\"h-8 w-[4.5rem] shrink-0 animate-pulse rounded-full bg-surface-hover motion-reduce:animate-none dark:bg-surface-active/50\"\n />\n ))}\n </div>\n ) : null}\n </div>\n {mpCategoriesError ? (\n <p className=\"text-xs text-red-600 dark:text-red-400\" role=\"alert\">\n {mpCategoriesError}\n </p>\n ) : null}\n {mpLoading ? (\n <div\n className=\"overflow-hidden rounded-2xl border border-edge-subtle bg-surface-base dark:border-edge-subtle\"\n aria-busy=\"true\"\n aria-label={sk.loading}\n >\n {Array.from({ length: SKILL_LIST_SKELETON_COUNT }, (_, i) => (\n <MarketplaceSkillListRowSkeleton key={i} />\n ))}\n </div>\n ) : mpError ? (\n <div\n className=\"rounded-xl border border-edge bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-edge dark:bg-red-950/40 dark:text-red-300\"\n role=\"alert\"\n >\n {mpError}\n </div>\n ) : !mpPayload || mpPayload.items.length === 0 ? (\n <div className=\"rounded-2xl border border-dashed border-edge py-16 text-center text-sm text-fg-muted\">\n {sk.marketplaceEmpty}\n </div>\n ) : (\n <>\n <div className=\"overflow-hidden rounded-2xl border border-edge-subtle bg-surface-base dark:border-edge-subtle\">\n {mpPayload.items.map((row) => {\n const installed = isSkillInstalledByName(row.id);\n const busy = installingMarketName === row.id;\n const skillhubPageUrl =\n marketBrowseProvider === 'skillhub' ? skillHubPublicSkillPageUrl(row.id) : null;\n return (\n <article\n key={row.id}\n className={cn(\n 'group relative flex items-center gap-4 border-b border-edge-subtle px-4 py-3.5 last:border-b-0',\n 'transition-colors hover:bg-surface-hover/50 dark:hover:bg-surface-hover/25',\n )}\n >\n <div\n role=\"button\"\n tabIndex={0}\n className={cn(\n 'flex min-w-0 flex-1 cursor-pointer items-start gap-4 rounded-lg text-left outline-none',\n interaction.focusRingPanel,\n )}\n aria-labelledby={`mp-skill-title-${row.id}`}\n onClick={(e) => {\n if ((e.target as HTMLElement).closest('a[href]')) return;\n void openMarketplaceDetail(row.id, row.name);\n }}\n onKeyDown={(e) => {\n if ((e.target as HTMLElement).closest('a[href]')) return;\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n void openMarketplaceDetail(row.id, row.name);\n }\n }}\n >\n <SkillCardIcon name={row.id} />\n <div className=\"min-w-0 flex-1 pr-2\">\n <h3\n id={`mp-skill-title-${row.id}`}\n className=\"text-[15px] font-semibold leading-snug tracking-tight text-fg\"\n >\n {row.name}\n </h3>\n <p\n className=\"mt-0.5 truncate text-sm leading-relaxed text-fg-muted\"\n title={row.description ? row.description : undefined}\n >\n {row.description || '—'}\n </p>\n <div className=\"mt-1.5 flex flex-wrap gap-1.5 text-[11px] text-fg-subtle\">\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50\">\n {sk.marketplaceAuthor}: {row.author.username}\n </span>\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50\">\n {sk.marketplaceDownloads}: {row.downloads}\n </span>\n {row.stars != null && row.stars > 0 ? (\n <span className=\"inline-flex items-center gap-0.5 rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50\">\n <Star className=\"size-3 shrink-0 text-amber-600 dark:text-amber-400\" strokeWidth={2} aria-hidden />\n {row.stars}\n </span>\n ) : null}\n {row.sourceLabel ? (\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50\">\n {sk.marketplaceSource}: {row.sourceLabel}\n </span>\n ) : null}\n {row.latestVersion ? (\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 font-mono text-[10px] dark:bg-surface-active/50\">\n {sk.marketplaceVersion}: {row.latestVersion}\n </span>\n ) : null}\n {installed ? (\n <span className=\"rounded-md bg-emerald-500/15 px-2 py-0.5 text-emerald-800 dark:text-emerald-200\">\n {sk.marketplaceInstalled}\n </span>\n ) : null}\n {skillhubPageUrl ? (\n <a\n href={skillhubPageUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={cn(\n 'inline-flex items-center gap-0.5 rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50',\n 'hover:bg-surface-hover/80 hover:text-fg-muted dark:hover:bg-surface-active/70',\n interaction.focusRingPanel,\n )}\n aria-label={sk.marketplaceOpenOnSkillhubAria}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n >\n <ExternalLink className=\"size-3 shrink-0\" strokeWidth={2} aria-hidden />\n {sk.marketplaceOpenOnSkillhub}\n </a>\n ) : null}\n </div>\n </div>\n </div>\n <div className=\"flex shrink-0 justify-end sm:pl-2\">\n <Button\n type=\"button\"\n variant={installed ? 'secondary' : 'primary'}\n className=\"min-w-[6.5rem]\"\n disabled={busy || mpLoading}\n onClick={() => void onMarketInstall(row.id)}\n >\n {busy ? sk.uploading : installed ? sk.marketplaceReinstall : sk.marketplaceInstall}\n </Button>\n </div>\n </article>\n );\n })}\n </div>\n <div className=\"flex flex-col items-center justify-between gap-3 sm:flex-row\">\n <p className=\"text-center text-xs text-fg-muted sm:text-left\">\n {interpolate(sk.marketplacePageStatus, {\n page: mpPayload.meta.page,\n totalPages: mpPayload.meta.totalPages,\n total: mpPayload.meta.total,\n })}\n </p>\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"h-9 gap-1 px-2\"\n disabled={mpLoading || marketPage <= 1}\n aria-label={sk.marketplacePagePrev}\n onClick={() => setMarketPage((p) => Math.max(1, p - 1))}\n >\n <ChevronLeft className=\"size-4\" strokeWidth={1.75} aria-hidden />\n <span className=\"sr-only sm:not-sr-only\">{sk.marketplacePagePrev}</span>\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"h-9 gap-1 px-2\"\n disabled={mpLoading || marketPage >= mpPayload.meta.totalPages}\n aria-label={sk.marketplacePageNext}\n onClick={() =>\n setMarketPage((p) => Math.min(mpPayload.meta.totalPages, p + 1))\n }\n >\n <span className=\"sr-only sm:not-sr-only\">{sk.marketplacePageNext}</span>\n <ChevronRight className=\"size-4\" strokeWidth={1.75} aria-hidden />\n </Button>\n </div>\n </div>\n </>\n )}\n </>\n ) : (\n <>\n {loading ? (\n <div\n className=\"overflow-hidden rounded-2xl border border-edge-subtle bg-surface-base dark:border-edge-subtle\"\n aria-busy=\"true\"\n aria-label={sk.loading}\n >\n {Array.from({ length: SKILL_LIST_SKELETON_COUNT }, (_, i) => (\n <SkillListRowSkeleton key={i} />\n ))}\n </div>\n ) : catalog.length === 0 ? (\n <div className=\"rounded-2xl border border-dashed border-edge py-16 text-center text-sm text-fg-muted\">\n {sk.empty}\n </div>\n ) : filteredCatalog.length === 0 ? (\n <div className=\"rounded-2xl border border-dashed border-edge py-16 text-center text-sm text-fg-muted\">\n {sk.noSearchResults}\n </div>\n ) : (\n <>\n {builtinCategories.length > 1 ? (\n <div\n role=\"tablist\"\n aria-label={sk.marketplaceCategoriesAria}\n className=\"-mx-1 flex gap-2 overflow-x-auto px-1 pb-1 pt-0.5 [scrollbar-width:thin]\"\n >\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={builtinCategoryFilter === ''}\n className={cn(\n 'shrink-0 rounded-full border px-3 py-1.5 text-xs font-medium transition-colors',\n interaction.focusRingPanel,\n builtinCategoryFilter === ''\n ? 'border-fg bg-fg text-surface-panel dark:border-fg dark:bg-fg dark:text-surface-base'\n : 'border-edge bg-surface-panel text-fg-muted hover:border-edge-strong hover:text-fg dark:border-edge dark:bg-surface-hover/40',\n )}\n onClick={() => setBuiltinCategoryFilter('')}\n >\n {sk.marketplaceCategoryAll}\n </button>\n {builtinCategories.map((cat) => {\n const selected = builtinCategoryFilter === cat;\n return (\n <button\n key={cat}\n type=\"button\"\n role=\"tab\"\n aria-selected={selected}\n className={cn(\n 'max-w-[14rem] shrink-0 truncate rounded-full border px-3 py-1.5 text-xs font-medium transition-colors',\n interaction.focusRingPanel,\n selected\n ? 'border-fg bg-fg text-surface-panel dark:border-fg dark:bg-fg dark:text-surface-base'\n : 'border-edge bg-surface-panel text-fg-muted hover:border-edge-strong hover:text-fg dark:border-edge dark:bg-surface-hover/40',\n )}\n title={categoryLabel(cat)}\n onClick={() => setBuiltinCategoryFilter(cat)}\n >\n {categoryLabel(cat)}\n </button>\n );\n })}\n </div>\n ) : null}\n {categoryFilteredCatalog.length === 0 ? (\n <div className=\"rounded-2xl border border-dashed border-edge py-16 text-center text-sm text-fg-muted\">\n {sk.noSearchResults}\n </div>\n ) : (\n <div className=\"overflow-hidden rounded-2xl border border-edge-subtle bg-surface-base dark:border-edge-subtle\">\n {categoryFilteredCatalog.map((row, i, arr) => (\n <article\n key={`${row.directoryId}-${row.path}`}\n className={cn(\n 'group relative flex items-center gap-4 border-b border-edge-subtle px-4 py-3.5',\n i === arr.length - 1 && 'border-b-0',\n 'transition-colors hover:bg-surface-hover/50 dark:hover:bg-surface-hover/25',\n )}\n >\n <button\n type=\"button\"\n className={cn(\n 'flex min-w-0 flex-1 cursor-pointer items-center gap-4 rounded-lg text-left outline-none',\n interaction.focusRingPanel,\n )}\n onClick={() => void openSkillDetail(row)}\n >\n <SkillCardIcon name={row.name} />\n <div className=\"min-w-0 flex-1 pr-2\">\n <h3 className=\"text-[15px] font-semibold leading-snug tracking-tight text-fg\">\n {row.name}\n </h3>\n <p\n className=\"mt-0.5 truncate text-sm leading-relaxed text-fg-muted\"\n title={row.description ? row.description : undefined}\n >\n {row.description || '—'}\n </p>\n {mainTab !== 'builtin' || row.managed ? (\n <div className=\"mt-1.5 flex flex-wrap gap-1.5 text-[11px] text-fg-subtle\">\n {mainTab !== 'builtin' ? (\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50\">\n {sourceLabel(row.source)}\n </span>\n ) : null}\n {row.managed ? (\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50\">\n {sk.col.managed}: {sk.yes}\n </span>\n ) : null}\n {row.hub ? (\n <span\n className=\"max-w-full truncate rounded-md bg-surface-hover/60 px-2 py-0.5 font-mono text-[10px] dark:bg-surface-active/50\"\n title={`${row.hub.source}${row.hub.ref ? `\\nref: ${row.hub.ref}` : ''}\\nupdated: ${row.hub.updatedAt}`}\n >\n {sk.hubRemote} ·{' '}\n {row.hub.kind === 'git' ? sk.hubKindGit : sk.hubKindArchive} ·{' '}\n {row.hub.source.length > 48\n ? `${row.hub.source.slice(0, 48)}…`\n : row.hub.source}\n </span>\n ) : null}\n </div>\n ) : null}\n </div>\n </button>\n <div\n className=\"flex shrink-0 items-center gap-1\"\n onClick={(e) => e.stopPropagation()}\n role=\"presentation\"\n >\n {row.managed ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n 'flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg',\n interaction.focusRingPanel,\n )}\n aria-label={sk.col.actions}\n >\n <MoreVertical className=\"size-4\" strokeWidth={1.75} />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n className=\"z-50 min-w-[8rem] rounded-xl border border-edge bg-surface-panel p-1 shadow-popover dark:border-edge\"\n sideOffset={4}\n align=\"end\"\n >\n <DropdownMenu.Item\n className={cn(\n 'flex cursor-pointer items-center gap-2 rounded-lg px-3 py-2 text-sm text-red-600 outline-none',\n 'hover:bg-red-50 data-[highlighted]:bg-red-50 dark:text-red-400 dark:hover:bg-red-950/40',\n )}\n onSelect={() => {\n setConfirmId(row.directoryId);\n setConfirmOpen(true);\n }}\n >\n <Trash2 className=\"size-4\" strokeWidth={1.75} aria-hidden />\n {sk.delete}\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n ) : null}\n <SkillEnableSwitch\n checked={enabledOverride[row.name] ?? row.enabled}\n onChange={(next) => void onSkillToggle(row.name, next)}\n />\n </div>\n </article>\n ))}\n </div>\n )}\n </>\n )}\n </>\n )}\n </section>\n </div>\n\n <Dialog.Root\n open={detailOpen}\n onOpenChange={(open) => {\n setDetailOpen(open);\n if (!open) {\n setDetailSource('catalog');\n setDetailMarkdown('');\n setDetailCatalogPreview(null);\n setDetailMarketplacePreview(null);\n setDetailError(null);\n setDetailTitle('');\n }\n }}\n >\n <Dialog.Portal>\n <Dialog.Overlay className=\"xopc-dialog-overlay fixed inset-0 z-[60] bg-scrim\" />\n <Dialog.Content\n className={cn(\n 'xopc-dialog-content fixed left-1/2 top-1/2 z-[60] flex h-[min(88vh,44rem)] max-h-[min(92vh,56rem)] w-[min(100%-2rem,min(92vw,56rem))]',\n '-translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-2xl border border-edge bg-surface-panel shadow-float dark:border-edge',\n )}\n >\n <div className=\"group flex min-h-[3.25rem] shrink-0 items-center gap-3 border-b border-edge px-4 py-3\">\n <SkillCardIcon name={detailTitle || '?'} />\n <Dialog.Title className=\"min-w-0 flex-1 truncate text-base font-semibold text-fg\">\n {detailTitle || '—'}\n </Dialog.Title>\n <Dialog.Close asChild>\n <button\n type=\"button\"\n className={cn(\n 'rounded-lg p-1.5 text-fg-muted hover:bg-surface-hover hover:text-fg',\n interaction.focusRingPanel,\n )}\n aria-label={sk.detailCloseAria}\n >\n <X className=\"size-5\" strokeWidth={1.75} aria-hidden />\n </button>\n </Dialog.Close>\n </div>\n <div className=\"flex min-h-[3.25rem] shrink-0 items-start gap-2 border-b border-blue-200/80 bg-blue-50/95 px-4 py-2.5 text-sm text-fg dark:border-blue-900/50 dark:bg-blue-950/45\">\n <Info className=\"mt-0.5 size-4 shrink-0 text-blue-600 dark:text-blue-400\" strokeWidth={1.75} aria-hidden />\n <p className=\"min-w-0 leading-relaxed\">\n {detailSource === 'store' && detailMarketplacePreview\n ? sk.detailModalBanner\n : detailSource === 'store'\n ? sk.detailModalBannerStore\n : sk.detailModalBanner}\n </p>\n </div>\n <div className=\"min-h-0 min-w-0 flex-1 overflow-auto px-4 py-4\">\n {detailLoading ? (\n <div\n className=\"flex h-full min-h-[14rem] flex-col gap-2.5 py-1\"\n aria-busy=\"true\"\n aria-label={sk.loading}\n >\n {Array.from({ length: 10 }, (_, i) => (\n <div\n key={i}\n className={cn(\n 'h-4 animate-pulse rounded-md bg-surface-hover dark:bg-surface-active/50',\n i % 3 === 0 ? 'w-[92%]' : i % 3 === 1 ? 'w-full' : 'w-4/5',\n )}\n />\n ))}\n </div>\n ) : detailError ? (\n <p className=\"text-sm text-red-600 dark:text-red-400\">{detailError}</p>\n ) : detailSource === 'catalog' && detailCatalogPreview ? (\n <SkillCatalogStructuredPreview preview={detailCatalogPreview} sk={sk} />\n ) : detailSource === 'store' && detailMarketplacePreview ? (\n <SkillCatalogStructuredPreview preview={detailMarketplacePreview} sk={sk} />\n ) : (\n <div className=\"markdown-content min-w-0 break-words\">\n <MarkdownView content={detailMarkdown} />\n </div>\n )}\n </div>\n <div className=\"flex shrink-0 justify-end gap-2 border-t border-edge px-4 py-3\">\n {detailSource === 'store' ? (\n <>\n <Button type=\"button\" variant=\"ghost\" onClick={() => setDetailOpen(false)}>\n {sk.cancel}\n </Button>\n <Button\n type=\"button\"\n variant=\"secondary\"\n disabled={\n !detailTitle ||\n detailLoading ||\n usingSkillInChatName === detailTitle ||\n installingMarketName === detailTitle\n }\n onClick={() => void onUseSkillInChat()}\n >\n {usingSkillInChatName === detailTitle ? sk.previewUseInChatBusy : sk.previewUseInChat}\n </Button>\n <Button\n type=\"button\"\n variant={isSkillInstalledByName(detailTitle) ? 'secondary' : 'primary'}\n disabled={!detailTitle || installingMarketName === detailTitle}\n onClick={() => {\n if (!detailTitle) return;\n void onMarketInstall(detailTitle, { useDetailProvider: true });\n }}\n >\n {installingMarketName === detailTitle\n ? sk.uploading\n : isSkillInstalledByName(detailTitle)\n ? sk.marketplaceReinstall\n : sk.marketplaceInstall}\n </Button>\n </>\n ) : (\n <>\n <Button\n type=\"button\"\n variant=\"secondary\"\n disabled={\n !detailTitle ||\n detailLoading ||\n usingSkillInChatName === detailTitle ||\n togglingSkillName === detailTitle\n }\n onClick={() => void onUseSkillInChat()}\n >\n {usingSkillInChatName === detailTitle ? sk.previewUseInChatBusy : sk.previewUseInChat}\n </Button>\n <Button\n type=\"button\"\n variant=\"primary\"\n disabled={!detailTitle || togglingSkillName === detailTitle}\n onClick={async () => {\n if (!detailTitle) return;\n const ok = await onSkillToggle(detailTitle, !detailEnabled);\n if (ok) setDetailOpen(false);\n }}\n >\n {detailEnabled ? sk.detailModalDisable : sk.detailModalEnable}\n </Button>\n </>\n )}\n </div>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n\n <Dialog.Root\n open={installOpen}\n onOpenChange={(open) => {\n setInstallOpen(open);\n if (!open) {\n setPendingFile(null);\n setDropActive(false);\n }\n }}\n >\n <Dialog.Portal>\n <Dialog.Overlay className=\"xopc-dialog-overlay fixed inset-0 z-[60] bg-scrim\" />\n <Dialog.Content\n className={cn(\n 'xopc-dialog-content fixed left-1/2 top-1/2 z-[60] max-h-[min(100vh-2rem,44rem)] w-[min(100%-2rem,min(92vw,48rem))] -translate-x-1/2 -translate-y-1/2 overflow-y-auto',\n 'rounded-2xl border border-edge bg-surface-panel p-6 shadow-float dark:border-edge',\n )}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <Dialog.Title className=\"text-base font-semibold text-fg\">{sk.installModalTitle}</Dialog.Title>\n <Dialog.Close asChild>\n <button\n type=\"button\"\n className={cn(\n 'rounded-lg p-1.5 text-fg-muted hover:bg-surface-hover hover:text-fg',\n interaction.focusRingPanel,\n )}\n aria-label={sk.installClose}\n >\n <X className=\"size-5\" strokeWidth={1.75} aria-hidden />\n <span className=\"sr-only\">{sk.installClose}</span>\n </button>\n </Dialog.Close>\n </div>\n\n <label\n className={cn(\n 'mt-4 flex min-h-[11rem] cursor-pointer flex-col items-center justify-center gap-3 rounded-xl border-2 border-dashed px-6 py-12 text-center transition-colors',\n dropActive\n ? 'border-accent bg-accent-soft/60 dark:bg-blue-950/40'\n : 'border-edge bg-surface-base dark:bg-surface-hover/30',\n )}\n onDragLeave={onModalDragLeave}\n onDragOver={onModalDragOver}\n onDrop={onModalDrop}\n >\n <input\n type=\"file\"\n accept=\".zip,.md,application/zip,text/markdown\"\n className=\"sr-only\"\n aria-label={sk.installModalDropHint}\n disabled={uploading}\n onChange={onFileInputChange}\n />\n <FileArchive className=\"size-12 text-fg-subtle\" strokeWidth={1.25} aria-hidden />\n <span className=\"text-sm text-fg-muted\">{sk.installModalDropHint}</span>\n {pendingFile ? (\n <span className=\"text-xs font-medium text-fg\">{pendingFile.name}</span>\n ) : null}\n </label>\n\n <div className=\"mt-5 space-y-2\">\n <p className=\"text-sm font-medium text-fg\">{sk.installModalReqTitle}</p>\n <ul className=\"list-inside list-disc space-y-1 text-sm text-fg-muted\">\n <li>{sk.installModalReq1}</li>\n <li>{sk.installModalReq2}</li>\n </ul>\n </div>\n\n <button\n type=\"button\"\n disabled={!pendingFile || uploading}\n className={cn(\n 'mt-6 flex w-full items-center justify-center rounded-xl py-3 text-sm font-semibold',\n 'transition-colors',\n !pendingFile || uploading\n ? 'cursor-not-allowed bg-surface-active text-fg-disabled'\n : 'bg-accent text-white hover:bg-accent-hover',\n interaction.focusRingPanel,\n )}\n onClick={() => void onInstallSubmit()}\n >\n {uploading ? sk.uploading : sk.installAction}\n </button>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n\n <Dialog.Root\n open={confirmOpen}\n onOpenChange={(open) => {\n setConfirmOpen(open);\n if (!open) setConfirmId(null);\n }}\n >\n <Dialog.Portal>\n <Dialog.Overlay className=\"xopc-dialog-overlay fixed inset-0 z-[60] bg-scrim\" />\n <Dialog.Content className=\"xopc-dialog-content fixed left-1/2 top-1/2 z-[60] w-[min(100%-2rem,24rem)] -translate-x-1/2 -translate-y-1/2 rounded-xl border border-edge bg-surface-panel p-4 shadow-popover dark:border-edge\">\n <Dialog.Title className=\"text-base font-semibold text-fg\">{sk.deleteTitle}</Dialog.Title>\n <p className=\"mt-2 text-sm text-fg-muted\">\n {confirmId ? interpolate(sk.deleteMessage, { id: confirmId }) : ''}\n </p>\n <div className=\"mt-4 flex justify-end gap-2\">\n <Button type=\"button\" variant=\"secondary\" onClick={() => setConfirmOpen(false)}>\n {sk.cancel}\n </Button>\n <Button\n type=\"button\"\n variant=\"primary\"\n className=\"bg-red-600 hover:bg-red-700\"\n onClick={() => void runDelete()}\n >\n {sk.deleteConfirm}\n </Button>\n </div>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n </div>\n );\n}\n","export async function fileToZipUpload(file: File): Promise<File> {\n const lower = file.name.toLowerCase();\n if (lower.endsWith('.zip')) return file;\n if (lower.endsWith('skill.md')) {\n const JSZip = (await import('jszip')).default;\n const zip = new JSZip();\n zip.file('SKILL.md', await file.arrayBuffer());\n const blob = await zip.generateAsync({ type: 'blob', compression: 'DEFLATE' });\n const base = file.name.replace(/\\.md$/i, '').replace(/\\s+/g, '-') || 'skill';\n return new File([blob], `${base}.zip`, { type: 'application/zip' });\n }\n throw new Error('invalid');\n}\n","import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type DragEvent,\n} from 'react';\nimport { useLocation, useNavigate, useSearchParams } from 'react-router-dom';\n\nimport {\n deleteSkill,\n getMarketplaceCategories,\n getMarketplacePackageDetail,\n getMarketplaceProvider,\n getMarketplaceSkills,\n getSkillMarkdown,\n getSkills,\n installMarketplaceSkill,\n patchSkillEnabled,\n reloadSkills,\n uploadSkillZip,\n} from '@/features/skills/skill-api';\nimport type {\n MarketplaceCategoryItem,\n MarketplacePackageItem,\n SkillCatalogEntry,\n SkillMarkdownPreviewPayload,\n} from '@/features/skills/skill.types';\nimport { fileToZipUpload } from '@/features/skills/skill-upload-zip';\nimport {\n BUILTIN_SKILL_CATEGORY_ORDER,\n MAIN_TAB_SET,\n MARKETPLACE_PROVIDER_PARAM,\n SOURCE_FILTER_SET,\n type MainTab,\n type SourceFilter,\n} from '@/features/skills/skills-page.constants';\nimport { normalizeCatalogEntry } from '@/features/skills/skills-page.utils';\nimport { messages } from '@/i18n/messages';\nimport { useGatewayStore } from '@/stores/gateway-store';\nimport { useLocaleStore } from '@/stores/locale-store';\n\nexport function useSkillsPage() {\n const language = useLocaleStore((s) => s.language);\n const m = messages(language);\n const sk = m.skills;\n const token = useGatewayStore((st) => st.token);\n const hasToken = Boolean(token);\n const navigate = useNavigate();\n const [searchParams, setSearchParams] = useSearchParams();\n\n const mprovRaw = searchParams.get(MARKETPLACE_PROVIDER_PARAM);\n const urlMarketProvider =\n mprovRaw === 'store' || mprovRaw === 'skillhub' ? mprovRaw : null;\n\n const [catalog, setCatalog] = useState<SkillCatalogEntry[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [uploading, setUploading] = useState(false);\n const initialSearch = searchParams.get('q') ?? '';\n const initialTabRaw = searchParams.get('tab');\n const initialSourceRaw = searchParams.get('source');\n const initialTab: MainTab = MAIN_TAB_SET.has(initialTabRaw as MainTab)\n ? (initialTabRaw as MainTab)\n : 'marketplace';\n const initialSourceFilter: SourceFilter = SOURCE_FILTER_SET.has(initialSourceRaw as SourceFilter)\n ? (initialSourceRaw as SourceFilter)\n : 'all';\n\n const [searchQuery, setSearchQuery] = useState(initialSearch);\n const [actionFeedback, setActionFeedback] = useState<{\n kind: 'success' | 'error';\n message: string;\n } | null>(null);\n\n const [mainTab, setMainTab] = useState<MainTab>(initialTab);\n const [sourceFilter, setSourceFilter] = useState<SourceFilter>(initialSourceFilter);\n const [builtinCategoryFilter, setBuiltinCategoryFilter] = useState('');\n\n const [installOpen, setInstallOpen] = useState(false);\n const [pendingFile, setPendingFile] = useState<File | null>(null);\n const [dropActive, setDropActive] = useState(false);\n\n const [confirmOpen, setConfirmOpen] = useState(false);\n const [confirmId, setConfirmId] = useState<string | null>(null);\n const [togglingSkillName, setTogglingSkillName] = useState<string | null>(null);\n const [enabledOverride, setEnabledOverride] = useState<Record<string, boolean>>({});\n\n const [detailOpen, setDetailOpen] = useState(false);\n const [detailSource, setDetailSource] = useState<'catalog' | 'store'>('catalog');\n const [detailTitle, setDetailTitle] = useState('');\n const [detailMarkdown, setDetailMarkdown] = useState('');\n const [detailCatalogPreview, setDetailCatalogPreview] = useState<SkillMarkdownPreviewPayload | null>(null);\n const [detailMarketplacePreview, setDetailMarketplacePreview] = useState<SkillMarkdownPreviewPayload | null>(\n null,\n );\n const [detailLoading, setDetailLoading] = useState(false);\n const [detailError, setDetailError] = useState<string | null>(null);\n\n const [marketSort, setMarketSort] = useState<'downloads' | 'newest'>('downloads');\n const [marketPage, setMarketPage] = useState(1);\n const [mpLoading, setMpLoading] = useState(false);\n const [mpError, setMpError] = useState<string | null>(null);\n const [mpPayload, setMpPayload] = useState<{\n items: MarketplacePackageItem[];\n meta: { page: number; pageSize: number; total: number; totalPages: number };\n provider?: 'store' | 'skillhub';\n } | null>(null);\n const [installingMarketName, setInstallingMarketName] = useState<string | null>(null);\n const [usingSkillInChatName, setUsingSkillInChatName] = useState<string | null>(null);\n const [marketCategoryId, setMarketCategoryId] = useState('');\n const [mpCategories, setMpCategories] = useState<MarketplaceCategoryItem[]>([]);\n const [mpCategoriesError, setMpCategoriesError] = useState<string | null>(null);\n const [mpCategoriesLoading, setMpCategoriesLoading] = useState(false);\n const [marketBrowseProvider, setMarketBrowseProvider] = useState<'store' | 'skillhub' | null>(null);\n const marketplaceDetailProviderRef = useRef<'store' | 'skillhub' | null>(null);\n const prevMarketBrowseProviderRef = useRef<'store' | 'skillhub' | null>(null);\n\n const load = useCallback(\n async (opts?: { silent?: boolean }): Promise<{ ok: true } | { ok: false; message: string }> => {\n const silent = opts?.silent === true;\n if (!silent) {\n setLoading(true);\n }\n setError(null);\n try {\n const data = await getSkills(language !== 'en' ? language : undefined);\n setCatalog(data.catalog.map(normalizeCatalogEntry));\n return { ok: true };\n } catch (e) {\n const message = e instanceof Error ? e.message : sk.loadFailed;\n setError(message);\n return { ok: false, message };\n } finally {\n if (!silent) {\n setLoading(false);\n }\n }\n },\n [language, sk.loadFailed],\n );\n\n useEffect(() => {\n if (!hasToken) return;\n void load();\n }, [hasToken, load]);\n\n useEffect(() => {\n if (!hasToken) {\n setMarketBrowseProvider(null);\n marketplaceDetailProviderRef.current = null;\n return;\n }\n if (urlMarketProvider) {\n setMarketBrowseProvider(urlMarketProvider);\n }\n }, [hasToken, urlMarketProvider]);\n\n useEffect(() => {\n if (!hasToken || urlMarketProvider != null) return;\n let cancelled = false;\n void getMarketplaceProvider()\n .then((info) => {\n if (!cancelled) {\n setMarketBrowseProvider((prev) => (prev != null ? prev : info.provider));\n }\n })\n .catch(() => {\n if (!cancelled) {\n setMarketBrowseProvider((prev) => (prev != null ? prev : 'skillhub'));\n }\n });\n return () => {\n cancelled = true;\n };\n }, [hasToken, urlMarketProvider]);\n\n useEffect(() => {\n const nextQ = searchParams.get('q') ?? '';\n const nextTabRaw = searchParams.get('tab');\n const nextSourceRaw = searchParams.get('source');\n const nextTab: MainTab = MAIN_TAB_SET.has(nextTabRaw as MainTab)\n ? (nextTabRaw as MainTab)\n : 'marketplace';\n const nextSource: SourceFilter = SOURCE_FILTER_SET.has(nextSourceRaw as SourceFilter)\n ? (nextSourceRaw as SourceFilter)\n : 'all';\n setSearchQuery((prev) => (prev === nextQ ? prev : nextQ));\n setMainTab((prev) => (prev === nextTab ? prev : nextTab));\n setSourceFilter((prev) => (prev === nextSource ? prev : nextSource));\n const nextMcat = searchParams.get('mcat') ?? '';\n if (nextTab === 'marketplace') {\n setMarketCategoryId((prev) => (prev === nextMcat ? prev : nextMcat));\n } else {\n setMarketCategoryId('');\n }\n }, [searchParams]);\n\n useEffect(() => {\n if (mainTab !== 'marketplace') return;\n setMarketPage(1);\n }, [searchQuery, marketSort, mainTab, marketCategoryId, marketBrowseProvider]);\n\n useEffect(() => {\n if (mainTab !== 'marketplace' || !marketBrowseProvider) {\n prevMarketBrowseProviderRef.current = marketBrowseProvider;\n return;\n }\n const prev = prevMarketBrowseProviderRef.current;\n prevMarketBrowseProviderRef.current = marketBrowseProvider;\n if (prev != null && prev !== marketBrowseProvider) {\n setMarketCategoryId('');\n }\n }, [mainTab, marketBrowseProvider]);\n\n /** Before paint: avoid one frame of empty/stale list then skeleton (useEffect runs too late). */\n useLayoutEffect(() => {\n if (!hasToken || mainTab !== 'marketplace') return;\n setMpLoading(true);\n }, [hasToken, mainTab, marketCategoryId, marketPage, marketSort, searchQuery, marketBrowseProvider]);\n\n useLayoutEffect(() => {\n if (!hasToken || mainTab !== 'marketplace') return;\n setMpCategoriesLoading(true);\n }, [hasToken, mainTab, marketBrowseProvider]);\n\n useEffect(() => {\n if (mainTab === 'marketplace') return;\n setMpCategories([]);\n setMpCategoriesError(null);\n setMpCategoriesLoading(false);\n }, [mainTab]);\n\n useEffect(() => {\n if (!hasToken || mainTab !== 'marketplace' || !marketBrowseProvider) return;\n let cancelled = false;\n setMpError(null);\n void getMarketplaceSkills({\n q: searchQuery.trim() || undefined,\n page: marketPage,\n pageSize: 20,\n sort: marketSort,\n category: marketCategoryId.trim() || undefined,\n provider: marketBrowseProvider,\n })\n .then((payload) => {\n if (!cancelled) setMpPayload(payload);\n })\n .catch((e) => {\n if (!cancelled) {\n setMpError(e instanceof Error ? e.message : sk.marketplaceLoadFailed);\n setMpPayload(null);\n }\n })\n .finally(() => {\n if (!cancelled) setMpLoading(false);\n });\n return () => {\n cancelled = true;\n };\n }, [\n hasToken,\n mainTab,\n marketCategoryId,\n marketPage,\n marketSort,\n searchQuery,\n sk.marketplaceLoadFailed,\n marketBrowseProvider,\n ]);\n\n useEffect(() => {\n if (!hasToken || mainTab !== 'marketplace' || !marketBrowseProvider) return;\n let cancelled = false;\n setMpCategoriesError(null);\n void getMarketplaceCategories({ provider: marketBrowseProvider })\n .then((r) => {\n if (!cancelled) setMpCategories(r.items);\n })\n .catch((e) => {\n if (!cancelled) {\n setMpCategories([]);\n setMpCategoriesError(e instanceof Error ? e.message : sk.marketplaceCategoriesFailed);\n }\n })\n .finally(() => {\n if (!cancelled) setMpCategoriesLoading(false);\n });\n return () => {\n cancelled = true;\n setMpCategoriesLoading(false);\n };\n }, [hasToken, mainTab, sk.marketplaceCategoriesFailed, marketBrowseProvider]);\n\n useEffect(() => {\n if (!marketCategoryId.trim() || mpCategories.length === 0) return;\n if (!mpCategories.some((c) => c.id === marketCategoryId)) {\n setMarketCategoryId('');\n }\n }, [mpCategories, marketCategoryId]);\n\n useEffect(() => {\n setSearchParams(\n (prev) => {\n const params = new URLSearchParams(prev);\n const nextQ = searchQuery.trim();\n if (nextQ) params.set('q', nextQ);\n else params.delete('q');\n if (mainTab !== 'marketplace') params.set('tab', mainTab);\n else params.delete('tab');\n if (sourceFilter !== 'all') params.set('source', sourceFilter);\n else params.delete('source');\n if (mainTab === 'marketplace' && marketCategoryId.trim()) {\n params.set('mcat', marketCategoryId.trim());\n } else {\n params.delete('mcat');\n }\n if (mainTab === 'marketplace' && marketBrowseProvider) {\n params.set(MARKETPLACE_PROVIDER_PARAM, marketBrowseProvider);\n } else {\n params.delete(MARKETPLACE_PROVIDER_PARAM);\n }\n if (params.toString() === prev.toString()) {\n return prev;\n }\n return params;\n },\n { replace: true },\n );\n }, [mainTab, marketCategoryId, marketBrowseProvider, searchQuery, setSearchParams, sourceFilter]);\n\n const showFeedback = useCallback((kind: 'success' | 'error', message: string, durationMs = 5000) => {\n setActionFeedback({ kind, message });\n window.setTimeout(() => setActionFeedback(null), durationMs);\n }, []);\n\n const openSkillDetail = useCallback(\n async (row: SkillCatalogEntry) => {\n setDetailSource('catalog');\n setDetailOpen(true);\n setDetailTitle(row.name);\n setDetailMarkdown('');\n setDetailCatalogPreview(null);\n setDetailMarketplacePreview(null);\n setDetailError(null);\n setDetailLoading(true);\n try {\n const preview = await getSkillMarkdown(row.name, language !== 'en' ? language : undefined);\n setDetailCatalogPreview(preview);\n setDetailTitle(preview.name);\n } catch (e) {\n setDetailCatalogPreview(null);\n setDetailError(e instanceof Error ? e.message : sk.detailLoadFailed);\n } finally {\n setDetailLoading(false);\n }\n },\n [language, sk.detailLoadFailed],\n );\n\n const openMarketplaceDetail = useCallback(\n async (packageId: string, listTitle?: string) => {\n const browse = marketBrowseProvider;\n if (!browse) return;\n marketplaceDetailProviderRef.current = browse;\n setDetailSource('store');\n setDetailOpen(true);\n setDetailTitle(listTitle?.trim() || packageId);\n setDetailMarkdown('');\n setDetailCatalogPreview(null);\n setDetailMarketplacePreview(null);\n setDetailError(null);\n setDetailLoading(true);\n try {\n const pkg = await getMarketplacePackageDetail(packageId, { provider: browse });\n setDetailTitle(pkg.name);\n if (pkg.skillDocPreview) {\n setDetailMarketplacePreview(pkg.skillDocPreview);\n setDetailMarkdown('');\n } else {\n setDetailMarketplacePreview(null);\n const readme = pkg.readme?.trim();\n if (readme) {\n setDetailMarkdown(readme);\n } else if (pkg.description?.trim()) {\n setDetailMarkdown(`## ${pkg.name}\\n\\n${pkg.description.trim()}`);\n } else {\n setDetailMarkdown(`*${sk.marketplaceNoReadme}*`);\n }\n }\n } catch (e) {\n setDetailMarketplacePreview(null);\n setDetailError(e instanceof Error ? e.message : sk.detailLoadFailed);\n } finally {\n setDetailLoading(false);\n }\n },\n [marketBrowseProvider, sk.detailLoadFailed, sk.marketplaceNoReadme],\n );\n\n const onSkillToggle = useCallback(\n async (name: string, next: boolean): Promise<boolean> => {\n setTogglingSkillName(name);\n setEnabledOverride((prev) => ({ ...prev, [name]: next }));\n setActionFeedback(null);\n try {\n await patchSkillEnabled(name, next);\n await load({ silent: true });\n return true;\n } catch (e) {\n setEnabledOverride((prev) => {\n const { [name]: _, ...rest } = prev;\n return rest;\n });\n const msg = e instanceof Error ? e.message : sk.skillToggleFailed;\n showFeedback('error', msg);\n return false;\n } finally {\n setTogglingSkillName(null);\n setEnabledOverride((prev) => {\n const { [name]: _, ...rest } = prev;\n return rest;\n });\n }\n },\n [load, showFeedback, sk.skillToggleFailed],\n );\n\n const onReloadClick = useCallback(async () => {\n setActionFeedback(null);\n setLoading(true);\n setError(null);\n try {\n await reloadSkills();\n } catch (e) {\n const msg = e instanceof Error ? e.message : sk.reloadFailed;\n setError(msg);\n setLoading(false);\n return;\n }\n await load();\n }, [load, sk.reloadFailed]);\n\n const builtinTabStats = useMemo(() => {\n const rows = catalog.filter((r) => r.source === 'builtin');\n return {\n total: rows.length,\n enabled: rows.filter((r) => enabledOverride[r.name] ?? r.enabled).length,\n };\n }, [catalog, enabledOverride]);\n\n const userTabStats = useMemo(() => {\n const rows = catalog.filter((r) => r.source !== 'builtin');\n return {\n total: rows.length,\n enabled: rows.filter((r) => enabledOverride[r.name] ?? r.enabled).length,\n };\n }, [catalog, enabledOverride]);\n\n const detailFromCatalog = useMemo(\n () => (detailTitle ? catalog.find((r) => r.name === detailTitle) : undefined),\n [catalog, detailTitle],\n );\n const detailEnabled =\n detailFromCatalog == null\n ? true\n : (enabledOverride[detailTitle] ?? detailFromCatalog.enabled);\n\n const filteredCatalog = useMemo(() => {\n const q = searchQuery.trim().toLowerCase();\n let rows = catalog;\n\n if (mainTab === 'builtin') {\n rows = rows.filter((r) => r.source === 'builtin');\n } else {\n rows = rows.filter((r) => r.source !== 'builtin');\n if (sourceFilter !== 'all') {\n rows = rows.filter((r) => r.source === sourceFilter);\n }\n }\n\n if (!q) return rows;\n return rows.filter((row) => {\n const blob = [\n row.name,\n row.description,\n row.directoryId,\n row.path,\n row.source,\n row.hub?.source,\n row.hub?.ref,\n ]\n .filter(Boolean)\n .join(' ')\n .toLowerCase();\n return blob.includes(q);\n });\n }, [catalog, searchQuery, mainTab, sourceFilter]);\n\n const builtinCategories = useMemo(() => {\n const seen = new Set<string>();\n const ordered: string[] = [];\n for (const entry of filteredCatalog) {\n const cat = entry.category;\n if (!cat || seen.has(cat)) continue;\n seen.add(cat);\n ordered.push(cat);\n }\n return ordered.sort((a, b) => {\n const ai = BUILTIN_SKILL_CATEGORY_ORDER.indexOf(a as (typeof BUILTIN_SKILL_CATEGORY_ORDER)[number]);\n const bi = BUILTIN_SKILL_CATEGORY_ORDER.indexOf(b as (typeof BUILTIN_SKILL_CATEGORY_ORDER)[number]);\n if (ai >= 0 && bi >= 0) return ai - bi;\n if (ai >= 0) return -1;\n if (bi >= 0) return 1;\n return a.localeCompare(b);\n });\n }, [filteredCatalog]);\n\n const categoryLabel = useCallback(\n (cat: string): string => {\n const labels = sk.categoryLabel as Record<string, string> | undefined;\n return labels?.[cat] || cat;\n },\n [sk.categoryLabel],\n );\n\n const categoryFilteredCatalog = useMemo(() => {\n if (!builtinCategoryFilter) return filteredCatalog;\n return filteredCatalog.filter((r) => r.category === builtinCategoryFilter);\n }, [filteredCatalog, builtinCategoryFilter]);\n\n const runUpload = async (file: File) => {\n setActionFeedback(null);\n setUploading(true);\n setError(null);\n try {\n let upload: File;\n try {\n upload = await fileToZipUpload(file);\n } catch {\n setError(sk.invalidFile);\n showFeedback('error', sk.invalidFile);\n return;\n }\n await uploadSkillZip(upload, { overwrite: true });\n await load();\n showFeedback('success', sk.installSuccess);\n setInstallOpen(false);\n setPendingFile(null);\n setMainTab('user');\n } catch (err) {\n setError(err instanceof Error ? err.message : sk.uploadFailed);\n showFeedback('error', err instanceof Error ? err.message : sk.uploadFailed);\n } finally {\n setUploading(false);\n }\n };\n\n const onInstallSubmit = () => {\n if (pendingFile) void runUpload(pendingFile);\n };\n\n const onFileInputChange = (e: ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n e.target.value = '';\n if (file) setPendingFile(file);\n };\n\n const onModalDragOver = (e: DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (e.dataTransfer.types.includes('Files')) {\n setDropActive(true);\n e.dataTransfer.dropEffect = 'copy';\n }\n };\n\n const onModalDragLeave = (e: DragEvent) => {\n const root = e.currentTarget as HTMLElement;\n const to = e.relatedTarget as Node | null;\n if (to && root.contains(to)) return;\n setDropActive(false);\n };\n\n const onModalDrop = (e: DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setDropActive(false);\n const file = e.dataTransfer?.files?.[0];\n if (file) setPendingFile(file);\n };\n\n const sourceLabel = (source: SkillCatalogEntry['source']): string => {\n switch (source) {\n case 'builtin':\n return sk.source.builtin;\n case 'workspace':\n return sk.source.workspace;\n case 'global':\n return sk.source.global;\n case 'extra':\n return sk.source.extra;\n default:\n return source;\n }\n };\n\n const runDelete = async () => {\n const id = confirmId;\n setConfirmOpen(false);\n setConfirmId(null);\n if (!id) return;\n setActionFeedback(null);\n try {\n await deleteSkill(id);\n await load();\n } catch (e) {\n setError(e instanceof Error ? e.message : sk.deleteFailed);\n }\n };\n\n const isSkillInstalledByName = useCallback(\n (name: string) => catalog.some((r) => r.name === name),\n [catalog],\n );\n\n const onUseSkillInChat = useCallback(async () => {\n const name = detailTitle.trim();\n if (!name) return;\n setActionFeedback(null);\n const needsMarketInstall = detailSource === 'store' && !isSkillInstalledByName(name);\n if (needsMarketInstall) setUsingSkillInChatName(name);\n try {\n if (needsMarketInstall) {\n const mp = marketplaceDetailProviderRef.current ?? marketBrowseProvider;\n await installMarketplaceSkill({\n name,\n overwrite: false,\n ...(mp ? { provider: mp } : {}),\n });\n await load({ silent: true });\n }\n setDetailOpen(false);\n navigate(`/chat/new?skill=${encodeURIComponent(name)}`);\n } catch (e) {\n showFeedback('error', e instanceof Error ? e.message : sk.uploadFailed);\n } finally {\n setUsingSkillInChatName(null);\n }\n }, [\n detailTitle,\n detailSource,\n isSkillInstalledByName,\n load,\n navigate,\n showFeedback,\n sk.uploadFailed,\n marketBrowseProvider,\n ]);\n\n const onMarketInstall = useCallback(\n async (name: string, opts?: { useDetailProvider?: boolean }) => {\n const installed = isSkillInstalledByName(name);\n if (installed) {\n const ok = window.confirm(sk.marketplaceReinstallConfirm);\n if (!ok) return;\n }\n setActionFeedback(null);\n setInstallingMarketName(name);\n try {\n const p = opts?.useDetailProvider\n ? marketplaceDetailProviderRef.current ?? marketBrowseProvider\n : marketBrowseProvider;\n await installMarketplaceSkill({\n name,\n overwrite: installed,\n ...(p ? { provider: p } : {}),\n });\n await load({ silent: true });\n showFeedback('success', sk.installSuccess);\n setDetailOpen(false);\n setMainTab('user');\n } catch (e) {\n showFeedback('error', e instanceof Error ? e.message : sk.uploadFailed);\n } finally {\n setInstallingMarketName(null);\n }\n },\n [\n isSkillInstalledByName,\n load,\n marketBrowseProvider,\n showFeedback,\n sk.installSuccess,\n sk.marketplaceReinstallConfirm,\n sk.uploadFailed,\n ],\n );\n\n const filterLabel =\n sourceFilter === 'all'\n ? sk.filterAll\n : sourceFilter === 'global'\n ? sk.filterGlobal\n : sourceFilter === 'workspace'\n ? sk.filterWorkspace\n : sk.filterExtra;\n\n const { pathname } = useLocation();\n const inSettingsShell = pathname.startsWith('/settings/');\n\n return {\n sk,\n hasToken,\n catalog,\n loading,\n error,\n uploading,\n searchQuery,\n setSearchQuery,\n actionFeedback,\n mainTab,\n setMainTab,\n sourceFilter,\n setSourceFilter,\n builtinCategoryFilter,\n setBuiltinCategoryFilter,\n installOpen,\n setInstallOpen,\n pendingFile,\n setPendingFile,\n dropActive,\n setDropActive,\n confirmOpen,\n setConfirmOpen,\n confirmId,\n setConfirmId,\n togglingSkillName,\n enabledOverride,\n detailOpen,\n setDetailOpen,\n detailSource,\n setDetailSource,\n detailTitle,\n setDetailTitle,\n detailMarkdown,\n setDetailMarkdown,\n detailCatalogPreview,\n setDetailCatalogPreview,\n detailMarketplacePreview,\n setDetailMarketplacePreview,\n detailLoading,\n detailError,\n setDetailError,\n marketSort,\n setMarketSort,\n marketPage,\n setMarketPage,\n mpLoading,\n mpError,\n mpPayload,\n installingMarketName,\n usingSkillInChatName,\n onUseSkillInChat,\n marketCategoryId,\n setMarketCategoryId,\n mpCategories,\n mpCategoriesError,\n mpCategoriesLoading,\n marketBrowseProvider,\n setMarketBrowseProvider,\n builtinTabStats,\n userTabStats,\n detailEnabled,\n filteredCatalog,\n builtinCategories,\n categoryFilteredCatalog,\n filterLabel,\n inSettingsShell,\n categoryLabel,\n onReloadClick,\n openSkillDetail,\n openMarketplaceDetail,\n onSkillToggle,\n onInstallSubmit,\n onFileInputChange,\n onModalDragOver,\n onModalDragLeave,\n onModalDrop,\n sourceLabel,\n runDelete,\n onMarketInstall,\n isSkillInstalledByName,\n };\n}\n\nexport type SkillsPageVm = ReturnType<typeof useSkillsPage>;\n","import { SkillsPageView } from '@/features/skills/skills-page-view';\nimport { useSkillsPage } from '@/features/skills/use-skills-page';\n\nexport function SkillsPage() {\n const vm = useSkillsPage();\n return <SkillsPageView vm={vm} />;\n}\n"],"file":"skills-page-UzbTgnVY.js"}
|
|
1
|
+
{"version":3,"mappings":"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I,CACF,IAAM,EAAI,GAAM,kBACZ,GAA6B,SAAW,EACxC,EACJ,MAAM,GAAwB,CAC5B,OACA,UAAW,EACX,GAAI,EAAI,CAAE,SAAU,EAAG,CAAG,EAAE,CAC7B,CAAC,CACF,MAAM,EAAK,CAAE,OAAQ,GAAM,CAAC,CAC5B,EAAa,UAAW,EAAG,eAAe,CAC1C,EAAc,GAAM,CACpB,GAAW,OAAO,OACX,EAAG,CACV,EAAa,QAAS,aAAa,MAAQ,EAAE,QAAU,EAAG,aAAa,QAC/D,CACR,GAAwB,KAAK,IAGjC,CACE,GACA,EACA,EACA,EACA,EAAG,eACH,EAAG,4BACH,EAAG,aACJ,CACF,CAEK,GACJ,IAAiB,MACb,EAAG,UACH,IAAiB,SACf,EAAG,aACH,IAAiB,YACf,EAAG,gBACH,EAAG,YAEP,CAAE,aAAa,GAAa,CAGlC,MAAO,CACL,KACA,WACA,UACA,WACA,SACA,aACA,cACA,kBACA,kBACA,UACA,cACA,eACA,kBACA,wBACA,4BACA,eACA,iBACA,cACA,iBACA,cACA,gBACA,eACA,kBACA,aACA,gBACA,qBACA,kBACA,cACA,gBACA,gBACA,mBACA,cACA,iBACA,kBACA,oBACA,wBACA,0BACA,4BACA,8BACA,iBACA,eACA,iBACA,aACA,gBACA,aACA,iBACA,YACA,WACA,aACA,wBACA,wBACA,oBACA,mBACA,uBACA,eACA,qBACA,uBACA,uBACA,0BACA,mBACA,gBACA,iBACA,kBACA,qBACA,2BACA,eACA,gBArEsB,GAAS,WAAW,aAqE1C,CACA,iBACA,iBACA,mBACA,yBACA,iBACA,mBACA,qBACA,mBACA,oBACA,eACA,eACA,aACA,mBACA,0BACD,CCzxBH,SAAgB,IAAa,CAE3B,OAAO,SAAC,EAAD,CAAoB,GADhB,GACgB,CAAM","names":[],"ignoreList":[],"sources":["../../../../../web/src/features/skills/skill-card-icon.tsx","../../../../../web/src/features/skills/skills-page.utils.ts","../../../../../web/src/features/skills/skill-catalog-structured-preview.tsx","../../../../../web/src/features/skills/skills-page-header-end.tsx","../../../../../web/src/features/skills/skills-page-primitives.tsx","../../../../../web/src/features/skills/skills-page.constants.ts","../../../../../web/src/features/skills/skills-page-view.tsx","../../../../../web/src/features/skills/skill-upload-zip.ts","../../../../../web/src/features/skills/use-skills-page.ts","../../../../../web/src/features/skills/skills-page.tsx"],"sourcesContent":["import { cn } from '@/lib/cn';\n\n/** Pastel tile + saturated letter (light / dark pairs), stable per skill name hash. */\nconst SKILL_INITIAL_PALETTE: { light: string; dark: string }[] = [\n { light: 'bg-sky-100 text-sky-800', dark: 'dark:bg-sky-950/55 dark:text-sky-200' },\n { light: 'bg-violet-100 text-violet-800', dark: 'dark:bg-violet-950/55 dark:text-violet-200' },\n { light: 'bg-emerald-100 text-emerald-800', dark: 'dark:bg-emerald-950/55 dark:text-emerald-200' },\n { light: 'bg-orange-100 text-orange-800', dark: 'dark:bg-orange-950/55 dark:text-orange-200' },\n { light: 'bg-rose-100 text-rose-800', dark: 'dark:bg-rose-950/55 dark:text-rose-200' },\n { light: 'bg-amber-100 text-amber-900', dark: 'dark:bg-amber-950/55 dark:text-amber-200' },\n { light: 'bg-cyan-100 text-cyan-800', dark: 'dark:bg-cyan-950/55 dark:text-cyan-200' },\n { light: 'bg-indigo-100 text-indigo-800', dark: 'dark:bg-indigo-950/55 dark:text-indigo-200' },\n { light: 'bg-fuchsia-100 text-fuchsia-800', dark: 'dark:bg-fuchsia-950/55 dark:text-fuchsia-200' },\n { light: 'bg-teal-100 text-teal-800', dark: 'dark:bg-teal-950/55 dark:text-teal-200' },\n];\n\nfunction hashSkillNameKey(name: string): number {\n let h = 0;\n for (let i = 0; i < name.length; i += 1) {\n h = (Math.imul(31, h) + name.charCodeAt(i)) | 0;\n }\n return Math.abs(h);\n}\n\n/** First letter or digit (Unicode letters included); skips leading punctuation in slugs. */\nfunction skillInitialLetter(name: string): string {\n const t = name.trim();\n if (!t) return '?';\n const m = t.match(/[\\p{L}\\p{N}]/u);\n if (m) {\n const ch = m[0];\n return ch.toLocaleUpperCase('en-US');\n }\n return t[0];\n}\n\nexport function SkillCardIcon({ name, className }: { name: string; className?: string }) {\n const initial = skillInitialLetter(name);\n const pair = SKILL_INITIAL_PALETTE[hashSkillNameKey(name) % SKILL_INITIAL_PALETTE.length];\n return (\n <div\n className={cn(\n 'flex size-11 shrink-0 items-center justify-center rounded-xl font-semibold tracking-tight shadow-surface',\n 'text-[1.05rem] ring-1 ring-inset ring-black/[0.06] dark:ring-white/[0.1]',\n 'transition-[transform,box-shadow] duration-200 ease-out group-hover:ring-black/[0.1] dark:group-hover:ring-white/[0.14]',\n 'group-hover:-translate-y-px',\n pair.light,\n pair.dark,\n className,\n )}\n aria-hidden\n >\n {initial}\n </div>\n );\n}\n","import type { SkillCatalogEntry, SkillInstallSpecApi } from '@/features/skills/skill.types';\n\nconst SKILLHUB_PUBLIC_ORIGIN = 'https://skillhub.cn';\n\n/**\n * Public SkillHub web URL for a marketplace row `id` (canonical slug, e.g. `self-improving-agent` or `team--skill`).\n * Site shape: `https://skillhub.cn/skills/<slug>`.\n */\nexport function skillHubPublicSkillPageUrl(canonicalSlug: string): string | null {\n const id = canonicalSlug.trim();\n if (!id) return null;\n return `${SKILLHUB_PUBLIC_ORIGIN}/skills/${encodeURIComponent(id)}`;\n}\n\nexport function interpolate(template: string, params: Record<string, string | number>): string {\n return template.replace(/\\{\\{(\\w+)\\}\\}/g, (_, key) => String(params[key] ?? ''));\n}\n\nexport function installSpecSummary(spec: SkillInstallSpecApi): string {\n const parts = [spec.kind];\n if (spec.label?.trim()) parts.push(spec.label.trim());\n if (spec.package?.trim()) parts.push(spec.package.trim());\n if (spec.formula?.trim()) parts.push(spec.formula.trim());\n if (spec.module?.trim()) parts.push(spec.module.trim());\n if (spec.url?.trim()) parts.push(spec.url.trim());\n return parts.join(' · ');\n}\n\nexport function normalizeCatalogEntry(r: SkillCatalogEntry): SkillCatalogEntry {\n return {\n ...r,\n enabled: r.enabled ?? true,\n disableModelInvocation: r.disableModelInvocation ?? false,\n };\n}\n","import { type ReactNode } from 'react';\n\nimport { MarkdownView } from '@/components/markdown/markdown-view';\nimport { cn } from '@/lib/cn';\nimport type { SkillMarkdownPreviewPayload } from '@/features/skills/skill.types';\nimport { installSpecSummary } from '@/features/skills/skills-page.utils';\nimport type { MessageBundle } from '@/i18n/messages';\n\nexport type SkillsCopy = MessageBundle['skills'];\n\nfunction MetaRow({ label, children }: { label: string; children: ReactNode }) {\n if (children === null || children === undefined || children === false) return null;\n return (\n <div className=\"mt-3 border-t border-edge-subtle pt-3 dark:border-edge/60\">\n <div className=\"text-xs font-semibold uppercase tracking-wide text-fg-muted\">{label}</div>\n <div className=\"mt-1.5 min-w-0 text-sm text-fg\">{children}</div>\n </div>\n );\n}\n\nexport function SkillCatalogStructuredPreview({\n preview,\n sk,\n}: {\n preview: SkillMarkdownPreviewPayload;\n sk: SkillsCopy;\n}) {\n const meta = preview.metadata;\n const gate = preview.toolConditions;\n const hasToolGating =\n !!gate &&\n (gate.requiresTools.length > 0 ||\n gate.requiresToolsets.length > 0 ||\n gate.fallbackForTools.length > 0 ||\n gate.fallbackForToolsets.length > 0);\n const req = meta.requires;\n const hasRequires =\n req &&\n ((req.bins?.length ?? 0) > 0 || (req.env?.length ?? 0) > 0 || (req.anyBins?.length ?? 0) > 0);\n const installs = meta.install?.filter((s) => s && typeof s.kind === 'string') ?? [];\n const envNames = preview.requiredEnvVarNames?.filter((n) => n.trim()) ?? [];\n\n return (\n <div className=\"space-y-6\">\n <section aria-labelledby=\"skill-detail-summary-heading\">\n <h3\n id=\"skill-detail-summary-heading\"\n className=\"mb-2 text-xs font-semibold uppercase tracking-wide text-fg-muted\"\n >\n {sk.detailSummaryHeading}\n </h3>\n <div className=\"rounded-xl border border-edge bg-surface-base px-4 py-3 dark:bg-surface-hover/25\">\n {meta.emoji?.trim() ? (\n <p className=\"text-2xl leading-none\" aria-hidden>\n {meta.emoji.trim()}\n </p>\n ) : null}\n <p className={cn('text-sm leading-relaxed text-fg', meta.emoji?.trim() ? 'mt-2' : '')}>\n {preview.description}\n </p>\n {preview.disableModelInvocation ? (\n <p className=\"mt-3 rounded-lg border border-amber-200/80 bg-amber-50/90 px-3 py-2 text-xs leading-snug text-amber-950 dark:border-amber-900/50 dark:bg-amber-950/40 dark:text-amber-100\">\n {sk.detailNotInjectedNote}\n </p>\n ) : null}\n <MetaRow label={sk.detailHomepageLabel}>\n {meta.homepage?.trim() ? (\n <a\n href={meta.homepage.trim()}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"break-all text-accent underline-offset-2 hover:underline\"\n >\n {meta.homepage.trim()}\n </a>\n ) : null}\n </MetaRow>\n <MetaRow label={sk.detailPlatformsLabel}>\n {meta.os && meta.os.length > 0 ? (\n <span className=\"font-mono text-xs text-fg-muted\">{meta.os.join(', ')}</span>\n ) : null}\n </MetaRow>\n <MetaRow label={sk.detailRequiresLabel}>\n {hasRequires && req ? (\n <ul className=\"list-inside list-disc space-y-1 text-sm text-fg-muted\">\n {req.bins && req.bins.length > 0 ? (\n <li>\n <span className=\"text-fg\">{sk.detailRequiresBins}: </span>\n {req.bins.join(', ')}\n </li>\n ) : null}\n {req.env && req.env.length > 0 ? (\n <li>\n <span className=\"text-fg\">{sk.detailRequiresEnv}: </span>\n <span className=\"font-mono text-xs\">{req.env.join(', ')}</span>\n </li>\n ) : null}\n {req.anyBins && req.anyBins.length > 0 ? (\n <li>\n <span className=\"text-fg\">{sk.detailRequiresAnyBins}: </span>\n {req.anyBins.join(', ')}\n </li>\n ) : null}\n </ul>\n ) : null}\n </MetaRow>\n <MetaRow label={sk.detailInstallLabel}>\n {installs.length > 0 ? (\n <ul className=\"list-inside list-decimal space-y-1.5 text-sm text-fg-muted\">\n {installs.map((spec, i) => (\n <li key={spec.id || `${spec.kind}-${i}`} className=\"[overflow-wrap:anywhere]\">\n <span className=\"text-fg\">{installSpecSummary(spec)}</span>\n </li>\n ))}\n </ul>\n ) : null}\n </MetaRow>\n <MetaRow label={sk.detailToolGatingLabel}>\n {hasToolGating && gate ? (\n <ul className=\"mt-1 space-y-2 text-sm text-fg-muted\">\n {gate.requiresTools.length > 0 ? (\n <li>\n <span className=\"font-medium text-fg\">{sk.detailToolsRequiresList}: </span>\n {gate.requiresTools.join(', ')}\n </li>\n ) : null}\n {gate.requiresToolsets.length > 0 ? (\n <li>\n <span className=\"font-medium text-fg\">{sk.detailToolsetsRequiresList}: </span>\n {gate.requiresToolsets.join(', ')}\n </li>\n ) : null}\n {gate.fallbackForTools.length > 0 ? (\n <li>\n <span className=\"font-medium text-fg\">{sk.detailToolsFallbackList}: </span>\n {gate.fallbackForTools.join(', ')}\n </li>\n ) : null}\n {gate.fallbackForToolsets.length > 0 ? (\n <li>\n <span className=\"font-medium text-fg\">{sk.detailToolsetsFallbackList}: </span>\n {gate.fallbackForToolsets.join(', ')}\n </li>\n ) : null}\n </ul>\n ) : null}\n </MetaRow>\n <MetaRow label={sk.detailEnvVarsLabel}>\n {envNames.length > 0 ? (\n <span className=\"font-mono text-xs text-fg-muted\">{envNames.join(', ')}</span>\n ) : null}\n </MetaRow>\n </div>\n </section>\n <section aria-labelledby=\"skill-detail-instructions-heading\">\n <h3\n id=\"skill-detail-instructions-heading\"\n className=\"mb-2 text-xs font-semibold uppercase tracking-wide text-fg-muted\"\n >\n {sk.detailInstructionsHeading}\n </h3>\n {preview.bodyMarkdown.trim() ? (\n <div className=\"markdown-content min-w-0 break-words\">\n <MarkdownView content={preview.bodyMarkdown} />\n </div>\n ) : (\n <p className=\"text-sm italic text-fg-muted\">{sk.detailNoInstructionsBody}</p>\n )}\n </section>\n </div>\n );\n}\n","import { Plus, RefreshCw, Search } from 'lucide-react';\nimport { memo } from 'react';\n\nimport { Button } from '@/components/ui/button';\nimport { cn } from '@/lib/cn';\nimport type { MainTab } from '@/features/skills/skills-page.constants';\nimport type { SkillsCopy } from '@/features/skills/skill-catalog-structured-preview';\n\nexport const SkillsPageHeaderEnd = memo(function SkillsPageHeaderEnd({\n loading,\n onReloadClick,\n searchQuery,\n setSearchQuery,\n mainTab,\n sk,\n setPendingFile,\n setInstallOpen,\n}: {\n loading: boolean;\n onReloadClick: () => void;\n searchQuery: string;\n setSearchQuery: (v: string) => void;\n mainTab: MainTab;\n sk: SkillsCopy;\n setPendingFile: (f: File | null) => void;\n setInstallOpen: (v: boolean) => void;\n}) {\n return (\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center justify-end gap-2\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"h-9 w-9 shrink-0 p-0\"\n disabled={loading}\n title={sk.reloadRuntime}\n aria-label={sk.reloadDiskAria}\n onClick={() => void onReloadClick()}\n >\n <RefreshCw className={cn('size-4', loading && 'animate-spin')} strokeWidth={1.75} />\n </Button>\n <label className=\"relative flex min-h-9 min-w-0 max-w-sm cursor-text items-center rounded-pill border border-edge bg-surface-base py-1.5 pl-9 pr-3 shadow-surface dark:bg-surface-hover/40 sm:max-w-md\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-fg-disabled\"\n strokeWidth={1.75}\n aria-hidden\n />\n <input\n type=\"text\"\n role=\"searchbox\"\n enterKeyHint=\"search\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n placeholder={mainTab === 'marketplace' ? sk.marketplaceSearchPackages : sk.searchPlaceholder}\n autoComplete=\"off\"\n spellCheck={false}\n className=\"min-w-0 flex-1 appearance-none border-0 bg-transparent py-0.5 text-sm leading-normal text-fg caret-current placeholder:text-fg-disabled focus:border-0 focus:shadow-none focus:outline-none focus:ring-0 focus-visible:outline-none\"\n />\n </label>\n <Button\n type=\"button\"\n variant=\"primary\"\n className=\"shrink-0 gap-2\"\n onClick={() => {\n setPendingFile(null);\n setInstallOpen(true);\n }}\n >\n <Plus className=\"size-4\" strokeWidth={1.75} aria-hidden />\n {sk.installCta}\n </Button>\n </div>\n );\n});\n","import { cn } from '@/lib/cn';\n\nexport function SkillEnableSwitch({\n checked,\n onChange,\n}: {\n checked: boolean;\n onChange: (next: boolean) => void;\n}) {\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n className={cn(\n 'relative h-6 w-10 shrink-0 overflow-hidden rounded-full border border-edge p-0.5',\n 'transition-[border-color,background-color] duration-200 ease-out',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-surface-base',\n 'active:scale-[0.97] motion-reduce:transition-none motion-reduce:active:scale-100',\n checked ? 'bg-accent' : 'bg-surface-hover',\n )}\n onClick={() => onChange(!checked)}\n >\n <span\n className={cn(\n 'pointer-events-none absolute left-0.5 top-1/2 block size-4 -translate-y-1/2 rounded-full bg-surface-panel shadow-surface ring-1 ring-edge/40 dark:ring-edge/55',\n 'transition-transform duration-200 ease-out motion-reduce:transition-none',\n checked ? 'translate-x-5' : 'translate-x-0',\n )}\n aria-hidden\n />\n </button>\n );\n}\n\nexport function SkillListRowSkeleton() {\n const skel =\n 'animate-pulse motion-reduce:animate-none rounded-md bg-surface-hover dark:bg-surface-active/50';\n return (\n <div className=\"flex items-center gap-4 px-4 py-3.5\" aria-hidden>\n <div className={cn('size-11 shrink-0 rounded-xl', skel)} />\n <div className=\"min-w-0 flex-1 space-y-2\">\n <div className={cn('h-4 max-w-[10rem]', skel)} />\n <div className={cn('h-3 w-full max-w-xl rounded', skel)} />\n </div>\n <div className={cn('h-6 w-10 shrink-0 rounded-full', skel)} />\n </div>\n );\n}\n\n/** Taller row — matches marketplace cards (meta pills + install button) to avoid layout jump after fetch. */\nexport function MarketplaceSkillListRowSkeleton() {\n const skel =\n 'animate-pulse motion-reduce:animate-none rounded-md bg-surface-hover dark:bg-surface-active/50';\n return (\n <div className=\"flex items-center gap-4 px-4 py-3.5\" aria-hidden>\n <div className={cn('size-11 shrink-0 rounded-xl', skel)} />\n <div className=\"min-w-0 flex-1 space-y-2 pr-2\">\n <div className={cn('h-4 max-w-[12rem]', skel)} />\n <div className={cn('h-3 w-full max-w-xl rounded', skel)} />\n <div className=\"flex flex-wrap gap-1.5 pt-0.5\">\n <div className={cn('h-5 w-[5.5rem] rounded-md', skel)} />\n <div className={cn('h-5 w-16 rounded-md', skel)} />\n <div className={cn('h-5 w-14 rounded-md', skel)} />\n </div>\n </div>\n <div className={cn('h-9 min-w-[6.5rem] shrink-0 rounded-lg', skel)} />\n </div>\n );\n}\n","export type MainTab = 'builtin' | 'user' | 'marketplace';\nexport type SourceFilter = 'all' | 'global' | 'workspace' | 'extra';\n\nexport const MAIN_TAB_SET = new Set<MainTab>(['builtin', 'user', 'marketplace']);\nexport const SOURCE_FILTER_SET = new Set<SourceFilter>(['all', 'global', 'workspace', 'extra']);\n\n/** Hash query: which skills marketplace to browse (`store` | `skillhub`). */\nexport const MARKETPLACE_PROVIDER_PARAM = 'mprov';\n\nexport const SKILL_LIST_SKELETON_COUNT = 6;\n\n/** Category display order for consistent pill ordering on the built-in tab. */\nexport const BUILTIN_SKILL_CATEGORY_ORDER = [\n 'business',\n 'creative',\n 'documents',\n 'engineering',\n 'tools',\n] as const;\n","import * as Dialog from '@radix-ui/react-dialog';\nimport * as DropdownMenu from '@radix-ui/react-dropdown-menu';\nimport {\n ChevronDown,\n ChevronLeft,\n ChevronRight,\n ExternalLink,\n FileArchive,\n Funnel,\n Info,\n MoreVertical,\n Star,\n Trash2,\n X,\n} from 'lucide-react';\nimport { useLayoutEffect, useMemo } from 'react';\n\nimport { MarkdownView } from '@/components/markdown/markdown-view';\nimport { Button } from '@/components/ui/button';\nimport { cn } from '@/lib/cn';\nimport { interaction } from '@/lib/interaction';\nimport { SkillCardIcon } from '@/features/skills/skill-card-icon';\nimport { SkillCatalogStructuredPreview } from '@/features/skills/skill-catalog-structured-preview';\nimport { SkillsPageHeaderEnd } from '@/features/skills/skills-page-header-end';\nimport {\n MarketplaceSkillListRowSkeleton,\n SkillEnableSwitch,\n SkillListRowSkeleton,\n} from '@/features/skills/skills-page-primitives';\nimport { SKILL_LIST_SKELETON_COUNT } from '@/features/skills/skills-page.constants';\nimport { interpolate, skillHubPublicSkillPageUrl } from '@/features/skills/skills-page.utils';\nimport type { SkillsPageVm } from '@/features/skills/use-skills-page';\nimport { usePageHeaderStore } from '@/stores/page-header-store';\n\nexport function SkillsPageView({ vm }: { vm: SkillsPageVm }) {\n const {\n sk,\n hasToken,\n catalog,\n loading,\n error,\n uploading,\n searchQuery,\n setSearchQuery,\n actionFeedback,\n mainTab,\n setMainTab,\n setSourceFilter,\n builtinCategoryFilter,\n setBuiltinCategoryFilter,\n installOpen,\n setInstallOpen,\n pendingFile,\n setPendingFile,\n dropActive,\n setDropActive,\n confirmOpen,\n setConfirmOpen,\n confirmId,\n setConfirmId,\n togglingSkillName,\n enabledOverride,\n detailOpen,\n setDetailOpen,\n detailSource,\n setDetailSource,\n detailTitle,\n setDetailTitle,\n detailMarkdown,\n setDetailMarkdown,\n detailCatalogPreview,\n setDetailCatalogPreview,\n detailMarketplacePreview,\n setDetailMarketplacePreview,\n detailLoading,\n detailError,\n setDetailError,\n marketSort,\n setMarketSort,\n marketPage,\n setMarketPage,\n mpLoading,\n mpError,\n mpPayload,\n installingMarketName,\n marketCategoryId,\n setMarketCategoryId,\n mpCategories,\n mpCategoriesError,\n mpCategoriesLoading,\n marketBrowseProvider,\n setMarketBrowseProvider,\n builtinTabStats,\n userTabStats,\n detailEnabled,\n filteredCatalog,\n builtinCategories,\n categoryFilteredCatalog,\n filterLabel,\n inSettingsShell,\n categoryLabel,\n onReloadClick,\n openSkillDetail,\n openMarketplaceDetail,\n onSkillToggle,\n onInstallSubmit,\n onFileInputChange,\n onModalDragOver,\n onModalDragLeave,\n onModalDrop,\n sourceLabel,\n runDelete,\n onMarketInstall,\n isSkillInstalledByName,\n usingSkillInChatName,\n onUseSkillInChat,\n } = vm;\n\n const setPageHeader = usePageHeaderStore((s) => s.setPageHeader);\n const clearPageHeader = usePageHeaderStore((s) => s.clearPageHeader);\n\n const skillsHeaderEnd = useMemo(\n () => (\n <SkillsPageHeaderEnd\n loading={loading}\n onReloadClick={onReloadClick}\n searchQuery={searchQuery}\n setSearchQuery={setSearchQuery}\n mainTab={mainTab}\n sk={sk}\n setPendingFile={setPendingFile}\n setInstallOpen={setInstallOpen}\n />\n ),\n [\n loading,\n onReloadClick,\n searchQuery,\n setSearchQuery,\n mainTab,\n sk,\n setPendingFile,\n setInstallOpen,\n ],\n );\n\n useLayoutEffect(() => {\n if (!hasToken || inSettingsShell) {\n clearPageHeader();\n return () => clearPageHeader();\n }\n setPageHeader({\n startExtra: null,\n main: null,\n end: skillsHeaderEnd,\n });\n return () => clearPageHeader();\n }, [clearPageHeader, hasToken, inSettingsShell, setPageHeader, skillsHeaderEnd]);\n\n if (!hasToken) {\n return (\n <div className=\"mx-auto w-full max-w-app-main px-4 py-16 text-center text-sm text-fg-muted sm:px-8\">\n {sk.needToken}\n </div>\n );\n }\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col overflow-y-auto bg-surface-panel\">\n <div className=\"mx-auto flex w-full max-w-app-main flex-col gap-6 px-4 py-6 sm:px-8\">\n {actionFeedback ? (\n <div\n role=\"status\"\n aria-live=\"polite\"\n className={cn(\n 'rounded-xl border px-3 py-2 text-sm',\n actionFeedback.kind === 'success'\n ? 'border-emerald-200 bg-emerald-50 text-emerald-800 dark:border-emerald-900/40 dark:bg-emerald-950/40 dark:text-emerald-200'\n : 'border-red-200 bg-red-50 text-red-800 dark:border-red-900/50 dark:bg-red-950/40 dark:text-red-200',\n )}\n >\n {actionFeedback.message}\n </div>\n ) : error ? (\n <div\n className=\"rounded-xl border border-edge bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-edge dark:bg-red-950/40 dark:text-red-300\"\n role=\"alert\"\n >\n {error}\n </div>\n ) : null}\n\n <header className=\"flex flex-col gap-4\">\n <div className=\"min-w-0\">\n <h1 className=\"text-xl font-semibold tracking-tight text-fg\">{sk.title}</h1>\n <p className=\"mt-1 max-w-2xl text-sm text-fg-muted\">{sk.tagline}</p>\n </div>\n </header>\n\n {inSettingsShell ? (\n <div className=\"flex flex-col gap-3 border-b border-edge-subtle pb-4 dark:border-edge-subtle sm:flex-row sm:flex-wrap sm:items-center sm:justify-end\">\n {skillsHeaderEnd}\n </div>\n ) : null}\n\n <section className=\"flex flex-col gap-4\">\n <div className=\"flex flex-col gap-3 border-b border-edge-subtle pb-3 sm:flex-row sm:items-center sm:justify-between dark:border-edge-subtle\">\n <div\n className=\"flex flex-wrap gap-x-1 gap-y-1\"\n role=\"tablist\"\n aria-label={sk.skillsNavAria}\n >\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mainTab === 'marketplace'}\n className={cn(\n 'relative max-w-full rounded-md px-3 py-2 text-left text-sm font-medium transition-colors sm:text-center',\n mainTab === 'marketplace' ? 'text-fg' : 'text-fg-muted hover:text-fg',\n mainTab === 'marketplace' &&\n 'after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent',\n )}\n onClick={() => setMainTab('marketplace')}\n >\n {sk.tabMarketplace}\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mainTab === 'builtin'}\n className={cn(\n 'relative rounded-md px-3 py-2 text-sm font-medium transition-colors',\n mainTab === 'builtin' ? 'text-fg' : 'text-fg-muted hover:text-fg',\n mainTab === 'builtin' &&\n 'after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent',\n )}\n onClick={() => setMainTab('builtin')}\n >\n {sk.tabBuiltin}\n <span className=\"ml-1 tabular-nums text-fg-muted\">\n ({builtinTabStats.enabled}/{builtinTabStats.total})\n </span>\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mainTab === 'user'}\n className={cn(\n 'relative rounded-md px-3 py-2 text-sm font-medium transition-colors',\n mainTab === 'user' ? 'text-fg' : 'text-fg-muted hover:text-fg',\n mainTab === 'user' &&\n 'after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent',\n )}\n onClick={() => setMainTab('user')}\n >\n {sk.tabUser}\n <span className=\"ml-1 tabular-nums text-fg-muted\">\n ({userTabStats.enabled}/{userTabStats.total})\n </span>\n </button>\n </div>\n <div\n className={cn(\n 'flex min-h-9 min-w-0 items-center gap-2',\n mainTab === 'user'\n ? 'flex-nowrap overflow-x-auto pb-0.5 sm:justify-end'\n : 'flex-wrap sm:justify-end',\n )}\n >\n {mainTab === 'user' ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n 'inline-flex h-9 min-h-9 min-w-[9rem] shrink-0 items-center gap-1.5 rounded-lg border border-edge bg-surface-panel px-2.5 text-xs font-medium text-fg shadow-surface',\n interaction.transition,\n interaction.focusRingPanel,\n )}\n >\n <Funnel className=\"size-3.5 text-fg-muted\" strokeWidth={1.75} aria-hidden />\n <span>{filterLabel}</span>\n <ChevronDown className=\"size-3.5 text-fg-subtle\" strokeWidth={1.75} aria-hidden />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n className=\"z-50 min-w-[10rem] rounded-xl border border-edge bg-surface-panel p-1 shadow-popover dark:border-edge\"\n sideOffset={6}\n align=\"end\"\n >\n {(['all', 'global', 'workspace', 'extra'] as const).map((key) => (\n <DropdownMenu.Item\n key={key}\n className={cn(\n 'cursor-pointer rounded-lg px-3 py-2 text-sm text-fg outline-none',\n 'hover:bg-surface-hover data-[highlighted]:bg-surface-hover',\n )}\n onSelect={() => setSourceFilter(key)}\n >\n {key === 'all'\n ? sk.filterAll\n : key === 'global'\n ? sk.filterGlobal\n : key === 'workspace'\n ? sk.filterWorkspace\n : sk.filterExtra}\n </DropdownMenu.Item>\n ))}\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n ) : null}\n {mainTab === 'marketplace' ? (\n <>\n <div\n className=\"inline-flex h-9 shrink-0 rounded-lg border border-edge bg-surface-panel p-0.5 shadow-surface\"\n role=\"group\"\n aria-label={sk.marketplaceBrowseSwitchAria}\n >\n {(['skillhub', 'store'] as const).map((id) => {\n const selected = marketBrowseProvider === id;\n return (\n <button\n key={id}\n type=\"button\"\n className={cn(\n 'rounded-md px-2.5 py-1.5 text-xs font-medium transition-colors',\n interaction.focusRingPanel,\n selected\n ? 'bg-fg text-surface-panel dark:bg-fg dark:text-surface-base'\n : 'text-fg-muted hover:text-fg',\n )}\n aria-pressed={selected}\n onClick={() => setMarketBrowseProvider(id)}\n >\n {id === 'skillhub' ? sk.marketplaceBrowseSkillhub : sk.marketplaceBrowseStore}\n </button>\n );\n })}\n </div>\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n 'inline-flex h-9 min-h-9 min-w-[9rem] shrink-0 items-center gap-1.5 rounded-lg border border-edge bg-surface-panel px-2.5 text-xs font-medium text-fg shadow-surface',\n interaction.transition,\n interaction.focusRingPanel,\n )}\n >\n <Funnel className=\"size-3.5 text-fg-muted\" strokeWidth={1.75} aria-hidden />\n <span>\n {marketSort === 'newest' ? sk.marketplaceSortNewest : sk.marketplaceSortDownloads}\n </span>\n <ChevronDown className=\"size-3.5 text-fg-subtle\" strokeWidth={1.75} aria-hidden />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n className=\"z-50 min-w-[10rem] rounded-xl border border-edge bg-surface-panel p-1 shadow-popover dark:border-edge\"\n sideOffset={6}\n align=\"end\"\n >\n <DropdownMenu.Item\n className={cn(\n 'cursor-pointer rounded-lg px-3 py-2 text-sm text-fg outline-none',\n 'hover:bg-surface-hover data-[highlighted]:bg-surface-hover',\n )}\n onSelect={() => setMarketSort('downloads')}\n >\n {sk.marketplaceSortDownloads}\n </DropdownMenu.Item>\n <DropdownMenu.Item\n className={cn(\n 'cursor-pointer rounded-lg px-3 py-2 text-sm text-fg outline-none',\n 'hover:bg-surface-hover data-[highlighted]:bg-surface-hover',\n )}\n onSelect={() => setMarketSort('newest')}\n >\n {sk.marketplaceSortNewest}\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n </>\n ) : null}\n {mainTab === 'builtin' ? (\n <div className=\"h-9 min-w-[9rem] shrink-0\" aria-hidden />\n ) : null}\n </div>\n </div>\n\n {mainTab === 'marketplace' ? (\n <>\n <div\n className={cn(\n '-mx-1 flex min-h-[2.75rem] items-center gap-2 overflow-x-auto px-1 pb-1 pt-0.5 [scrollbar-width:thin]',\n !mpCategoriesLoading && mpCategories.length === 0 && 'min-h-0 pb-0 pt-0',\n )}\n role={mpCategories.length > 0 || mpCategoriesLoading ? 'tablist' : undefined}\n aria-label={\n mpCategories.length > 0 || mpCategoriesLoading ? sk.marketplaceCategoriesAria : undefined\n }\n >\n {mpCategories.length > 0 ? (\n <>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={marketCategoryId === ''}\n className={cn(\n 'shrink-0 rounded-full border px-3 py-1.5 text-xs font-medium transition-colors',\n interaction.focusRingPanel,\n marketCategoryId === ''\n ? 'border-fg bg-fg text-surface-panel dark:border-fg dark:bg-fg dark:text-surface-base'\n : 'border-edge bg-surface-panel text-fg-muted hover:border-edge-strong hover:text-fg dark:border-edge dark:bg-surface-hover/40',\n )}\n onClick={() => setMarketCategoryId('')}\n >\n {sk.marketplaceCategoryAll}\n </button>\n {mpCategories.map((c) => {\n const selected = marketCategoryId === c.id;\n return (\n <button\n key={c.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={selected}\n className={cn(\n 'max-w-[14rem] shrink-0 truncate rounded-full border px-3 py-1.5 text-xs font-medium transition-colors',\n interaction.focusRingPanel,\n selected\n ? 'border-fg bg-fg text-surface-panel dark:border-fg dark:bg-fg dark:text-surface-base'\n : 'border-edge bg-surface-panel text-fg-muted hover:border-edge-strong hover:text-fg dark:border-edge dark:bg-surface-hover/40',\n )}\n title={c.label}\n onClick={() => setMarketCategoryId(c.id)}\n >\n {c.label}\n </button>\n );\n })}\n </>\n ) : mpCategoriesLoading ? (\n <div className=\"flex gap-2 px-1\" aria-hidden>\n {Array.from({ length: 5 }, (_, i) => (\n <div\n key={i}\n className=\"h-8 w-[4.5rem] shrink-0 animate-pulse rounded-full bg-surface-hover motion-reduce:animate-none dark:bg-surface-active/50\"\n />\n ))}\n </div>\n ) : null}\n </div>\n {mpCategoriesError ? (\n <p className=\"text-xs text-red-600 dark:text-red-400\" role=\"alert\">\n {mpCategoriesError}\n </p>\n ) : null}\n {mpLoading ? (\n <div\n className=\"overflow-hidden rounded-2xl border border-edge-subtle bg-surface-base dark:border-edge-subtle\"\n aria-busy=\"true\"\n aria-label={sk.loading}\n >\n {Array.from({ length: SKILL_LIST_SKELETON_COUNT }, (_, i) => (\n <MarketplaceSkillListRowSkeleton key={i} />\n ))}\n </div>\n ) : mpError ? (\n <div\n className=\"rounded-xl border border-edge bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-edge dark:bg-red-950/40 dark:text-red-300\"\n role=\"alert\"\n >\n {mpError}\n </div>\n ) : !mpPayload || mpPayload.items.length === 0 ? (\n <div className=\"rounded-2xl border border-dashed border-edge py-16 text-center text-sm text-fg-muted\">\n {sk.marketplaceEmpty}\n </div>\n ) : (\n <>\n <div className=\"overflow-hidden rounded-2xl border border-edge-subtle bg-surface-base dark:border-edge-subtle\">\n {mpPayload.items.map((row) => {\n const installed = isSkillInstalledByName(row.id);\n const busy = installingMarketName === row.id;\n const skillhubPageUrl =\n marketBrowseProvider === 'skillhub' ? skillHubPublicSkillPageUrl(row.id) : null;\n return (\n <article\n key={row.id}\n className={cn(\n 'group relative flex items-center gap-4 border-b border-edge-subtle px-4 py-3.5 last:border-b-0',\n 'transition-colors hover:bg-surface-hover/50 dark:hover:bg-surface-hover/25',\n )}\n >\n <div\n role=\"button\"\n tabIndex={0}\n className={cn(\n 'flex min-w-0 flex-1 cursor-pointer items-start gap-4 rounded-lg text-left outline-none',\n interaction.focusRingPanel,\n )}\n aria-labelledby={`mp-skill-title-${row.id}`}\n onClick={(e) => {\n if ((e.target as HTMLElement).closest('a[href]')) return;\n void openMarketplaceDetail(row.id, row.name);\n }}\n onKeyDown={(e) => {\n if ((e.target as HTMLElement).closest('a[href]')) return;\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n void openMarketplaceDetail(row.id, row.name);\n }\n }}\n >\n <SkillCardIcon name={row.id} />\n <div className=\"min-w-0 flex-1 pr-2\">\n <h3\n id={`mp-skill-title-${row.id}`}\n className=\"text-[15px] font-semibold leading-snug tracking-tight text-fg\"\n >\n {row.name}\n </h3>\n <p\n className=\"mt-0.5 truncate text-sm leading-relaxed text-fg-muted\"\n title={row.description ? row.description : undefined}\n >\n {row.description || '—'}\n </p>\n <div className=\"mt-1.5 flex flex-wrap gap-1.5 text-[11px] text-fg-subtle\">\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50\">\n {sk.marketplaceAuthor}: {row.author.username}\n </span>\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50\">\n {sk.marketplaceDownloads}: {row.downloads}\n </span>\n {row.stars != null && row.stars > 0 ? (\n <span className=\"inline-flex items-center gap-0.5 rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50\">\n <Star className=\"size-3 shrink-0 text-amber-600 dark:text-amber-400\" strokeWidth={2} aria-hidden />\n {row.stars}\n </span>\n ) : null}\n {row.sourceLabel ? (\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50\">\n {sk.marketplaceSource}: {row.sourceLabel}\n </span>\n ) : null}\n {row.latestVersion ? (\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 font-mono text-[10px] dark:bg-surface-active/50\">\n {sk.marketplaceVersion}: {row.latestVersion}\n </span>\n ) : null}\n {installed ? (\n <span className=\"rounded-md bg-emerald-500/15 px-2 py-0.5 text-emerald-800 dark:text-emerald-200\">\n {sk.marketplaceInstalled}\n </span>\n ) : null}\n {skillhubPageUrl ? (\n <a\n href={skillhubPageUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={cn(\n 'inline-flex items-center gap-0.5 rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50',\n 'hover:bg-surface-hover/80 hover:text-fg-muted dark:hover:bg-surface-active/70',\n interaction.focusRingPanel,\n )}\n aria-label={sk.marketplaceOpenOnSkillhubAria}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n >\n <ExternalLink className=\"size-3 shrink-0\" strokeWidth={2} aria-hidden />\n {sk.marketplaceOpenOnSkillhub}\n </a>\n ) : null}\n </div>\n </div>\n </div>\n <div className=\"flex shrink-0 justify-end sm:pl-2\">\n <Button\n type=\"button\"\n variant={installed ? 'secondary' : 'primary'}\n className=\"min-w-[6.5rem]\"\n disabled={busy || mpLoading}\n onClick={() => void onMarketInstall(row.id)}\n >\n {busy ? sk.uploading : installed ? sk.marketplaceReinstall : sk.marketplaceInstall}\n </Button>\n </div>\n </article>\n );\n })}\n </div>\n <div className=\"flex flex-col items-center justify-between gap-3 sm:flex-row\">\n <p className=\"text-center text-xs text-fg-muted sm:text-left\">\n {interpolate(sk.marketplacePageStatus, {\n page: mpPayload.meta.page,\n totalPages: mpPayload.meta.totalPages,\n total: mpPayload.meta.total,\n })}\n </p>\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"h-9 gap-1 px-2\"\n disabled={mpLoading || marketPage <= 1}\n aria-label={sk.marketplacePagePrev}\n onClick={() => setMarketPage((p) => Math.max(1, p - 1))}\n >\n <ChevronLeft className=\"size-4\" strokeWidth={1.75} aria-hidden />\n <span className=\"sr-only sm:not-sr-only\">{sk.marketplacePagePrev}</span>\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"h-9 gap-1 px-2\"\n disabled={mpLoading || marketPage >= mpPayload.meta.totalPages}\n aria-label={sk.marketplacePageNext}\n onClick={() =>\n setMarketPage((p) => Math.min(mpPayload.meta.totalPages, p + 1))\n }\n >\n <span className=\"sr-only sm:not-sr-only\">{sk.marketplacePageNext}</span>\n <ChevronRight className=\"size-4\" strokeWidth={1.75} aria-hidden />\n </Button>\n </div>\n </div>\n </>\n )}\n </>\n ) : (\n <>\n {loading ? (\n <div\n className=\"overflow-hidden rounded-2xl border border-edge-subtle bg-surface-base dark:border-edge-subtle\"\n aria-busy=\"true\"\n aria-label={sk.loading}\n >\n {Array.from({ length: SKILL_LIST_SKELETON_COUNT }, (_, i) => (\n <SkillListRowSkeleton key={i} />\n ))}\n </div>\n ) : catalog.length === 0 ? (\n <div className=\"rounded-2xl border border-dashed border-edge py-16 text-center text-sm text-fg-muted\">\n {sk.empty}\n </div>\n ) : filteredCatalog.length === 0 ? (\n <div className=\"rounded-2xl border border-dashed border-edge py-16 text-center text-sm text-fg-muted\">\n {sk.noSearchResults}\n </div>\n ) : (\n <>\n {builtinCategories.length > 1 ? (\n <div\n role=\"tablist\"\n aria-label={sk.marketplaceCategoriesAria}\n className=\"-mx-1 flex gap-2 overflow-x-auto px-1 pb-1 pt-0.5 [scrollbar-width:thin]\"\n >\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={builtinCategoryFilter === ''}\n className={cn(\n 'shrink-0 rounded-full border px-3 py-1.5 text-xs font-medium transition-colors',\n interaction.focusRingPanel,\n builtinCategoryFilter === ''\n ? 'border-fg bg-fg text-surface-panel dark:border-fg dark:bg-fg dark:text-surface-base'\n : 'border-edge bg-surface-panel text-fg-muted hover:border-edge-strong hover:text-fg dark:border-edge dark:bg-surface-hover/40',\n )}\n onClick={() => setBuiltinCategoryFilter('')}\n >\n {sk.marketplaceCategoryAll}\n </button>\n {builtinCategories.map((cat) => {\n const selected = builtinCategoryFilter === cat;\n return (\n <button\n key={cat}\n type=\"button\"\n role=\"tab\"\n aria-selected={selected}\n className={cn(\n 'max-w-[14rem] shrink-0 truncate rounded-full border px-3 py-1.5 text-xs font-medium transition-colors',\n interaction.focusRingPanel,\n selected\n ? 'border-fg bg-fg text-surface-panel dark:border-fg dark:bg-fg dark:text-surface-base'\n : 'border-edge bg-surface-panel text-fg-muted hover:border-edge-strong hover:text-fg dark:border-edge dark:bg-surface-hover/40',\n )}\n title={categoryLabel(cat)}\n onClick={() => setBuiltinCategoryFilter(cat)}\n >\n {categoryLabel(cat)}\n </button>\n );\n })}\n </div>\n ) : null}\n {categoryFilteredCatalog.length === 0 ? (\n <div className=\"rounded-2xl border border-dashed border-edge py-16 text-center text-sm text-fg-muted\">\n {sk.noSearchResults}\n </div>\n ) : (\n <div className=\"overflow-hidden rounded-2xl border border-edge-subtle bg-surface-base dark:border-edge-subtle\">\n {categoryFilteredCatalog.map((row, i, arr) => (\n <article\n key={`${row.directoryId}-${row.path}`}\n className={cn(\n 'group relative flex items-center gap-4 border-b border-edge-subtle px-4 py-3.5',\n i === arr.length - 1 && 'border-b-0',\n 'transition-colors hover:bg-surface-hover/50 dark:hover:bg-surface-hover/25',\n )}\n >\n <button\n type=\"button\"\n className={cn(\n 'flex min-w-0 flex-1 cursor-pointer items-center gap-4 rounded-lg text-left outline-none',\n interaction.focusRingPanel,\n )}\n onClick={() => void openSkillDetail(row)}\n >\n <SkillCardIcon name={row.name} />\n <div className=\"min-w-0 flex-1 pr-2\">\n <h3 className=\"text-[15px] font-semibold leading-snug tracking-tight text-fg\">\n {row.name}\n </h3>\n <p\n className=\"mt-0.5 truncate text-sm leading-relaxed text-fg-muted\"\n title={row.description ? row.description : undefined}\n >\n {row.description || '—'}\n </p>\n {mainTab !== 'builtin' || row.managed ? (\n <div className=\"mt-1.5 flex flex-wrap gap-1.5 text-[11px] text-fg-subtle\">\n {mainTab !== 'builtin' ? (\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50\">\n {sourceLabel(row.source)}\n </span>\n ) : null}\n {row.managed ? (\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50\">\n {sk.col.managed}: {sk.yes}\n </span>\n ) : null}\n {row.hub ? (\n <span\n className=\"max-w-full truncate rounded-md bg-surface-hover/60 px-2 py-0.5 font-mono text-[10px] dark:bg-surface-active/50\"\n title={`${row.hub.source}${row.hub.ref ? `\\nref: ${row.hub.ref}` : ''}\\nupdated: ${row.hub.updatedAt}`}\n >\n {sk.hubRemote} ·{' '}\n {row.hub.kind === 'git' ? sk.hubKindGit : sk.hubKindArchive} ·{' '}\n {row.hub.source.length > 48\n ? `${row.hub.source.slice(0, 48)}…`\n : row.hub.source}\n </span>\n ) : null}\n </div>\n ) : null}\n </div>\n </button>\n <div\n className=\"flex shrink-0 items-center gap-1\"\n onClick={(e) => e.stopPropagation()}\n role=\"presentation\"\n >\n {row.managed ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n 'flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg',\n interaction.focusRingPanel,\n )}\n aria-label={sk.col.actions}\n >\n <MoreVertical className=\"size-4\" strokeWidth={1.75} />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n className=\"z-50 min-w-[8rem] rounded-xl border border-edge bg-surface-panel p-1 shadow-popover dark:border-edge\"\n sideOffset={4}\n align=\"end\"\n >\n <DropdownMenu.Item\n className={cn(\n 'flex cursor-pointer items-center gap-2 rounded-lg px-3 py-2 text-sm text-red-600 outline-none',\n 'hover:bg-red-50 data-[highlighted]:bg-red-50 dark:text-red-400 dark:hover:bg-red-950/40',\n )}\n onSelect={() => {\n setConfirmId(row.directoryId);\n setConfirmOpen(true);\n }}\n >\n <Trash2 className=\"size-4\" strokeWidth={1.75} aria-hidden />\n {sk.delete}\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n ) : null}\n <SkillEnableSwitch\n checked={enabledOverride[row.name] ?? row.enabled}\n onChange={(next) => void onSkillToggle(row.name, next)}\n />\n </div>\n </article>\n ))}\n </div>\n )}\n </>\n )}\n </>\n )}\n </section>\n </div>\n\n <Dialog.Root\n open={detailOpen}\n onOpenChange={(open) => {\n setDetailOpen(open);\n if (!open) {\n setDetailSource('catalog');\n setDetailMarkdown('');\n setDetailCatalogPreview(null);\n setDetailMarketplacePreview(null);\n setDetailError(null);\n setDetailTitle('');\n }\n }}\n >\n <Dialog.Portal>\n <Dialog.Overlay className=\"xopc-dialog-overlay fixed inset-0 z-[60] bg-scrim\" />\n <Dialog.Content\n className={cn(\n 'xopc-dialog-content fixed left-1/2 top-1/2 z-[60] flex h-[min(88vh,44rem)] max-h-[min(92vh,56rem)] w-[min(100%-2rem,min(92vw,56rem))]',\n '-translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-2xl border border-edge bg-surface-panel shadow-float dark:border-edge',\n )}\n >\n <div className=\"group flex min-h-[3.25rem] shrink-0 items-center gap-3 border-b border-edge px-4 py-3\">\n <SkillCardIcon name={detailTitle || '?'} />\n <Dialog.Title className=\"min-w-0 flex-1 truncate text-base font-semibold text-fg\">\n {detailTitle || '—'}\n </Dialog.Title>\n <Dialog.Close asChild>\n <button\n type=\"button\"\n className={cn(\n 'rounded-lg p-1.5 text-fg-muted hover:bg-surface-hover hover:text-fg',\n interaction.focusRingPanel,\n )}\n aria-label={sk.detailCloseAria}\n >\n <X className=\"size-5\" strokeWidth={1.75} aria-hidden />\n </button>\n </Dialog.Close>\n </div>\n <div className=\"flex min-h-[3.25rem] shrink-0 items-start gap-2 border-b border-blue-200/80 bg-blue-50/95 px-4 py-2.5 text-sm text-fg dark:border-blue-900/50 dark:bg-blue-950/45\">\n <Info className=\"mt-0.5 size-4 shrink-0 text-blue-600 dark:text-blue-400\" strokeWidth={1.75} aria-hidden />\n <p className=\"min-w-0 leading-relaxed\">\n {detailSource === 'store' && detailMarketplacePreview\n ? sk.detailModalBanner\n : detailSource === 'store'\n ? sk.detailModalBannerStore\n : sk.detailModalBanner}\n </p>\n </div>\n <div className=\"min-h-0 min-w-0 flex-1 overflow-auto px-4 py-4\">\n {detailLoading ? (\n <div\n className=\"flex h-full min-h-[14rem] flex-col gap-2.5 py-1\"\n aria-busy=\"true\"\n aria-label={sk.loading}\n >\n {Array.from({ length: 10 }, (_, i) => (\n <div\n key={i}\n className={cn(\n 'h-4 animate-pulse rounded-md bg-surface-hover dark:bg-surface-active/50',\n i % 3 === 0 ? 'w-[92%]' : i % 3 === 1 ? 'w-full' : 'w-4/5',\n )}\n />\n ))}\n </div>\n ) : detailError ? (\n <p className=\"text-sm text-red-600 dark:text-red-400\">{detailError}</p>\n ) : detailSource === 'catalog' && detailCatalogPreview ? (\n <SkillCatalogStructuredPreview preview={detailCatalogPreview} sk={sk} />\n ) : detailSource === 'store' && detailMarketplacePreview ? (\n <SkillCatalogStructuredPreview preview={detailMarketplacePreview} sk={sk} />\n ) : (\n <div className=\"markdown-content min-w-0 break-words\">\n <MarkdownView content={detailMarkdown} />\n </div>\n )}\n </div>\n <div className=\"flex shrink-0 justify-end gap-2 border-t border-edge px-4 py-3\">\n {detailSource === 'store' ? (\n <>\n <Button type=\"button\" variant=\"ghost\" onClick={() => setDetailOpen(false)}>\n {sk.cancel}\n </Button>\n <Button\n type=\"button\"\n variant=\"secondary\"\n disabled={\n !detailTitle ||\n detailLoading ||\n usingSkillInChatName === detailTitle ||\n installingMarketName === detailTitle\n }\n onClick={() => void onUseSkillInChat()}\n >\n {usingSkillInChatName === detailTitle ? sk.previewUseInChatBusy : sk.previewUseInChat}\n </Button>\n <Button\n type=\"button\"\n variant={isSkillInstalledByName(detailTitle) ? 'secondary' : 'primary'}\n disabled={!detailTitle || installingMarketName === detailTitle}\n onClick={() => {\n if (!detailTitle) return;\n void onMarketInstall(detailTitle, { useDetailProvider: true });\n }}\n >\n {installingMarketName === detailTitle\n ? sk.uploading\n : isSkillInstalledByName(detailTitle)\n ? sk.marketplaceReinstall\n : sk.marketplaceInstall}\n </Button>\n </>\n ) : (\n <>\n <Button\n type=\"button\"\n variant=\"secondary\"\n disabled={\n !detailTitle ||\n detailLoading ||\n usingSkillInChatName === detailTitle ||\n togglingSkillName === detailTitle\n }\n onClick={() => void onUseSkillInChat()}\n >\n {usingSkillInChatName === detailTitle ? sk.previewUseInChatBusy : sk.previewUseInChat}\n </Button>\n <Button\n type=\"button\"\n variant=\"primary\"\n disabled={!detailTitle || togglingSkillName === detailTitle}\n onClick={async () => {\n if (!detailTitle) return;\n const ok = await onSkillToggle(detailTitle, !detailEnabled);\n if (ok) setDetailOpen(false);\n }}\n >\n {detailEnabled ? sk.detailModalDisable : sk.detailModalEnable}\n </Button>\n </>\n )}\n </div>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n\n <Dialog.Root\n open={installOpen}\n onOpenChange={(open) => {\n setInstallOpen(open);\n if (!open) {\n setPendingFile(null);\n setDropActive(false);\n }\n }}\n >\n <Dialog.Portal>\n <Dialog.Overlay className=\"xopc-dialog-overlay fixed inset-0 z-[60] bg-scrim\" />\n <Dialog.Content\n className={cn(\n 'xopc-dialog-content fixed left-1/2 top-1/2 z-[60] max-h-[min(100vh-2rem,44rem)] w-[min(100%-2rem,min(92vw,48rem))] -translate-x-1/2 -translate-y-1/2 overflow-y-auto',\n 'rounded-2xl border border-edge bg-surface-panel p-6 shadow-float dark:border-edge',\n )}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <Dialog.Title className=\"text-base font-semibold text-fg\">{sk.installModalTitle}</Dialog.Title>\n <Dialog.Close asChild>\n <button\n type=\"button\"\n className={cn(\n 'rounded-lg p-1.5 text-fg-muted hover:bg-surface-hover hover:text-fg',\n interaction.focusRingPanel,\n )}\n aria-label={sk.installClose}\n >\n <X className=\"size-5\" strokeWidth={1.75} aria-hidden />\n <span className=\"sr-only\">{sk.installClose}</span>\n </button>\n </Dialog.Close>\n </div>\n\n <label\n className={cn(\n 'mt-4 flex min-h-[11rem] cursor-pointer flex-col items-center justify-center gap-3 rounded-xl border-2 border-dashed px-6 py-12 text-center transition-colors',\n dropActive\n ? 'border-accent bg-accent-soft/60 dark:bg-blue-950/40'\n : 'border-edge bg-surface-base dark:bg-surface-hover/30',\n )}\n onDragLeave={onModalDragLeave}\n onDragOver={onModalDragOver}\n onDrop={onModalDrop}\n >\n <input\n type=\"file\"\n accept=\".zip,.md,application/zip,text/markdown\"\n className=\"sr-only\"\n aria-label={sk.installModalDropHint}\n disabled={uploading}\n onChange={onFileInputChange}\n />\n <FileArchive className=\"size-12 text-fg-subtle\" strokeWidth={1.25} aria-hidden />\n <span className=\"text-sm text-fg-muted\">{sk.installModalDropHint}</span>\n {pendingFile ? (\n <span className=\"text-xs font-medium text-fg\">{pendingFile.name}</span>\n ) : null}\n </label>\n\n <div className=\"mt-5 space-y-2\">\n <p className=\"text-sm font-medium text-fg\">{sk.installModalReqTitle}</p>\n <ul className=\"list-inside list-disc space-y-1 text-sm text-fg-muted\">\n <li>{sk.installModalReq1}</li>\n <li>{sk.installModalReq2}</li>\n </ul>\n </div>\n\n <button\n type=\"button\"\n disabled={!pendingFile || uploading}\n className={cn(\n 'mt-6 flex w-full items-center justify-center rounded-xl py-3 text-sm font-semibold',\n 'transition-colors',\n !pendingFile || uploading\n ? 'cursor-not-allowed bg-surface-active text-fg-disabled'\n : 'bg-accent text-white hover:bg-accent-hover',\n interaction.focusRingPanel,\n )}\n onClick={() => void onInstallSubmit()}\n >\n {uploading ? sk.uploading : sk.installAction}\n </button>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n\n <Dialog.Root\n open={confirmOpen}\n onOpenChange={(open) => {\n setConfirmOpen(open);\n if (!open) setConfirmId(null);\n }}\n >\n <Dialog.Portal>\n <Dialog.Overlay className=\"xopc-dialog-overlay fixed inset-0 z-[60] bg-scrim\" />\n <Dialog.Content className=\"xopc-dialog-content fixed left-1/2 top-1/2 z-[60] w-[min(100%-2rem,24rem)] -translate-x-1/2 -translate-y-1/2 rounded-xl border border-edge bg-surface-panel p-4 shadow-popover dark:border-edge\">\n <Dialog.Title className=\"text-base font-semibold text-fg\">{sk.deleteTitle}</Dialog.Title>\n <p className=\"mt-2 text-sm text-fg-muted\">\n {confirmId ? interpolate(sk.deleteMessage, { id: confirmId }) : ''}\n </p>\n <div className=\"mt-4 flex justify-end gap-2\">\n <Button type=\"button\" variant=\"secondary\" onClick={() => setConfirmOpen(false)}>\n {sk.cancel}\n </Button>\n <Button\n type=\"button\"\n variant=\"primary\"\n className=\"bg-red-600 hover:bg-red-700\"\n onClick={() => void runDelete()}\n >\n {sk.deleteConfirm}\n </Button>\n </div>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n </div>\n );\n}\n","export async function fileToZipUpload(file: File): Promise<File> {\n const lower = file.name.toLowerCase();\n if (lower.endsWith('.zip')) return file;\n if (lower.endsWith('skill.md')) {\n const JSZip = (await import('jszip')).default;\n const zip = new JSZip();\n zip.file('SKILL.md', await file.arrayBuffer());\n const blob = await zip.generateAsync({ type: 'blob', compression: 'DEFLATE' });\n const base = file.name.replace(/\\.md$/i, '').replace(/\\s+/g, '-') || 'skill';\n return new File([blob], `${base}.zip`, { type: 'application/zip' });\n }\n throw new Error('invalid');\n}\n","import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type DragEvent,\n} from 'react';\nimport { useLocation, useNavigate, useSearchParams } from 'react-router-dom';\n\nimport {\n deleteSkill,\n getMarketplaceCategories,\n getMarketplacePackageDetail,\n getMarketplaceProvider,\n getMarketplaceSkills,\n getSkillMarkdown,\n getSkills,\n installMarketplaceSkill,\n patchSkillEnabled,\n reloadSkills,\n uploadSkillZip,\n} from '@/features/skills/skill-api';\nimport type {\n MarketplaceCategoryItem,\n MarketplacePackageItem,\n SkillCatalogEntry,\n SkillMarkdownPreviewPayload,\n} from '@/features/skills/skill.types';\nimport { fileToZipUpload } from '@/features/skills/skill-upload-zip';\nimport {\n BUILTIN_SKILL_CATEGORY_ORDER,\n MAIN_TAB_SET,\n MARKETPLACE_PROVIDER_PARAM,\n SOURCE_FILTER_SET,\n type MainTab,\n type SourceFilter,\n} from '@/features/skills/skills-page.constants';\nimport { normalizeCatalogEntry } from '@/features/skills/skills-page.utils';\nimport { messages } from '@/i18n/messages';\nimport { useGatewayStore } from '@/stores/gateway-store';\nimport { useLocaleStore } from '@/stores/locale-store';\n\nexport function useSkillsPage() {\n const language = useLocaleStore((s) => s.language);\n const m = messages(language);\n const sk = m.skills;\n const token = useGatewayStore((st) => st.token);\n const hasToken = Boolean(token);\n const navigate = useNavigate();\n const [searchParams, setSearchParams] = useSearchParams();\n\n const mprovRaw = searchParams.get(MARKETPLACE_PROVIDER_PARAM);\n const urlMarketProvider =\n mprovRaw === 'store' || mprovRaw === 'skillhub' ? mprovRaw : null;\n\n const [catalog, setCatalog] = useState<SkillCatalogEntry[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [uploading, setUploading] = useState(false);\n const initialSearch = searchParams.get('q') ?? '';\n const initialTabRaw = searchParams.get('tab');\n const initialSourceRaw = searchParams.get('source');\n const initialTab: MainTab = MAIN_TAB_SET.has(initialTabRaw as MainTab)\n ? (initialTabRaw as MainTab)\n : 'marketplace';\n const initialSourceFilter: SourceFilter = SOURCE_FILTER_SET.has(initialSourceRaw as SourceFilter)\n ? (initialSourceRaw as SourceFilter)\n : 'all';\n\n const [searchQuery, setSearchQuery] = useState(initialSearch);\n const [actionFeedback, setActionFeedback] = useState<{\n kind: 'success' | 'error';\n message: string;\n } | null>(null);\n\n const [mainTab, setMainTab] = useState<MainTab>(initialTab);\n const [sourceFilter, setSourceFilter] = useState<SourceFilter>(initialSourceFilter);\n const [builtinCategoryFilter, setBuiltinCategoryFilter] = useState('');\n\n const [installOpen, setInstallOpen] = useState(false);\n const [pendingFile, setPendingFile] = useState<File | null>(null);\n const [dropActive, setDropActive] = useState(false);\n\n const [confirmOpen, setConfirmOpen] = useState(false);\n const [confirmId, setConfirmId] = useState<string | null>(null);\n const [togglingSkillName, setTogglingSkillName] = useState<string | null>(null);\n const [enabledOverride, setEnabledOverride] = useState<Record<string, boolean>>({});\n\n const [detailOpen, setDetailOpen] = useState(false);\n const [detailSource, setDetailSource] = useState<'catalog' | 'store'>('catalog');\n const [detailTitle, setDetailTitle] = useState('');\n const [detailMarkdown, setDetailMarkdown] = useState('');\n const [detailCatalogPreview, setDetailCatalogPreview] = useState<SkillMarkdownPreviewPayload | null>(null);\n const [detailMarketplacePreview, setDetailMarketplacePreview] = useState<SkillMarkdownPreviewPayload | null>(\n null,\n );\n const [detailLoading, setDetailLoading] = useState(false);\n const [detailError, setDetailError] = useState<string | null>(null);\n\n const [marketSort, setMarketSort] = useState<'downloads' | 'newest'>('downloads');\n const [marketPage, setMarketPage] = useState(1);\n const [mpLoading, setMpLoading] = useState(false);\n const [mpError, setMpError] = useState<string | null>(null);\n const [mpPayload, setMpPayload] = useState<{\n items: MarketplacePackageItem[];\n meta: { page: number; pageSize: number; total: number; totalPages: number };\n provider?: 'store' | 'skillhub';\n } | null>(null);\n const [installingMarketName, setInstallingMarketName] = useState<string | null>(null);\n const [usingSkillInChatName, setUsingSkillInChatName] = useState<string | null>(null);\n const [marketCategoryId, setMarketCategoryId] = useState('');\n const [mpCategories, setMpCategories] = useState<MarketplaceCategoryItem[]>([]);\n const [mpCategoriesError, setMpCategoriesError] = useState<string | null>(null);\n const [mpCategoriesLoading, setMpCategoriesLoading] = useState(false);\n const [marketBrowseProvider, setMarketBrowseProvider] = useState<'store' | 'skillhub' | null>(null);\n const marketplaceDetailProviderRef = useRef<'store' | 'skillhub' | null>(null);\n const prevMarketBrowseProviderRef = useRef<'store' | 'skillhub' | null>(null);\n\n const load = useCallback(\n async (opts?: { silent?: boolean }): Promise<{ ok: true } | { ok: false; message: string }> => {\n const silent = opts?.silent === true;\n if (!silent) {\n setLoading(true);\n }\n setError(null);\n try {\n const data = await getSkills(language !== 'en' ? language : undefined);\n setCatalog(data.catalog.map(normalizeCatalogEntry));\n return { ok: true };\n } catch (e) {\n const message = e instanceof Error ? e.message : sk.loadFailed;\n setError(message);\n return { ok: false, message };\n } finally {\n if (!silent) {\n setLoading(false);\n }\n }\n },\n [language, sk.loadFailed],\n );\n\n useEffect(() => {\n if (!hasToken) return;\n void load();\n }, [hasToken, load]);\n\n useEffect(() => {\n if (!hasToken) {\n setMarketBrowseProvider(null);\n marketplaceDetailProviderRef.current = null;\n return;\n }\n if (urlMarketProvider) {\n setMarketBrowseProvider(urlMarketProvider);\n }\n }, [hasToken, urlMarketProvider]);\n\n useEffect(() => {\n if (!hasToken || urlMarketProvider != null) return;\n let cancelled = false;\n void getMarketplaceProvider()\n .then((info) => {\n if (!cancelled) {\n setMarketBrowseProvider((prev) => (prev != null ? prev : info.provider));\n }\n })\n .catch(() => {\n if (!cancelled) {\n setMarketBrowseProvider((prev) => (prev != null ? prev : 'skillhub'));\n }\n });\n return () => {\n cancelled = true;\n };\n }, [hasToken, urlMarketProvider]);\n\n useEffect(() => {\n const nextQ = searchParams.get('q') ?? '';\n const nextTabRaw = searchParams.get('tab');\n const nextSourceRaw = searchParams.get('source');\n const nextTab: MainTab = MAIN_TAB_SET.has(nextTabRaw as MainTab)\n ? (nextTabRaw as MainTab)\n : 'marketplace';\n const nextSource: SourceFilter = SOURCE_FILTER_SET.has(nextSourceRaw as SourceFilter)\n ? (nextSourceRaw as SourceFilter)\n : 'all';\n setSearchQuery((prev) => (prev === nextQ ? prev : nextQ));\n setMainTab((prev) => (prev === nextTab ? prev : nextTab));\n setSourceFilter((prev) => (prev === nextSource ? prev : nextSource));\n const nextMcat = searchParams.get('mcat') ?? '';\n if (nextTab === 'marketplace') {\n setMarketCategoryId((prev) => (prev === nextMcat ? prev : nextMcat));\n } else {\n setMarketCategoryId('');\n }\n }, [searchParams]);\n\n useEffect(() => {\n if (mainTab !== 'marketplace') return;\n setMarketPage(1);\n }, [searchQuery, marketSort, mainTab, marketCategoryId, marketBrowseProvider]);\n\n useEffect(() => {\n if (mainTab !== 'marketplace' || !marketBrowseProvider) {\n prevMarketBrowseProviderRef.current = marketBrowseProvider;\n return;\n }\n const prev = prevMarketBrowseProviderRef.current;\n prevMarketBrowseProviderRef.current = marketBrowseProvider;\n if (prev != null && prev !== marketBrowseProvider) {\n setMarketCategoryId('');\n }\n }, [mainTab, marketBrowseProvider]);\n\n /** Before paint: avoid one frame of empty/stale list then skeleton (useEffect runs too late). */\n useLayoutEffect(() => {\n if (!hasToken || mainTab !== 'marketplace') return;\n setMpLoading(true);\n }, [hasToken, mainTab, marketCategoryId, marketPage, marketSort, searchQuery, marketBrowseProvider]);\n\n useLayoutEffect(() => {\n if (!hasToken || mainTab !== 'marketplace') return;\n setMpCategoriesLoading(true);\n }, [hasToken, mainTab, marketBrowseProvider]);\n\n useEffect(() => {\n if (mainTab === 'marketplace') return;\n setMpCategories([]);\n setMpCategoriesError(null);\n setMpCategoriesLoading(false);\n }, [mainTab]);\n\n useEffect(() => {\n if (!hasToken || mainTab !== 'marketplace' || !marketBrowseProvider) return;\n let cancelled = false;\n setMpError(null);\n void getMarketplaceSkills({\n q: searchQuery.trim() || undefined,\n page: marketPage,\n pageSize: 20,\n sort: marketSort,\n category: marketCategoryId.trim() || undefined,\n provider: marketBrowseProvider,\n })\n .then((payload) => {\n if (!cancelled) setMpPayload(payload);\n })\n .catch((e) => {\n if (!cancelled) {\n setMpError(e instanceof Error ? e.message : sk.marketplaceLoadFailed);\n setMpPayload(null);\n }\n })\n .finally(() => {\n if (!cancelled) setMpLoading(false);\n });\n return () => {\n cancelled = true;\n };\n }, [\n hasToken,\n mainTab,\n marketCategoryId,\n marketPage,\n marketSort,\n searchQuery,\n sk.marketplaceLoadFailed,\n marketBrowseProvider,\n ]);\n\n useEffect(() => {\n if (!hasToken || mainTab !== 'marketplace' || !marketBrowseProvider) return;\n let cancelled = false;\n setMpCategoriesError(null);\n void getMarketplaceCategories({ provider: marketBrowseProvider })\n .then((r) => {\n if (!cancelled) setMpCategories(r.items);\n })\n .catch((e) => {\n if (!cancelled) {\n setMpCategories([]);\n setMpCategoriesError(e instanceof Error ? e.message : sk.marketplaceCategoriesFailed);\n }\n })\n .finally(() => {\n if (!cancelled) setMpCategoriesLoading(false);\n });\n return () => {\n cancelled = true;\n setMpCategoriesLoading(false);\n };\n }, [hasToken, mainTab, sk.marketplaceCategoriesFailed, marketBrowseProvider]);\n\n useEffect(() => {\n if (!marketCategoryId.trim() || mpCategories.length === 0) return;\n if (!mpCategories.some((c) => c.id === marketCategoryId)) {\n setMarketCategoryId('');\n }\n }, [mpCategories, marketCategoryId]);\n\n useEffect(() => {\n setSearchParams(\n (prev) => {\n const params = new URLSearchParams(prev);\n const nextQ = searchQuery.trim();\n if (nextQ) params.set('q', nextQ);\n else params.delete('q');\n if (mainTab !== 'marketplace') params.set('tab', mainTab);\n else params.delete('tab');\n if (sourceFilter !== 'all') params.set('source', sourceFilter);\n else params.delete('source');\n if (mainTab === 'marketplace' && marketCategoryId.trim()) {\n params.set('mcat', marketCategoryId.trim());\n } else {\n params.delete('mcat');\n }\n if (mainTab === 'marketplace' && marketBrowseProvider) {\n params.set(MARKETPLACE_PROVIDER_PARAM, marketBrowseProvider);\n } else {\n params.delete(MARKETPLACE_PROVIDER_PARAM);\n }\n if (params.toString() === prev.toString()) {\n return prev;\n }\n return params;\n },\n { replace: true },\n );\n }, [mainTab, marketCategoryId, marketBrowseProvider, searchQuery, setSearchParams, sourceFilter]);\n\n const showFeedback = useCallback((kind: 'success' | 'error', message: string, durationMs = 5000) => {\n setActionFeedback({ kind, message });\n window.setTimeout(() => setActionFeedback(null), durationMs);\n }, []);\n\n const openSkillDetail = useCallback(\n async (row: SkillCatalogEntry) => {\n setDetailSource('catalog');\n setDetailOpen(true);\n setDetailTitle(row.name);\n setDetailMarkdown('');\n setDetailCatalogPreview(null);\n setDetailMarketplacePreview(null);\n setDetailError(null);\n setDetailLoading(true);\n try {\n const preview = await getSkillMarkdown(row.name, language !== 'en' ? language : undefined);\n setDetailCatalogPreview(preview);\n setDetailTitle(preview.name);\n } catch (e) {\n setDetailCatalogPreview(null);\n setDetailError(e instanceof Error ? e.message : sk.detailLoadFailed);\n } finally {\n setDetailLoading(false);\n }\n },\n [language, sk.detailLoadFailed],\n );\n\n const openMarketplaceDetail = useCallback(\n async (packageId: string, listTitle?: string) => {\n const browse = marketBrowseProvider;\n if (!browse) return;\n marketplaceDetailProviderRef.current = browse;\n setDetailSource('store');\n setDetailOpen(true);\n setDetailTitle(listTitle?.trim() || packageId);\n setDetailMarkdown('');\n setDetailCatalogPreview(null);\n setDetailMarketplacePreview(null);\n setDetailError(null);\n setDetailLoading(true);\n try {\n const pkg = await getMarketplacePackageDetail(packageId, { provider: browse });\n setDetailTitle(pkg.name);\n if (pkg.skillDocPreview) {\n setDetailMarketplacePreview(pkg.skillDocPreview);\n setDetailMarkdown('');\n } else {\n setDetailMarketplacePreview(null);\n const readme = pkg.readme?.trim();\n if (readme) {\n setDetailMarkdown(readme);\n } else if (pkg.description?.trim()) {\n setDetailMarkdown(`## ${pkg.name}\\n\\n${pkg.description.trim()}`);\n } else {\n setDetailMarkdown(`*${sk.marketplaceNoReadme}*`);\n }\n }\n } catch (e) {\n setDetailMarketplacePreview(null);\n setDetailError(e instanceof Error ? e.message : sk.detailLoadFailed);\n } finally {\n setDetailLoading(false);\n }\n },\n [marketBrowseProvider, sk.detailLoadFailed, sk.marketplaceNoReadme],\n );\n\n const onSkillToggle = useCallback(\n async (name: string, next: boolean): Promise<boolean> => {\n setTogglingSkillName(name);\n setEnabledOverride((prev) => ({ ...prev, [name]: next }));\n setActionFeedback(null);\n try {\n await patchSkillEnabled(name, next);\n await load({ silent: true });\n return true;\n } catch (e) {\n setEnabledOverride((prev) => {\n const { [name]: _, ...rest } = prev;\n return rest;\n });\n const msg = e instanceof Error ? e.message : sk.skillToggleFailed;\n showFeedback('error', msg);\n return false;\n } finally {\n setTogglingSkillName(null);\n setEnabledOverride((prev) => {\n const { [name]: _, ...rest } = prev;\n return rest;\n });\n }\n },\n [load, showFeedback, sk.skillToggleFailed],\n );\n\n const onReloadClick = useCallback(async () => {\n setActionFeedback(null);\n setLoading(true);\n setError(null);\n try {\n await reloadSkills();\n } catch (e) {\n const msg = e instanceof Error ? e.message : sk.reloadFailed;\n setError(msg);\n setLoading(false);\n return;\n }\n await load();\n }, [load, sk.reloadFailed]);\n\n const builtinTabStats = useMemo(() => {\n const rows = catalog.filter((r) => r.source === 'builtin');\n return {\n total: rows.length,\n enabled: rows.filter((r) => enabledOverride[r.name] ?? r.enabled).length,\n };\n }, [catalog, enabledOverride]);\n\n const userTabStats = useMemo(() => {\n const rows = catalog.filter((r) => r.source !== 'builtin');\n return {\n total: rows.length,\n enabled: rows.filter((r) => enabledOverride[r.name] ?? r.enabled).length,\n };\n }, [catalog, enabledOverride]);\n\n const detailFromCatalog = useMemo(\n () => (detailTitle ? catalog.find((r) => r.name === detailTitle) : undefined),\n [catalog, detailTitle],\n );\n const detailEnabled =\n detailFromCatalog == null\n ? true\n : (enabledOverride[detailTitle] ?? detailFromCatalog.enabled);\n\n const filteredCatalog = useMemo(() => {\n const q = searchQuery.trim().toLowerCase();\n let rows = catalog;\n\n if (mainTab === 'builtin') {\n rows = rows.filter((r) => r.source === 'builtin');\n } else {\n rows = rows.filter((r) => r.source !== 'builtin');\n if (sourceFilter !== 'all') {\n rows = rows.filter((r) => r.source === sourceFilter);\n }\n }\n\n if (!q) return rows;\n return rows.filter((row) => {\n const blob = [\n row.name,\n row.description,\n row.directoryId,\n row.path,\n row.source,\n row.hub?.source,\n row.hub?.ref,\n ]\n .filter(Boolean)\n .join(' ')\n .toLowerCase();\n return blob.includes(q);\n });\n }, [catalog, searchQuery, mainTab, sourceFilter]);\n\n const builtinCategories = useMemo(() => {\n const seen = new Set<string>();\n const ordered: string[] = [];\n for (const entry of filteredCatalog) {\n const cat = entry.category;\n if (!cat || seen.has(cat)) continue;\n seen.add(cat);\n ordered.push(cat);\n }\n return ordered.sort((a, b) => {\n const ai = BUILTIN_SKILL_CATEGORY_ORDER.indexOf(a as (typeof BUILTIN_SKILL_CATEGORY_ORDER)[number]);\n const bi = BUILTIN_SKILL_CATEGORY_ORDER.indexOf(b as (typeof BUILTIN_SKILL_CATEGORY_ORDER)[number]);\n if (ai >= 0 && bi >= 0) return ai - bi;\n if (ai >= 0) return -1;\n if (bi >= 0) return 1;\n return a.localeCompare(b);\n });\n }, [filteredCatalog]);\n\n const categoryLabel = useCallback(\n (cat: string): string => {\n const labels = sk.categoryLabel as Record<string, string> | undefined;\n return labels?.[cat] || cat;\n },\n [sk.categoryLabel],\n );\n\n const categoryFilteredCatalog = useMemo(() => {\n if (!builtinCategoryFilter) return filteredCatalog;\n return filteredCatalog.filter((r) => r.category === builtinCategoryFilter);\n }, [filteredCatalog, builtinCategoryFilter]);\n\n const runUpload = async (file: File) => {\n setActionFeedback(null);\n setUploading(true);\n setError(null);\n try {\n let upload: File;\n try {\n upload = await fileToZipUpload(file);\n } catch {\n setError(sk.invalidFile);\n showFeedback('error', sk.invalidFile);\n return;\n }\n await uploadSkillZip(upload, { overwrite: true });\n await load();\n showFeedback('success', sk.installSuccess);\n setInstallOpen(false);\n setPendingFile(null);\n setMainTab('user');\n } catch (err) {\n setError(err instanceof Error ? err.message : sk.uploadFailed);\n showFeedback('error', err instanceof Error ? err.message : sk.uploadFailed);\n } finally {\n setUploading(false);\n }\n };\n\n const onInstallSubmit = () => {\n if (pendingFile) void runUpload(pendingFile);\n };\n\n const onFileInputChange = (e: ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n e.target.value = '';\n if (file) setPendingFile(file);\n };\n\n const onModalDragOver = (e: DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (e.dataTransfer.types.includes('Files')) {\n setDropActive(true);\n e.dataTransfer.dropEffect = 'copy';\n }\n };\n\n const onModalDragLeave = (e: DragEvent) => {\n const root = e.currentTarget as HTMLElement;\n const to = e.relatedTarget as Node | null;\n if (to && root.contains(to)) return;\n setDropActive(false);\n };\n\n const onModalDrop = (e: DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setDropActive(false);\n const file = e.dataTransfer?.files?.[0];\n if (file) setPendingFile(file);\n };\n\n const sourceLabel = (source: SkillCatalogEntry['source']): string => {\n switch (source) {\n case 'builtin':\n return sk.source.builtin;\n case 'workspace':\n return sk.source.workspace;\n case 'global':\n return sk.source.global;\n case 'extra':\n return sk.source.extra;\n default:\n return source;\n }\n };\n\n const runDelete = async () => {\n const id = confirmId;\n setConfirmOpen(false);\n setConfirmId(null);\n if (!id) return;\n setActionFeedback(null);\n try {\n await deleteSkill(id);\n await load();\n } catch (e) {\n setError(e instanceof Error ? e.message : sk.deleteFailed);\n }\n };\n\n const isSkillInstalledByName = useCallback(\n (name: string) => catalog.some((r) => r.name === name),\n [catalog],\n );\n\n const onUseSkillInChat = useCallback(async () => {\n const name = detailTitle.trim();\n if (!name) return;\n setActionFeedback(null);\n const needsMarketInstall = detailSource === 'store' && !isSkillInstalledByName(name);\n if (needsMarketInstall) setUsingSkillInChatName(name);\n try {\n if (needsMarketInstall) {\n const mp = marketplaceDetailProviderRef.current ?? marketBrowseProvider;\n await installMarketplaceSkill({\n name,\n overwrite: false,\n ...(mp ? { provider: mp } : {}),\n });\n await load({ silent: true });\n }\n setDetailOpen(false);\n navigate(`/chat/new?skill=${encodeURIComponent(name)}`);\n } catch (e) {\n showFeedback('error', e instanceof Error ? e.message : sk.uploadFailed);\n } finally {\n setUsingSkillInChatName(null);\n }\n }, [\n detailTitle,\n detailSource,\n isSkillInstalledByName,\n load,\n navigate,\n showFeedback,\n sk.uploadFailed,\n marketBrowseProvider,\n ]);\n\n const onMarketInstall = useCallback(\n async (name: string, opts?: { useDetailProvider?: boolean }) => {\n const installed = isSkillInstalledByName(name);\n if (installed) {\n const ok = window.confirm(sk.marketplaceReinstallConfirm);\n if (!ok) return;\n }\n setActionFeedback(null);\n setInstallingMarketName(name);\n try {\n const p = opts?.useDetailProvider\n ? marketplaceDetailProviderRef.current ?? marketBrowseProvider\n : marketBrowseProvider;\n await installMarketplaceSkill({\n name,\n overwrite: installed,\n ...(p ? { provider: p } : {}),\n });\n await load({ silent: true });\n showFeedback('success', sk.installSuccess);\n setDetailOpen(false);\n setMainTab('user');\n } catch (e) {\n showFeedback('error', e instanceof Error ? e.message : sk.uploadFailed);\n } finally {\n setInstallingMarketName(null);\n }\n },\n [\n isSkillInstalledByName,\n load,\n marketBrowseProvider,\n showFeedback,\n sk.installSuccess,\n sk.marketplaceReinstallConfirm,\n sk.uploadFailed,\n ],\n );\n\n const filterLabel =\n sourceFilter === 'all'\n ? sk.filterAll\n : sourceFilter === 'global'\n ? sk.filterGlobal\n : sourceFilter === 'workspace'\n ? sk.filterWorkspace\n : sk.filterExtra;\n\n const { pathname } = useLocation();\n const inSettingsShell = pathname.startsWith('/settings/');\n\n return {\n sk,\n hasToken,\n catalog,\n loading,\n error,\n uploading,\n searchQuery,\n setSearchQuery,\n actionFeedback,\n mainTab,\n setMainTab,\n sourceFilter,\n setSourceFilter,\n builtinCategoryFilter,\n setBuiltinCategoryFilter,\n installOpen,\n setInstallOpen,\n pendingFile,\n setPendingFile,\n dropActive,\n setDropActive,\n confirmOpen,\n setConfirmOpen,\n confirmId,\n setConfirmId,\n togglingSkillName,\n enabledOverride,\n detailOpen,\n setDetailOpen,\n detailSource,\n setDetailSource,\n detailTitle,\n setDetailTitle,\n detailMarkdown,\n setDetailMarkdown,\n detailCatalogPreview,\n setDetailCatalogPreview,\n detailMarketplacePreview,\n setDetailMarketplacePreview,\n detailLoading,\n detailError,\n setDetailError,\n marketSort,\n setMarketSort,\n marketPage,\n setMarketPage,\n mpLoading,\n mpError,\n mpPayload,\n installingMarketName,\n usingSkillInChatName,\n onUseSkillInChat,\n marketCategoryId,\n setMarketCategoryId,\n mpCategories,\n mpCategoriesError,\n mpCategoriesLoading,\n marketBrowseProvider,\n setMarketBrowseProvider,\n builtinTabStats,\n userTabStats,\n detailEnabled,\n filteredCatalog,\n builtinCategories,\n categoryFilteredCatalog,\n filterLabel,\n inSettingsShell,\n categoryLabel,\n onReloadClick,\n openSkillDetail,\n openMarketplaceDetail,\n onSkillToggle,\n onInstallSubmit,\n onFileInputChange,\n onModalDragOver,\n onModalDragLeave,\n onModalDrop,\n sourceLabel,\n runDelete,\n onMarketInstall,\n isSkillInstalledByName,\n };\n}\n\nexport type SkillsPageVm = ReturnType<typeof useSkillsPage>;\n","import { SkillsPageView } from '@/features/skills/skills-page-view';\nimport { useSkillsPage } from '@/features/skills/use-skills-page';\n\nexport function SkillsPage() {\n const vm = useSkillsPage();\n return <SkillsPageView vm={vm} />;\n}\n"],"file":"skills-page-Dgd20nUt.js"}
|