schwarm-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. checksums.yaml +7 -0
  2. data/bin/schwarm +14 -0
  3. data/lib/schwarm_cli/client/agent_sessions.rb +16 -0
  4. data/lib/schwarm_cli/client/recurring_tasks.rb +33 -0
  5. data/lib/schwarm_cli/client/repositories.rb +37 -0
  6. data/lib/schwarm_cli/client/repository_agents.rb +37 -0
  7. data/lib/schwarm_cli/client/repository_skills.rb +25 -0
  8. data/lib/schwarm_cli/client/resource.rb +20 -0
  9. data/lib/schwarm_cli/client/secret_files.rb +29 -0
  10. data/lib/schwarm_cli/client/shared_agents.rb +33 -0
  11. data/lib/schwarm_cli/client/skill_files.rb +29 -0
  12. data/lib/schwarm_cli/client/skills.rb +29 -0
  13. data/lib/schwarm_cli/client/task_templates.rb +29 -0
  14. data/lib/schwarm_cli/client/tasks.rb +49 -0
  15. data/lib/schwarm_cli/client/user_messages.rb +11 -0
  16. data/lib/schwarm_cli/client.rb +101 -0
  17. data/lib/schwarm_cli/commands/agents.rb +92 -0
  18. data/lib/schwarm_cli/commands/base.rb +63 -0
  19. data/lib/schwarm_cli/commands/configure.rb +31 -0
  20. data/lib/schwarm_cli/commands/main.rb +64 -0
  21. data/lib/schwarm_cli/commands/recurring.rb +85 -0
  22. data/lib/schwarm_cli/commands/repo_skills.rb +50 -0
  23. data/lib/schwarm_cli/commands/repos.rb +86 -0
  24. data/lib/schwarm_cli/commands/secrets.rb +82 -0
  25. data/lib/schwarm_cli/commands/sessions.rb +30 -0
  26. data/lib/schwarm_cli/commands/shared_agents.rb +81 -0
  27. data/lib/schwarm_cli/commands/skill_files.rb +77 -0
  28. data/lib/schwarm_cli/commands/skills.rb +68 -0
  29. data/lib/schwarm_cli/commands/tasks.rb +146 -0
  30. data/lib/schwarm_cli/commands/templates.rb +58 -0
  31. data/lib/schwarm_cli/config.rb +46 -0
  32. data/lib/schwarm_cli/formatters/json.rb +13 -0
  33. data/lib/schwarm_cli/formatters/table.rb +39 -0
  34. data/lib/schwarm_cli/version.rb +5 -0
  35. data/lib/schwarm_cli.rb +12 -0
  36. metadata +148 -0
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "gum"
4
+
5
+ module SchwarmCli
6
+ module Commands
7
+ class Configure < Base
8
+ desc "setup", "Set up Schwarm CLI configuration"
9
+ default_task :setup
10
+
11
+ def setup
12
+ url = Gum.input(header: "Schwarm Server URL", value: "https://schwarm.getdexter.net")
13
+ abort "Cancelled." unless url
14
+
15
+ api_key = Gum.input(header: "API Key", password: true, placeholder: "sk-schwarm-...")
16
+ abort "Cancelled." unless api_key
17
+
18
+ config = SchwarmCli::Config.new(url:, api_key:)
19
+ client = SchwarmCli::Client.new(url:, api_key:)
20
+ Gum.spin("Testing connection...") { client.repositories.list(per_page: 1) }
21
+
22
+ config.save
23
+ puts "Configuration saved to #{config.config_path}"
24
+ rescue Faraday::UnauthorizedError
25
+ abort "Error: Invalid API key."
26
+ rescue Faraday::Error => e
27
+ abort "Error: Could not connect to server (#{e.message})."
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require_relative "tasks"
5
+ require_relative "repos"
6
+ require_relative "templates"
7
+ require_relative "skills"
8
+ require_relative "skill_files"
9
+ require_relative "agents"
10
+ require_relative "shared_agents"
11
+ require_relative "recurring"
12
+ require_relative "secrets"
13
+ require_relative "sessions"
14
+ require_relative "repo_skills"
15
+ require_relative "configure"
16
+
17
+ module SchwarmCli
18
+ module Commands
19
+ class Main < Thor
20
+ desc "tasks SUBCOMMAND", "Manage tasks"
21
+ subcommand "tasks", Tasks
22
+
23
+ desc "repos SUBCOMMAND", "Manage repositories"
24
+ subcommand "repos", Repos
25
+
26
+ desc "templates SUBCOMMAND", "Manage task templates"
27
+ subcommand "templates", Templates
28
+
29
+ desc "skills SUBCOMMAND", "Manage skills"
30
+ subcommand "skills", SkillsCmd
31
+
32
+ desc "skill-files SUBCOMMAND", "Manage skill files"
33
+ subcommand "skill-files", SkillFilesCmd
34
+
35
+ desc "agents SUBCOMMAND", "Manage repository agents"
36
+ subcommand "agents", Agents
37
+
38
+ desc "shared-agents SUBCOMMAND", "Manage shared agents"
39
+ subcommand "shared-agents", SharedAgentsCmd
40
+
41
+ desc "recurring SUBCOMMAND", "Manage recurring tasks"
42
+ subcommand "recurring", Recurring
43
+
44
+ desc "secrets SUBCOMMAND", "Manage secret files"
45
+ subcommand "secrets", Secrets
46
+
47
+ desc "sessions SUBCOMMAND", "View agent sessions"
48
+ subcommand "sessions", Sessions
49
+
50
+ desc "repo-skills SUBCOMMAND", "Manage repository-skill associations"
51
+ subcommand "repo-skills", RepoSkills
52
+
53
+ desc "configure", "Set up Schwarm CLI configuration"
54
+ subcommand "configure", Configure
55
+
56
+ desc "version", "Show CLI version"
57
+ def version
58
+ puts "schwarm-cli #{SchwarmCli::VERSION}"
59
+ end
60
+
61
+ map %w[-v --version] => :version
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SchwarmCli
4
+ module Commands
5
+ class Recurring < Base
6
+ desc "list", "List recurring tasks"
7
+ option :repo, type: :string, desc: "Filter by repository ID"
8
+ option :query, type: :string, desc: "Search by name"
9
+ def list
10
+ handle_errors do
11
+ data = client.recurring.list(repository_id: options[:repo], query: options[:query])
12
+ output_list(data, columns: [%w[ID id], %w[NAME name], %w[REPO github_repository_id],
13
+ %w[ENABLED enabled], %w[SCHEDULE schedule]])
14
+ end
15
+ end
16
+
17
+ desc "show ID", "Show recurring task details"
18
+ def show(id)
19
+ handle_errors do
20
+ data = client.recurring.find(id)
21
+ output_record(data, fields: {
22
+ "ID" => "id", "Name" => "name", "Repository" => "github_repository_id",
23
+ "Enabled" => "enabled", "Schedule" => "schedule", "Prompt" => "prompt",
24
+ "Created" => "created_at", "Updated" => "updated_at"
25
+ })
26
+ end
27
+ end
28
+
29
+ desc "create", "Create a recurring task"
30
+ option :name, type: :string, required: true, desc: "Task name"
31
+ option :repo, type: :string, required: true, desc: "Repository ID"
32
+ option :prompt, type: :string, required: true, desc: "Task prompt"
33
+ option :schedule, type: :string, required: true, desc: "Cron schedule"
34
+ def create
35
+ handle_errors do
36
+ attrs = {
37
+ name: options[:name], github_repository_id: options[:repo],
38
+ prompt: options[:prompt], schedule: options[:schedule]
39
+ }
40
+
41
+ data = client.recurring.create(**attrs)
42
+ output_record(data, fields: { "ID" => "id", "Name" => "name", "Schedule" => "schedule" })
43
+ end
44
+ end
45
+
46
+ desc "update ID", "Update a recurring task"
47
+ option :name, type: :string, desc: "Task name"
48
+ option :prompt, type: :string, desc: "Task prompt"
49
+ option :schedule, type: :string, desc: "Cron schedule"
50
+ def update(id)
51
+ handle_errors do
52
+ data = client.recurring.update(id, **update_attrs)
53
+ output_record(data, fields: { "ID" => "id", "Name" => "name", "Schedule" => "schedule" })
54
+ end
55
+ end
56
+
57
+ desc "delete ID", "Delete a recurring task"
58
+ def delete(id)
59
+ handle_errors do
60
+ client.recurring.destroy(id)
61
+ puts "Recurring task #{id} deleted."
62
+ end
63
+ end
64
+
65
+ desc "toggle ID", "Toggle recurring task enabled/disabled"
66
+ def toggle(id)
67
+ handle_errors do
68
+ data = client.recurring.toggle(id)
69
+ status = data.dig("data", "enabled") ? "enabled" : "disabled"
70
+ puts "Recurring task #{id} #{status}."
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ def update_attrs
77
+ {}.tap do |attrs|
78
+ attrs[:name] = options[:name] if options[:name]
79
+ attrs[:prompt] = options[:prompt] if options[:prompt]
80
+ attrs[:schedule] = options[:schedule] if options[:schedule]
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SchwarmCli
4
+ module Commands
5
+ class RepoSkills < Base
6
+ desc "list", "List repository-skill associations"
7
+ option :repo, type: :string, desc: "Filter by repository ID"
8
+ option :skill, type: :string, desc: "Filter by skill ID"
9
+ def list
10
+ handle_errors do
11
+ data = client.repo_skills.list(repository_id: options[:repo], skill_id: options[:skill])
12
+ output_list(data, columns: [%w[ID id], %w[REPO github_repository_id],
13
+ %w[SKILL skill_id]])
14
+ end
15
+ end
16
+
17
+ desc "show ID", "Show repository-skill association"
18
+ def show(id)
19
+ handle_errors do
20
+ data = client.repo_skills.find(id)
21
+ output_record(data, fields: {
22
+ "ID" => "id", "Repository" => "github_repository_id",
23
+ "Skill" => "skill_id", "Created" => "created_at"
24
+ })
25
+ end
26
+ end
27
+
28
+ desc "create", "Associate a skill with a repository"
29
+ option :repo, type: :string, required: true, desc: "Repository ID"
30
+ option :skill, type: :string, required: true, desc: "Skill ID"
31
+ def create
32
+ handle_errors do
33
+ data = client.repo_skills.create(
34
+ github_repository_id: options[:repo], skill_id: options[:skill]
35
+ )
36
+ output_record(data, fields: { "ID" => "id", "Repository" => "github_repository_id",
37
+ "Skill" => "skill_id" })
38
+ end
39
+ end
40
+
41
+ desc "delete ID", "Remove a repository-skill association"
42
+ def delete(id)
43
+ handle_errors do
44
+ client.repo_skills.destroy(id)
45
+ puts "Repository-skill association #{id} deleted."
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SchwarmCli
4
+ module Commands
5
+ class Repos < Base
6
+ desc "list", "List repositories"
7
+ option :status, type: :string, desc: "Filter by status"
8
+ option :query, type: :string, desc: "Search by name"
9
+ def list
10
+ handle_errors do
11
+ data = client.repositories.list(status: options[:status], query: options[:query])
12
+ output_list(data, columns: [%w[ID id], %w[NAME name], %w[STATUS status]])
13
+ end
14
+ end
15
+
16
+ desc "show ID", "Show repository details"
17
+ def show(id)
18
+ handle_errors do
19
+ data = client.repositories.find(id)
20
+ output_record(data, fields: {
21
+ "ID" => "id", "Name" => "name", "URL" => "url",
22
+ "Status" => "status", "Base Branch" => "base_branch"
23
+ })
24
+ end
25
+ end
26
+
27
+ desc "create", "Create a repository"
28
+ option :name, type: :string, required: true, desc: "Repository name"
29
+ option :url, type: :string, desc: "Repository URL"
30
+ option :base_branch, type: :string, desc: "Base branch (default: main)"
31
+ def create
32
+ handle_errors do
33
+ data = client.repositories.create(**create_attrs)
34
+ output_record(data, fields: { "ID" => "id", "Name" => "name", "Status" => "status" })
35
+ end
36
+ end
37
+
38
+ desc "update ID", "Update a repository"
39
+ option :name, type: :string, desc: "Repository name"
40
+ option :base_branch, type: :string, desc: "Base branch"
41
+ def update(id)
42
+ handle_errors do
43
+ attrs = {}
44
+ attrs[:name] = options[:name] if options[:name]
45
+ attrs[:base_branch] = options[:base_branch] if options[:base_branch]
46
+
47
+ data = client.repositories.update(id, **attrs)
48
+ output_record(data, fields: { "ID" => "id", "Name" => "name", "Status" => "status" })
49
+ end
50
+ end
51
+
52
+ desc "delete ID", "Delete a repository"
53
+ def delete(id)
54
+ handle_errors do
55
+ client.repositories.destroy(id)
56
+ puts "Repository #{id} deleted."
57
+ end
58
+ end
59
+
60
+ desc "pause ID", "Pause a repository"
61
+ def pause(id)
62
+ handle_errors do
63
+ data = client.repositories.pause(id)
64
+ puts "Repository #{id} paused (#{data.dig('data', 'status')})."
65
+ end
66
+ end
67
+
68
+ desc "resume ID", "Resume a repository"
69
+ def resume(id)
70
+ handle_errors do
71
+ data = client.repositories.resume(id)
72
+ puts "Repository #{id} resumed (#{data.dig('data', 'status')})."
73
+ end
74
+ end
75
+
76
+ private
77
+
78
+ def create_attrs
79
+ { name: options[:name] }.tap do |attrs|
80
+ attrs[:url] = options[:url] if options[:url]
81
+ attrs[:base_branch] = options[:base_branch] if options[:base_branch]
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SchwarmCli
4
+ module Commands
5
+ class Secrets < Base
6
+ desc "list", "List secret files"
7
+ option :repo, type: :string, desc: "Filter by repository ID"
8
+ def list
9
+ handle_errors do
10
+ data = client.secrets.list(repository_id: options[:repo])
11
+ output_list(data, columns: [%w[ID id], %w[NAME name], %w[REPO github_repository_id],
12
+ %w[PATH path]])
13
+ end
14
+ end
15
+
16
+ desc "show ID", "Show secret file details"
17
+ def show(id)
18
+ handle_errors do
19
+ data = client.secrets.find(id)
20
+ output_record(data, fields: {
21
+ "ID" => "id", "Name" => "name", "Repository" => "github_repository_id",
22
+ "Path" => "path", "Created" => "created_at", "Updated" => "updated_at"
23
+ })
24
+ end
25
+ end
26
+
27
+ desc "create", "Create a secret file"
28
+ option :name, type: :string, required: true, desc: "Secret name"
29
+ option :repo, type: :string, required: true, desc: "Repository ID"
30
+ option :path, type: :string, required: true, desc: "File path in workspace"
31
+ option :content, type: :string, desc: "Secret content"
32
+ option :file, type: :string, desc: "Read content from file"
33
+ def create
34
+ handle_errors do
35
+ content = read_content
36
+ attrs = { name: options[:name], github_repository_id: options[:repo], path: options[:path], content: }
37
+
38
+ data = client.secrets.create(**attrs)
39
+ output_record(data, fields: { "ID" => "id", "Name" => "name", "Path" => "path" })
40
+ end
41
+ end
42
+
43
+ desc "update ID", "Update a secret file"
44
+ option :name, type: :string, desc: "Secret name"
45
+ option :path, type: :string, desc: "File path in workspace"
46
+ option :content, type: :string, desc: "Secret content"
47
+ option :file, type: :string, desc: "Read content from file"
48
+ def update(id)
49
+ handle_errors do
50
+ data = client.secrets.update(id, **update_attrs)
51
+ output_record(data, fields: { "ID" => "id", "Name" => "name", "Path" => "path" })
52
+ end
53
+ end
54
+
55
+ desc "delete ID", "Delete a secret file"
56
+ def delete(id)
57
+ handle_errors do
58
+ client.secrets.destroy(id)
59
+ puts "Secret #{id} deleted."
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def update_attrs
66
+ { name: options[:name], path: options[:path] }.compact.tap do |attrs|
67
+ attrs[:content] = read_content if options[:content] || options[:file]
68
+ end
69
+ end
70
+
71
+ def read_content
72
+ if options[:file]
73
+ file_path = File.expand_path(options[:file])
74
+ abort "Error: File not found: #{file_path}" unless File.exist?(file_path)
75
+ File.read(file_path)
76
+ else
77
+ options[:content]
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SchwarmCli
4
+ module Commands
5
+ class Sessions < Base
6
+ desc "list", "List agent sessions"
7
+ option :source, type: :string, desc: "Filter by source"
8
+ option :status, type: :string, desc: "Filter by status"
9
+ def list
10
+ handle_errors do
11
+ data = client.sessions.list(source: options[:source], status: options[:status])
12
+ output_list(data, columns: [%w[ID id], %w[SOURCE source], %w[STATUS status],
13
+ %w[CREATED created_at]])
14
+ end
15
+ end
16
+
17
+ desc "show ID", "Show agent session details"
18
+ def show(id)
19
+ handle_errors do
20
+ data = client.sessions.find(id)
21
+ output_record(data, fields: {
22
+ "ID" => "id", "Source" => "source", "Status" => "status",
23
+ "Prompt" => "prompt", "Result" => "result",
24
+ "Created" => "created_at", "Updated" => "updated_at"
25
+ })
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SchwarmCli
4
+ module Commands
5
+ class SharedAgentsCmd < Base
6
+ desc "list", "List shared agents"
7
+ option :query, type: :string, desc: "Search by name"
8
+ def list
9
+ handle_errors do
10
+ data = client.shared_agents.list(query: options[:query])
11
+ output_list(data, columns: [%w[ID id], %w[NAME name], %w[ENABLED enabled],
12
+ %w[SCHEDULE schedule]])
13
+ end
14
+ end
15
+
16
+ desc "show ID", "Show shared agent details"
17
+ def show(id)
18
+ handle_errors do
19
+ data = client.shared_agents.find(id)
20
+ output_record(data, fields: {
21
+ "ID" => "id", "Name" => "name", "Enabled" => "enabled",
22
+ "Schedule" => "schedule", "Prompt" => "prompt",
23
+ "Created" => "created_at", "Updated" => "updated_at"
24
+ })
25
+ end
26
+ end
27
+
28
+ desc "create", "Create a shared agent"
29
+ option :name, type: :string, required: true, desc: "Agent name"
30
+ option :prompt, type: :string, required: true, desc: "Agent prompt"
31
+ option :schedule, type: :string, desc: "Cron schedule"
32
+ def create
33
+ handle_errors do
34
+ attrs = { name: options[:name], prompt: options[:prompt] }
35
+ attrs[:schedule] = options[:schedule] if options[:schedule]
36
+
37
+ data = client.shared_agents.create(**attrs)
38
+ output_record(data, fields: { "ID" => "id", "Name" => "name", "Enabled" => "enabled" })
39
+ end
40
+ end
41
+
42
+ desc "update ID", "Update a shared agent"
43
+ option :name, type: :string, desc: "Agent name"
44
+ option :prompt, type: :string, desc: "Agent prompt"
45
+ option :schedule, type: :string, desc: "Cron schedule"
46
+ def update(id)
47
+ handle_errors do
48
+ data = client.shared_agents.update(id, **update_attrs)
49
+ output_record(data, fields: { "ID" => "id", "Name" => "name", "Enabled" => "enabled" })
50
+ end
51
+ end
52
+
53
+ desc "delete ID", "Delete a shared agent"
54
+ def delete(id)
55
+ handle_errors do
56
+ client.shared_agents.destroy(id)
57
+ puts "Shared agent #{id} deleted."
58
+ end
59
+ end
60
+
61
+ desc "toggle ID", "Toggle shared agent enabled/disabled"
62
+ def toggle(id)
63
+ handle_errors do
64
+ data = client.shared_agents.toggle(id)
65
+ status = data.dig("data", "enabled") ? "enabled" : "disabled"
66
+ puts "Shared agent #{id} #{status}."
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ def update_attrs
73
+ {}.tap do |attrs|
74
+ attrs[:name] = options[:name] if options[:name]
75
+ attrs[:prompt] = options[:prompt] if options[:prompt]
76
+ attrs[:schedule] = options[:schedule] if options[:schedule]
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SchwarmCli
4
+ module Commands
5
+ class SkillFilesCmd < Base
6
+ class_option :skill, type: :string, required: true, desc: "Skill ID"
7
+
8
+ desc "list", "List skill files"
9
+ def list
10
+ handle_errors do
11
+ data = client.skill_files.list(skill_id: options[:skill])
12
+ output_list(data, columns: [%w[ID id], %w[PATH path], %w[CREATED created_at]])
13
+ end
14
+ end
15
+
16
+ desc "show ID", "Show skill file details"
17
+ def show(id)
18
+ handle_errors do
19
+ data = client.skill_files.find(skill_id: options[:skill], id:)
20
+ output_record(data, fields: {
21
+ "ID" => "id", "Path" => "path", "Content" => "content", "Created" => "created_at"
22
+ })
23
+ end
24
+ end
25
+
26
+ desc "create", "Create a skill file"
27
+ option :path, type: :string, required: true, desc: "File path"
28
+ option :content, type: :string, desc: "File content"
29
+ option :file, type: :string, desc: "Read content from file"
30
+ def create
31
+ handle_errors do
32
+ content = read_content
33
+ data = client.skill_files.create(skill_id: options[:skill], path: options[:path], content:)
34
+ output_record(data, fields: { "ID" => "id", "Path" => "path" })
35
+ end
36
+ end
37
+
38
+ desc "update ID", "Update a skill file"
39
+ option :path, type: :string, desc: "File path"
40
+ option :content, type: :string, desc: "File content"
41
+ option :file, type: :string, desc: "Read content from file"
42
+ def update(id)
43
+ handle_errors do
44
+ data = client.skill_files.update(skill_id: options[:skill], id:, **update_attrs)
45
+ output_record(data, fields: { "ID" => "id", "Path" => "path" })
46
+ end
47
+ end
48
+
49
+ desc "delete ID", "Delete a skill file"
50
+ def delete(id)
51
+ handle_errors do
52
+ client.skill_files.destroy(skill_id: options[:skill], id:)
53
+ puts "Skill file #{id} deleted."
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def update_attrs
60
+ {}.tap do |attrs|
61
+ attrs[:path] = options[:path] if options[:path]
62
+ attrs[:content] = read_content if options[:content] || options[:file]
63
+ end
64
+ end
65
+
66
+ def read_content
67
+ if options[:file]
68
+ file_path = File.expand_path(options[:file])
69
+ abort "Error: File not found: #{file_path}" unless File.exist?(file_path)
70
+ File.read(file_path)
71
+ else
72
+ options[:content]
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SchwarmCli
4
+ module Commands
5
+ class SkillsCmd < Base
6
+ desc "list", "List skills"
7
+ option :query, type: :string, desc: "Search by name"
8
+ def list
9
+ handle_errors do
10
+ data = client.skills.list(query: options[:query])
11
+ output_list(data, columns: [%w[ID id], %w[NAME name], %w[GLOBAL global]])
12
+ end
13
+ end
14
+
15
+ desc "show ID", "Show skill details"
16
+ def show(id)
17
+ handle_errors do
18
+ data = client.skills.find(id)
19
+ output_record(data, fields: {
20
+ "ID" => "id", "Name" => "name", "Description" => "description",
21
+ "Global" => "global", "Created" => "created_at"
22
+ })
23
+ end
24
+ end
25
+
26
+ desc "create", "Create a skill"
27
+ option :name, type: :string, required: true, desc: "Skill name"
28
+ option :description, type: :string, desc: "Skill description"
29
+ option :global, type: :boolean, default: false, desc: "Make skill global"
30
+ def create
31
+ handle_errors do
32
+ attrs = { name: options[:name], global: options[:global] }
33
+ attrs[:description] = options[:description] if options[:description]
34
+
35
+ data = client.skills.create(**attrs)
36
+ output_record(data, fields: { "ID" => "id", "Name" => "name", "Global" => "global" })
37
+ end
38
+ end
39
+
40
+ desc "update ID", "Update a skill"
41
+ option :name, type: :string, desc: "Skill name"
42
+ option :description, type: :string, desc: "Skill description"
43
+ option :global, type: :boolean, desc: "Make skill global"
44
+ def update(id)
45
+ handle_errors do
46
+ data = client.skills.update(id, **update_attrs)
47
+ output_record(data, fields: { "ID" => "id", "Name" => "name", "Global" => "global" })
48
+ end
49
+ end
50
+
51
+ desc "delete ID", "Delete a skill"
52
+ def delete(id)
53
+ handle_errors do
54
+ client.skills.destroy(id)
55
+ puts "Skill #{id} deleted."
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def update_attrs
62
+ { name: options[:name], description: options[:description] }.compact.tap do |attrs|
63
+ attrs[:global] = options[:global] unless options[:global].nil?
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end