Class: ZipSkillInstaller

Inherits:
Object
  • Object
show all
Defined in:
lib/clacky/default_skills/skill-add/scripts/install_from_zip.rb

Overview

Install a skill from a remote zip archive URL. Usage: ruby install_from_zip.rb <zip_url>

The zip archive is expected to contain a skill directory at its root, e.g.:

my-skill/
  SKILL.md
  scripts/

Or the archive may contain multiple skill directories (each with a SKILL.md).

Constant Summary collapse

ZIP_URL_PATTERN =
%r{^https?://.+\.zip(\?.*)?$}i

Instance Method Summary collapse

Constructor Details

#initialize(zip_source, skill_name: nil, target_dir: nil) ⇒ ZipSkillInstaller

Returns a new instance of ZipSkillInstaller.



22
23
24
25
26
27
28
29
30
31
32
# File 'lib/clacky/default_skills/skill-add/scripts/install_from_zip.rb', line 22

def initialize(zip_source, skill_name: nil, target_dir: nil)
  @zip_source = zip_source
  @local_path = local_zip_path?(zip_source)
  # skill_name can be provided explicitly (e.g. slug from the store API).
  # If not provided, we try to infer it from the filename in the URL/path, e.g.
  # "ui-ux-pro-max-1.0.0.zip" → "ui-ux-pro-max".
  @skill_name = skill_name || infer_skill_name(zip_source)
  @target_dir = target_dir || File.join(Dir.home, '.clacky', 'skills')
  @installed_skills = []
  @errors = []
end

Instance Method Details

#installObject

Main installation entry point.



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/clacky/default_skills/skill-add/scripts/install_from_zip.rb', line 35

def install
  if @local_path
    # Install directly from a local zip file — no download needed.
    # Expand tilde in path (e.g. ~/Downloads/skill.zip)
    expanded = File.expand_path(@zip_source)
    raise ArgumentError, "File not found: #{@zip_source}" unless File.exist?(expanded)
    raise ArgumentError, "Not a zip file: #{@zip_source}" unless expanded.end_with?('.zip')

    Dir.mktmpdir('clacky-zip-') do |tmpdir|
      extract_zip(expanded, tmpdir)
      extracted_dir = File.join(tmpdir, 'extracted')
      discover_and_install_skills(extracted_dir)
    end
  else
    # Install from a remote URL.
    unless valid_zip_url?
      raise ArgumentError, "Invalid zip source: #{@zip_source}\nProvide an http(s) URL ending with .zip, or an absolute path to a local zip file."
    end

    Dir.mktmpdir('clacky-zip-') do |tmpdir|
      zip_path = download_zip(tmpdir)
      extract_zip(zip_path, tmpdir)
      extracted_dir = File.join(tmpdir, 'extracted')
      discover_and_install_skills(extracted_dir)
    end
  end

  report_results
rescue ArgumentError => e
  puts "#{e.message}"
  exit 1
rescue StandardError => e
  puts "❌ Installation failed: #{e.message}"
  exit 1
end