feat(webui): support --force install for suspicious skills

This commit is contained in:
lpf
2026-03-03 14:27:27 +08:00
parent 1946c50fc5
commit 2357a5de9b
3 changed files with 25 additions and 2 deletions

View File

@@ -916,7 +916,18 @@ func (s *RegistryServer) handleWebUISkills(w http.ResponseWriter, r *http.Reques
http.Error(w, "clawhub is not installed. please install clawhub first.", http.StatusPreconditionFailed)
return
}
cmd := exec.CommandContext(r.Context(), clawhubPath, "install", name)
ignoreSuspicious := false
switch v := body["ignore_suspicious"].(type) {
case bool:
ignoreSuspicious = v
case string:
ignoreSuspicious = strings.EqualFold(strings.TrimSpace(v), "true") || strings.TrimSpace(v) == "1"
}
args := []string{"install", name}
if ignoreSuspicious {
args = append(args, "--force")
}
cmd := exec.CommandContext(r.Context(), clawhubPath, args...)
cmd.Dir = strings.TrimSpace(s.workspacePath)
out, err := cmd.CombinedOutput()
if err != nil {

View File

@@ -189,6 +189,7 @@ const resources = {
skillsImportDoneMessage: 'Skill imported successfully.',
skillsFileSaved: 'Skill file saved successfully.',
skillsNamePlaceholder: 'skill name',
skillsIgnoreSuspicious: 'Ignore suspicious warning (use --force)',
skillsClawhubNotFound: 'clawhub not found',
skillsClawhubStatus: 'clawhub',
skillsAdd: 'Add Skill',
@@ -491,6 +492,7 @@ const resources = {
skillsImportDoneMessage: '技能导入成功。',
skillsFileSaved: '技能文件保存成功。',
skillsNamePlaceholder: '技能名',
skillsIgnoreSuspicious: '忽略可疑告警(使用 --force',
skillsClawhubNotFound: '未找到 clawhub',
skillsClawhubStatus: 'clawhub',
skillsAdd: '添加技能',

View File

@@ -11,6 +11,7 @@ const Skills: React.FC = () => {
const ui = useUI();
const [installName, setInstallName] = useState('');
const [installingSkill, setInstallingSkill] = useState(false);
const [ignoreSuspicious, setIgnoreSuspicious] = useState(false);
const qp = (k: string, v: string) => `${q}${q ? '&' : '?'}${k}=${encodeURIComponent(v)}`;
const [isFileModalOpen, setIsFileModalOpen] = useState(false);
@@ -76,7 +77,7 @@ const Skills: React.FC = () => {
const r = await fetch(`/webui/api/skills${q}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'install', name }),
body: JSON.stringify({ action: 'install', name, ignore_suspicious: ignoreSuspicious }),
});
if (!r.ok) {
ui.hideLoading();
@@ -190,6 +191,15 @@ const Skills: React.FC = () => {
<div className="flex items-center gap-2">
<input disabled={installingSkill} value={installName} onChange={(e) => setInstallName(e.target.value)} placeholder={t('skillsNamePlaceholder')} className="px-3 py-2 bg-zinc-950 border border-zinc-800 rounded-lg text-sm disabled:opacity-60" />
<button disabled={installingSkill} onClick={installSkill} className="px-3 py-2 bg-emerald-600 hover:bg-emerald-500 disabled:opacity-60 disabled:cursor-not-allowed text-white rounded-lg text-sm font-medium">{installingSkill ? t('loading') : t('install')}</button>
<label className="flex items-center gap-2 text-xs text-zinc-400">
<input
type="checkbox"
checked={ignoreSuspicious}
disabled={installingSkill}
onChange={(e) => setIgnoreSuspicious(e.target.checked)}
/>
{t('skillsIgnoreSuspicious')}
</label>
</div>
<div className="flex items-center gap-3">
<div className={`text-xs px-2 py-1 rounded-md border ${clawhubInstalled ? 'text-emerald-300 border-emerald-700/50 bg-emerald-900/20' : 'text-amber-300 border-amber-700/50 bg-amber-900/20'}`} title={clawhubPath || t('skillsClawhubNotFound')}>