(ctx context.Context, job *model.SkillScanJob)
| 704 | } |
| 705 | |
| 706 | func (s *SkillLibraryService) executeScanJob(ctx context.Context, job *model.SkillScanJob) error { |
| 707 | if job == nil || job.ID <= 0 { |
| 708 | return nil |
| 709 | } |
| 710 | |
| 711 | if job.SkillLibraryID <= 0 { |
| 712 | return s.executeImportJob(ctx, job) |
| 713 | } |
| 714 | |
| 715 | logger.Infof(ctx, "【技能运行】开始扫描技能: job_id=%d skill_id=%d", job.ID, job.SkillLibraryID) |
| 716 | |
| 717 | skillInfo, err := model.GetSkillLibraryByID(job.SkillLibraryID) |
| 718 | if err != nil { |
| 719 | if errors.Is(err, gorm.ErrRecordNotFound) { |
| 720 | return s.finalizeScanFailure(job.ID, "", "技能不存在,扫描终止", "", false) |
| 721 | } |
| 722 | return s.finalizeScanFailure(job.ID, "", fmt.Sprintf("加载技能失败: %v", err), "", true) |
| 723 | } |
| 724 | |
| 725 | runtime, err := s.resolveWorkAIScanRuntime(ctx, skillInfo.Eid) |
| 726 | if err != nil { |
| 727 | if errors.Is(err, ErrSkillScanNoWorkAIModelConfigured) { |
| 728 | return s.finalizeScanFailure(job.ID, "", "未配置工作AI模型,无法进行技能扫描", "", false) |
| 729 | } |
| 730 | return s.finalizeScanFailure(job.ID, "", fmt.Sprintf("读取工作AI模型失败: %v", err), "", true) |
| 731 | } |
| 732 | |
| 733 | zipContent, err := s.storage.Load(skillInfo.OriginZipKey) |
| 734 | if err != nil { |
| 735 | return s.finalizeScanFailure(job.ID, runtime.Model, fmt.Sprintf("读取技能包失败: %v", err), "", true) |
| 736 | } |
| 737 | |
| 738 | archiveSkillPath := "" |
| 739 | if skillInfo.SourceType == model.SkillSourceTypeGithub { |
| 740 | archiveSkillPath = parseGithubSourceSkillPath(skillInfo.SourceRef) |
| 741 | } |
| 742 | skillMD, entries, err := s.unzipSkillPackage(zipContent, skillInfo.InstallPath, archiveSkillPath) |
| 743 | if err != nil { |
| 744 | retryable := !errors.Is(err, ErrSkillScanMissingSkillMD) && !errors.Is(err, ErrSkillScanZipPathTraversal) |
| 745 | return s.finalizeScanFailure(job.ID, runtime.Model, scanErrorToMessage(err), "", retryable) |
| 746 | } |
| 747 | |
| 748 | parsedSkill, parseErr := skillsvc.ParseSkillMetadata(skillMD) |
| 749 | var rawDescription string |
| 750 | if parseErr == nil && parsedSkill != nil { |
| 751 | rawDescription = strings.TrimSpace(parsedSkill.Description) |
| 752 | skillInfo.Version = normalizeSkillVersion(parsedSkill.Version) |
| 753 | } |
| 754 | |
| 755 | output, err := s.scanner.Scan(ctx, &SkillScanInput{ |
| 756 | Skill: skillInfo, |
| 757 | ScanModel: runtime.Model, |
| 758 | ScanChannel: runtime.Channel, |
| 759 | LLMInvoker: s.resolveLLMInvoker(), |
| 760 | SkillMD: skillMD, |
| 761 | FileEntries: entries, |
| 762 | SkillName: skillInfo.SkillName, |
| 763 | RawDescription: rawDescription, |
no test coverage detected