mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-05-18 14:57:37 +08:00
feat(webui): support --force install for suspicious skills
This commit is contained in:
@@ -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)
|
http.Error(w, "clawhub is not installed. please install clawhub first.", http.StatusPreconditionFailed)
|
||||||
return
|
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)
|
cmd.Dir = strings.TrimSpace(s.workspacePath)
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -189,6 +189,7 @@ const resources = {
|
|||||||
skillsImportDoneMessage: 'Skill imported successfully.',
|
skillsImportDoneMessage: 'Skill imported successfully.',
|
||||||
skillsFileSaved: 'Skill file saved successfully.',
|
skillsFileSaved: 'Skill file saved successfully.',
|
||||||
skillsNamePlaceholder: 'skill name',
|
skillsNamePlaceholder: 'skill name',
|
||||||
|
skillsIgnoreSuspicious: 'Ignore suspicious warning (use --force)',
|
||||||
skillsClawhubNotFound: 'clawhub not found',
|
skillsClawhubNotFound: 'clawhub not found',
|
||||||
skillsClawhubStatus: 'clawhub',
|
skillsClawhubStatus: 'clawhub',
|
||||||
skillsAdd: 'Add Skill',
|
skillsAdd: 'Add Skill',
|
||||||
@@ -491,6 +492,7 @@ const resources = {
|
|||||||
skillsImportDoneMessage: '技能导入成功。',
|
skillsImportDoneMessage: '技能导入成功。',
|
||||||
skillsFileSaved: '技能文件保存成功。',
|
skillsFileSaved: '技能文件保存成功。',
|
||||||
skillsNamePlaceholder: '技能名',
|
skillsNamePlaceholder: '技能名',
|
||||||
|
skillsIgnoreSuspicious: '忽略可疑告警(使用 --force)',
|
||||||
skillsClawhubNotFound: '未找到 clawhub',
|
skillsClawhubNotFound: '未找到 clawhub',
|
||||||
skillsClawhubStatus: 'clawhub',
|
skillsClawhubStatus: 'clawhub',
|
||||||
skillsAdd: '添加技能',
|
skillsAdd: '添加技能',
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const Skills: React.FC = () => {
|
|||||||
const ui = useUI();
|
const ui = useUI();
|
||||||
const [installName, setInstallName] = useState('');
|
const [installName, setInstallName] = useState('');
|
||||||
const [installingSkill, setInstallingSkill] = useState(false);
|
const [installingSkill, setInstallingSkill] = useState(false);
|
||||||
|
const [ignoreSuspicious, setIgnoreSuspicious] = useState(false);
|
||||||
const qp = (k: string, v: string) => `${q}${q ? '&' : '?'}${k}=${encodeURIComponent(v)}`;
|
const qp = (k: string, v: string) => `${q}${q ? '&' : '?'}${k}=${encodeURIComponent(v)}`;
|
||||||
|
|
||||||
const [isFileModalOpen, setIsFileModalOpen] = useState(false);
|
const [isFileModalOpen, setIsFileModalOpen] = useState(false);
|
||||||
@@ -76,7 +77,7 @@ const Skills: React.FC = () => {
|
|||||||
const r = await fetch(`/webui/api/skills${q}`, {
|
const r = await fetch(`/webui/api/skills${q}`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ action: 'install', name }),
|
body: JSON.stringify({ action: 'install', name, ignore_suspicious: ignoreSuspicious }),
|
||||||
});
|
});
|
||||||
if (!r.ok) {
|
if (!r.ok) {
|
||||||
ui.hideLoading();
|
ui.hideLoading();
|
||||||
@@ -190,6 +191,15 @@ const Skills: React.FC = () => {
|
|||||||
<div className="flex items-center gap-2">
|
<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" />
|
<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>
|
<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>
|
||||||
<div className="flex items-center gap-3">
|
<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')}>
|
<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')}>
|
||||||
|
|||||||
Reference in New Issue
Block a user