(ctx context.Context, skillRootPath string, resources []string)
| 474 | } |
| 475 | |
| 476 | func loadSkillFilesForSandbox(ctx context.Context, skillRootPath string, resources []string) (map[string]string, error) { |
| 477 | files := make(map[string]string) |
| 478 | |
| 479 | resolvedPath, err := filepath.EvalSymlinks(skillRootPath) |
| 480 | if err != nil { |
| 481 | return nil, fmt.Errorf("failed to resolve skill path: %w", err) |
| 482 | } |
| 483 | |
| 484 | if len(resources) == 0 { |
| 485 | err := filepath.Walk(resolvedPath, func(path string, info os.FileInfo, err error) error { |
| 486 | if err != nil { |
| 487 | return err |
| 488 | } |
| 489 | if info.IsDir() { |
| 490 | return nil |
| 491 | } |
| 492 | return appendSkillFile(ctx, files, resolvedPath, path, info) |
| 493 | }) |
| 494 | return files, err |
| 495 | } |
| 496 | |
| 497 | for _, entry := range resources { |
| 498 | pattern := strings.TrimSpace(entry) |
| 499 | if pattern == "" { |
| 500 | continue |
| 501 | } |
| 502 | if strings.Contains(pattern, "..") || filepath.IsAbs(pattern) { |
| 503 | logger.Warnf(ctx, "Skip suspicious skill resource pattern: %s", pattern) |
| 504 | continue |
| 505 | } |
| 506 | matches, err := filepath.Glob(filepath.Join(skillRootPath, pattern)) |
| 507 | if err != nil { |
| 508 | logger.Warnf(ctx, "Invalid skill resource pattern %s: %v", pattern, err) |
| 509 | continue |
| 510 | } |
| 511 | for _, match := range matches { |
| 512 | info, statErr := os.Stat(match) |
| 513 | if statErr != nil || info.IsDir() { |
| 514 | continue |
| 515 | } |
| 516 | if err := appendSkillFile(ctx, files, skillRootPath, match, info); err != nil { |
| 517 | logger.Warnf(ctx, "Skip skill resource %s: %v", match, err) |
| 518 | continue |
| 519 | } |
| 520 | } |
| 521 | } |
| 522 | |
| 523 | return files, nil |
| 524 | } |
| 525 | |
| 526 | func appendSkillFile(ctx context.Context, files map[string]string, root string, absPath string, info os.FileInfo) error { |
| 527 | if info.Size() > 10*1024*1024 { |
no test coverage detected