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,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SchwarmCli
4
+ module Commands
5
+ class Tasks < Base
6
+ desc "list", "List tasks"
7
+ option :status, type: :string, desc: "Filter by status"
8
+ option :repo, type: :string, desc: "Filter by repository ID"
9
+ option :query, type: :string, desc: "Search by name"
10
+ def list
11
+ handle_errors do
12
+ data = client.tasks.list(status: options[:status], repository_id: options[:repo], query: options[:query])
13
+ output_list(data, columns: [%w[ID id], %w[NAME name], %w[STATUS status],
14
+ %w[REPO github_repository_id], %w[CREATED created_at]])
15
+ end
16
+ end
17
+
18
+ desc "show ID", "Show task details"
19
+ def show(id)
20
+ handle_errors do
21
+ data = client.tasks.find(id)
22
+ output_record(data, fields: {
23
+ "ID" => "id", "Name" => "name", "Status" => "status", "Prompt" => "prompt",
24
+ "Branch" => "branch_name", "Error" => "error_message",
25
+ "Repository" => "github_repository_id", "Dependencies" => "dependency_ids",
26
+ "Created" => "created_at", "Updated" => "updated_at"
27
+ })
28
+ end
29
+ end
30
+
31
+ desc "create", "Create a new task"
32
+ option :name, type: :string, required: true, desc: "Task name"
33
+ option :prompt, type: :string, desc: "Task prompt"
34
+ option :prompt_file, type: :string, desc: "Read prompt from file"
35
+ option :repo, type: :string, desc: "Repository ID"
36
+ option :status, type: :string, desc: "Initial status (draft/waiting)"
37
+ option :template, type: :string, desc: "Template ID"
38
+ option :depends_on, type: :array, desc: "Dependency task IDs"
39
+ def create
40
+ handle_errors do
41
+ data = client.tasks.create(**create_attrs)
42
+ output_record(data, fields: { "ID" => "id", "Name" => "name", "Status" => "status" })
43
+ end
44
+ end
45
+
46
+ desc "update ID", "Update a task"
47
+ option :name, type: :string, desc: "Task name"
48
+ option :prompt, type: :string, desc: "Task prompt"
49
+ option :prompt_file, type: :string, desc: "Read prompt from file"
50
+ option :repo, type: :string, desc: "Repository ID"
51
+ option :depends_on, type: :array, desc: "Dependency task IDs"
52
+ def update(id)
53
+ handle_errors do
54
+ data = client.tasks.update(id, **update_attrs)
55
+ output_record(data, fields: { "ID" => "id", "Name" => "name", "Status" => "status" })
56
+ end
57
+ end
58
+
59
+ desc "delete ID", "Delete a task"
60
+ def delete(id)
61
+ handle_errors do
62
+ client.tasks.destroy(id)
63
+ puts "Task #{id} deleted."
64
+ end
65
+ end
66
+
67
+ desc "start ID", "Start a task"
68
+ def start(id)
69
+ handle_errors do
70
+ data = client.tasks.start(id)
71
+ puts "Task #{id} started (#{data.dig('data', 'status')})."
72
+ end
73
+ end
74
+
75
+ desc "archive ID", "Archive a task"
76
+ def archive(id)
77
+ handle_errors do
78
+ data = client.tasks.archive(id)
79
+ puts "Task #{id} archived (#{data.dig('data', 'status')})."
80
+ end
81
+ end
82
+
83
+ desc "retry ID", "Retry a failed task"
84
+ def retry(id)
85
+ handle_errors do
86
+ data = client.tasks.retry(id)
87
+ puts "Task #{id} retried (#{data.dig('data', 'status')})."
88
+ end
89
+ end
90
+
91
+ desc "reset ID", "Reset a task to draft"
92
+ def reset(id)
93
+ handle_errors do
94
+ data = client.tasks.reset(id)
95
+ puts "Task #{id} reset (#{data.dig('data', 'status')})."
96
+ end
97
+ end
98
+
99
+ desc "pause ID", "Pause a task"
100
+ def pause(id)
101
+ handle_errors do
102
+ data = client.tasks.pause(id)
103
+ puts "Task #{id} paused (#{data.dig('data', 'status')})."
104
+ end
105
+ end
106
+
107
+ desc "message ID", "Send a message to a running task"
108
+ option :content, type: :string, required: true, desc: "Message content"
109
+ def message(id)
110
+ handle_errors do
111
+ client.messages.create(task_id: id, content: options[:content])
112
+ puts "Message sent to task #{id}."
113
+ end
114
+ end
115
+
116
+ private
117
+
118
+ def create_attrs
119
+ {
120
+ name: options[:name], prompt: read_prompt,
121
+ github_repository_id: options[:repo], status: options[:status],
122
+ task_template_id: options[:template], dependency_ids: options[:depends_on]
123
+ }.compact
124
+ end
125
+
126
+ def update_attrs
127
+ {
128
+ name: options[:name], github_repository_id: options[:repo],
129
+ dependency_ids: options[:depends_on]
130
+ }.compact.tap do |attrs|
131
+ attrs[:prompt] = read_prompt if options[:prompt] || options[:prompt_file]
132
+ end
133
+ end
134
+
135
+ def read_prompt
136
+ if options[:prompt_file]
137
+ file_path = File.expand_path(options[:prompt_file])
138
+ abort "Error: File not found: #{file_path}" unless File.exist?(file_path)
139
+ File.read(file_path)
140
+ else
141
+ options[:prompt]
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SchwarmCli
4
+ module Commands
5
+ class Templates < Base
6
+ desc "list", "List task templates"
7
+ option :query, type: :string, desc: "Search by name"
8
+ def list
9
+ handle_errors do
10
+ data = client.templates.list(query: options[:query])
11
+ output_list(data, columns: [%w[ID id], %w[NAME name], %w[CREATED created_at]])
12
+ end
13
+ end
14
+
15
+ desc "show ID", "Show template details"
16
+ def show(id)
17
+ handle_errors do
18
+ data = client.templates.find(id)
19
+ output_record(data, fields: {
20
+ "ID" => "id", "Name" => "name", "Prompt" => "prompt", "Created" => "created_at"
21
+ })
22
+ end
23
+ end
24
+
25
+ desc "create", "Create a task template"
26
+ option :name, type: :string, required: true, desc: "Template name"
27
+ option :prompt, type: :string, required: true, desc: "Template prompt"
28
+ def create
29
+ handle_errors do
30
+ data = client.templates.create(name: options[:name], prompt: options[:prompt])
31
+ output_record(data, fields: { "ID" => "id", "Name" => "name" })
32
+ end
33
+ end
34
+
35
+ desc "update ID", "Update a task template"
36
+ option :name, type: :string, desc: "Template name"
37
+ option :prompt, type: :string, desc: "Template prompt"
38
+ def update(id)
39
+ handle_errors do
40
+ attrs = {}
41
+ attrs[:name] = options[:name] if options[:name]
42
+ attrs[:prompt] = options[:prompt] if options[:prompt]
43
+
44
+ data = client.templates.update(id, **attrs)
45
+ output_record(data, fields: { "ID" => "id", "Name" => "name" })
46
+ end
47
+ end
48
+
49
+ desc "delete ID", "Delete a task template"
50
+ def delete(id)
51
+ handle_errors do
52
+ client.templates.destroy(id)
53
+ puts "Template #{id} deleted."
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "fileutils"
5
+
6
+ module SchwarmCli
7
+ # Loads CLI configuration from multiple sources with priority:
8
+ # 1. Explicit constructor arguments (highest)
9
+ # 2. Environment variables (SCHWARM_URL, SCHWARM_TOKEN)
10
+ # 3. Config file (~/.config/schwarm.json)
11
+ class Config
12
+ DEFAULT_PATH = File.expand_path("~/.config/schwarm.json")
13
+
14
+ attr_reader :url, :api_key, :config_path
15
+
16
+ def initialize(url: nil, api_key: nil, config_path: DEFAULT_PATH)
17
+ @config_path = config_path
18
+ file_config = load_file
19
+ @url = strip_slash(url || ENV["SCHWARM_URL"] || file_config["url"])
20
+ @api_key = api_key || ENV["SCHWARM_TOKEN"] || file_config["api_key"]
21
+ end
22
+
23
+ def valid?
24
+ !@url.nil? && !@url.empty? && !@api_key.nil? && !@api_key.empty?
25
+ end
26
+
27
+ def save
28
+ FileUtils.mkdir_p(File.dirname(@config_path))
29
+ File.write(@config_path, JSON.pretty_generate(url: @url, api_key: @api_key))
30
+ end
31
+
32
+ private
33
+
34
+ def load_file
35
+ return {} unless File.exist?(@config_path)
36
+
37
+ JSON.parse(File.read(@config_path))
38
+ rescue JSON::ParserError
39
+ {}
40
+ end
41
+
42
+ def strip_slash(value)
43
+ value&.chomp("/")
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module SchwarmCli
6
+ module Formatters
7
+ module Json
8
+ def self.format(data)
9
+ puts JSON.pretty_generate(data)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SchwarmCli
4
+ module Formatters
5
+ module Table
6
+ def self.format_list(records, columns:)
7
+ if records.empty?
8
+ puts "No results found."
9
+ return
10
+ end
11
+
12
+ widths = column_widths(records, columns)
13
+ puts format_row(columns.map(&:first), columns, widths)
14
+ records.each do |record|
15
+ puts format_row(columns.map { |_, key| record[key].to_s }, columns, widths)
16
+ end
17
+ end
18
+
19
+ def self.format_record(record, fields:)
20
+ label_width = fields.keys.map(&:length).max
21
+ fields.each do |label, key|
22
+ puts "#{label.rjust(label_width)}: #{record[key]}"
23
+ end
24
+ end
25
+
26
+ def self.column_widths(records, columns)
27
+ columns.to_h do |label, key|
28
+ [key, [label.length, *records.map { |r| r[key].to_s.length }].max]
29
+ end
30
+ end
31
+
32
+ def self.format_row(values, columns, widths)
33
+ values.zip(columns).map { |val, (_, key)| val.ljust(widths[key]) }.join(" ")
34
+ end
35
+
36
+ private_class_method :column_widths, :format_row
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SchwarmCli
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "schwarm_cli/version"
4
+ require_relative "schwarm_cli/config"
5
+ require_relative "schwarm_cli/client"
6
+ require_relative "schwarm_cli/formatters/json"
7
+ require_relative "schwarm_cli/formatters/table"
8
+ require_relative "schwarm_cli/commands/main"
9
+
10
+ module SchwarmCli
11
+ class Error < StandardError; end
12
+ end
metadata ADDED
@@ -0,0 +1,148 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: schwarm-cli
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Vincent Garrigues
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: faraday
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '2.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '2.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: faraday-net_http_persistent
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '2.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '2.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: faraday-retry
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '2.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '2.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: gum
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.1'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '0.1'
68
+ - !ruby/object:Gem::Dependency
69
+ name: thor
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.3'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '1.3'
82
+ description: Command-line interface for managing tasks, repositories, skills, and
83
+ agents on a Schwarm server via the public API v2.
84
+ executables:
85
+ - schwarm
86
+ extensions: []
87
+ extra_rdoc_files: []
88
+ files:
89
+ - bin/schwarm
90
+ - lib/schwarm_cli.rb
91
+ - lib/schwarm_cli/client.rb
92
+ - lib/schwarm_cli/client/agent_sessions.rb
93
+ - lib/schwarm_cli/client/recurring_tasks.rb
94
+ - lib/schwarm_cli/client/repositories.rb
95
+ - lib/schwarm_cli/client/repository_agents.rb
96
+ - lib/schwarm_cli/client/repository_skills.rb
97
+ - lib/schwarm_cli/client/resource.rb
98
+ - lib/schwarm_cli/client/secret_files.rb
99
+ - lib/schwarm_cli/client/shared_agents.rb
100
+ - lib/schwarm_cli/client/skill_files.rb
101
+ - lib/schwarm_cli/client/skills.rb
102
+ - lib/schwarm_cli/client/task_templates.rb
103
+ - lib/schwarm_cli/client/tasks.rb
104
+ - lib/schwarm_cli/client/user_messages.rb
105
+ - lib/schwarm_cli/commands/agents.rb
106
+ - lib/schwarm_cli/commands/base.rb
107
+ - lib/schwarm_cli/commands/configure.rb
108
+ - lib/schwarm_cli/commands/main.rb
109
+ - lib/schwarm_cli/commands/recurring.rb
110
+ - lib/schwarm_cli/commands/repo_skills.rb
111
+ - lib/schwarm_cli/commands/repos.rb
112
+ - lib/schwarm_cli/commands/secrets.rb
113
+ - lib/schwarm_cli/commands/sessions.rb
114
+ - lib/schwarm_cli/commands/shared_agents.rb
115
+ - lib/schwarm_cli/commands/skill_files.rb
116
+ - lib/schwarm_cli/commands/skills.rb
117
+ - lib/schwarm_cli/commands/tasks.rb
118
+ - lib/schwarm_cli/commands/templates.rb
119
+ - lib/schwarm_cli/config.rb
120
+ - lib/schwarm_cli/formatters/json.rb
121
+ - lib/schwarm_cli/formatters/table.rb
122
+ - lib/schwarm_cli/version.rb
123
+ homepage: https://github.com/getdexter/schwarm
124
+ licenses:
125
+ - MIT
126
+ metadata:
127
+ homepage_uri: https://github.com/getdexter/schwarm
128
+ source_code_uri: https://github.com/getdexter/schwarm/tree/main/cli
129
+ changelog_uri: https://github.com/getdexter/schwarm/blob/main/cli/CHANGELOG.md
130
+ rubygems_mfa_required: 'true'
131
+ rdoc_options: []
132
+ require_paths:
133
+ - lib
134
+ required_ruby_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '4.0'
139
+ required_rubygems_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ requirements: []
145
+ rubygems_version: 4.0.6
146
+ specification_version: 4
147
+ summary: CLI for the Schwarm distributed agent system
148
+ test_files: []