--- install from GitHub ---------------------------------------------------
(kind entities.Kind, repoArg, skillName string, all, force bool, out io.Writer, resolveApps func() ([]string, error), stdin io.Reader)
| 1592 | // --- install from GitHub --------------------------------------------------- |
| 1593 | |
| 1594 | func installFromGitHub(kind entities.Kind, repoArg, skillName string, all, force bool, out io.Writer, resolveApps func() ([]string, error), stdin io.Reader) error { |
| 1595 | // Parse owner/repo, optional @branch. |
| 1596 | ghOwner, ghRepo, ghBranch := parseRepoArg(repoArg) |
| 1597 | if ghOwner == "" || ghRepo == "" { |
| 1598 | return fmt.Errorf("invalid repository %q: expected owner/repo or owner/repo@branch", repoArg) |
| 1599 | } |
| 1600 | |
| 1601 | fmt.Fprintf(out, "Fetching from %s/%s@%s ...\n", ghOwner, ghRepo, ghBranch) |
| 1602 | |
| 1603 | client := fetching.New() |
| 1604 | dest := filepath.Join(os.TempDir(), fmt.Sprintf("cam-install-%s-%s", ghOwner, ghRepo)) |
| 1605 | _ = os.RemoveAll(dest) |
| 1606 | root, err := client.DownloadGitHubZip(ghOwner, ghRepo, ghBranch, dest) |
| 1607 | if err != nil { |
| 1608 | return fmt.Errorf("failed to download repository: %w", err) |
| 1609 | } |
| 1610 | |
| 1611 | items := discoverEntities(kind, root) |
| 1612 | if len(items) == 0 { |
| 1613 | fmt.Fprintf(out, "No %ss found in %s/%s\n", kind, ghOwner, ghRepo) |
| 1614 | return nil |
| 1615 | } |
| 1616 | |
| 1617 | // Let user pick skills first. |
| 1618 | source := fmt.Sprintf("%s/%s", ghOwner, ghRepo) |
| 1619 | items, err = selectItems(items, skillName, all, kind, source, stdin) |
| 1620 | if err != nil { |
| 1621 | return err |
| 1622 | } |
| 1623 | |
| 1624 | // Now resolve the target agent(s) (prompt if needed). |
| 1625 | apps, err := resolveApps() |
| 1626 | if err != nil { |
| 1627 | return err |
| 1628 | } |
| 1629 | |
| 1630 | for _, app := range apps { |
| 1631 | fmt.Fprintf(out, "\n%s:\n", app) |
| 1632 | installed := 0 |
| 1633 | for _, item := range items { |
| 1634 | if !force && isAlreadyInstalled(item.name, kind, app) { |
| 1635 | if isInteractive(stdin) && confirmOverwrite(item.name, kind, app) { |
| 1636 | // user said yes — fall through to install |
| 1637 | } else { |
| 1638 | fmt.Fprintf(out, " Skipping %s (already installed)\n", item.name) |
| 1639 | continue |
| 1640 | } |
| 1641 | } |
| 1642 | e := entities.Entity{ |
| 1643 | Name: item.name, |
| 1644 | Content: item.content, |
| 1645 | Path: item.path, |
| 1646 | Repo: &entities.RepoRef{Owner: ghOwner, Name: ghRepo, Branch: ghBranch}, |
| 1647 | } |
| 1648 | destPath, err := entities.InstallToApp(e, kind, app) |
| 1649 | if err != nil { |
| 1650 | fmt.Fprintf(out, " Error installing %s: %v\n", item.name, err) |
| 1651 | continue |
no test coverage detected