fix: import github skill directories

This commit is contained in:
Junyan Qin
2026-05-18 17:26:35 +08:00
parent bf8b51569f
commit 651904a5d4
6 changed files with 144 additions and 100 deletions

View File

@@ -24,8 +24,14 @@ import {
Loader2,
CheckCircle2,
XCircle,
CircleHelp,
} from 'lucide-react';
import { Input } from '@/components/ui/input';
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from '@/components/ui/tooltip';
import React, { useState, useCallback, useEffect, useRef } from 'react';
import { httpClient, systemInfo } from '@/app/infra/http/HttpClient';
import { toast } from 'sonner';
@@ -855,9 +861,23 @@ function AddExtensionContent() {
<div className="min-h-0 flex-1 space-y-3 overflow-y-auto p-4">
{githubInstallStatus === GithubInstallStatus.WAIT_INPUT && (
<div className="space-y-2">
<p className="text-xs text-muted-foreground">
{t('addExtension.githubUrlHelp')}
</p>
<div className="flex items-center gap-1.5 text-xs text-muted-foreground">
<span>{t('addExtension.githubUrlHelp')}</span>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
className="inline-flex size-4 items-center justify-center rounded-full transition-colors hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50"
aria-label={t('addExtension.githubUrlTooltip')}
>
<CircleHelp className="size-3.5" />
</button>
</TooltipTrigger>
<TooltipContent side="top" className="max-w-[280px]">
{t('addExtension.githubUrlTooltip')}
</TooltipContent>
</Tooltip>
</div>
<Input
placeholder={t('addExtension.githubUrlPlaceholder')}
value={githubURL}
@@ -866,9 +886,6 @@ function AddExtensionContent() {
if (e.key === 'Enter') handleGithubAddressSubmit();
}}
/>
<p className="text-[11px] leading-relaxed text-muted-foreground">
{t('addExtension.skillMdUrlHelp')}
</p>
<Button
className="w-full"
onClick={handleGithubAddressSubmit}

View File

@@ -214,7 +214,7 @@ const FileTree = forwardRef<FileTreeHandle, FileTreeProps>(function FileTree(
return (
<div className="space-y-2">
<div className="max-h-48 space-y-1 overflow-y-auto">
<div className="max-h-[min(46vh,32rem)] space-y-1 overflow-y-auto overscroll-contain pr-1">
{rootEntries.length === 0 && !loading && (
<div className="text-sm text-muted-foreground py-2">
{t('skills.noFiles')}
@@ -330,24 +330,9 @@ export default function SkillForm({
}
};
const handleContentChange = (content: string) => {
const handleInstructionDraftChange = (content: string) => {
setFileContent(content);
// If editing SKILL.md, sync to skill.instructions
if (selectedFile === 'SKILL.md' || selectedFile?.endsWith('/SKILL.md')) {
setSkill((prev) => ({ ...prev, instructions: content }));
}
};
const handleSaveFile = async () => {
if (!initSkillName || !selectedFile) return;
try {
await httpClient.writeSkillFile(initSkillName, selectedFile, fileContent);
toast.success(t('skills.saveFileSuccess'));
} catch (error) {
console.error('Failed to save file:', error);
toast.error(t('skills.saveFileError') + String(error));
}
setSkill((prev) => ({ ...prev, instructions: content }));
};
const handleSubmit = async (e: FormEvent) => {
@@ -462,23 +447,12 @@ export default function SkillForm({
<Textarea
id="instructions"
value={fileContent}
onChange={(e) => handleContentChange(e.target.value)}
onChange={(e) => handleInstructionDraftChange(e.target.value)}
readOnly={Boolean(initSkillName)}
placeholder={t('skills.instructionsPlaceholder')}
rows={16}
className="min-h-[360px] resize-y font-mono text-sm lg:min-h-[calc(100vh-220px)]"
className="min-h-[360px] resize-y font-mono text-sm read-only:cursor-default read-only:bg-muted/30 lg:min-h-[calc(100vh-220px)]"
/>
{selectedFile &&
selectedFile !== 'SKILL.md' &&
!selectedFile.endsWith('/SKILL.md') && (
<Button
type="button"
variant="outline"
size="sm"
onClick={handleSaveFile}
>
{t('skills.saveFile')}
</Button>
)}
</div>
);