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.
- checksums.yaml +7 -0
- data/bin/schwarm +14 -0
- data/lib/schwarm_cli/client/agent_sessions.rb +16 -0
- data/lib/schwarm_cli/client/recurring_tasks.rb +33 -0
- data/lib/schwarm_cli/client/repositories.rb +37 -0
- data/lib/schwarm_cli/client/repository_agents.rb +37 -0
- data/lib/schwarm_cli/client/repository_skills.rb +25 -0
- data/lib/schwarm_cli/client/resource.rb +20 -0
- data/lib/schwarm_cli/client/secret_files.rb +29 -0
- data/lib/schwarm_cli/client/shared_agents.rb +33 -0
- data/lib/schwarm_cli/client/skill_files.rb +29 -0
- data/lib/schwarm_cli/client/skills.rb +29 -0
- data/lib/schwarm_cli/client/task_templates.rb +29 -0
- data/lib/schwarm_cli/client/tasks.rb +49 -0
- data/lib/schwarm_cli/client/user_messages.rb +11 -0
- data/lib/schwarm_cli/client.rb +101 -0
- data/lib/schwarm_cli/commands/agents.rb +92 -0
- data/lib/schwarm_cli/commands/base.rb +63 -0
- data/lib/schwarm_cli/commands/configure.rb +31 -0
- data/lib/schwarm_cli/commands/main.rb +64 -0
- data/lib/schwarm_cli/commands/recurring.rb +85 -0
- data/lib/schwarm_cli/commands/repo_skills.rb +50 -0
- data/lib/schwarm_cli/commands/repos.rb +86 -0
- data/lib/schwarm_cli/commands/secrets.rb +82 -0
- data/lib/schwarm_cli/commands/sessions.rb +30 -0
- data/lib/schwarm_cli/commands/shared_agents.rb +81 -0
- data/lib/schwarm_cli/commands/skill_files.rb +77 -0
- data/lib/schwarm_cli/commands/skills.rb +68 -0
- data/lib/schwarm_cli/commands/tasks.rb +146 -0
- data/lib/schwarm_cli/commands/templates.rb +58 -0
- data/lib/schwarm_cli/config.rb +46 -0
- data/lib/schwarm_cli/formatters/json.rb +13 -0
- data/lib/schwarm_cli/formatters/table.rb +39 -0
- data/lib/schwarm_cli/version.rb +5 -0
- data/lib/schwarm_cli.rb +12 -0
- metadata +148 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 485f701799de73d084bf43fff3cc0ebf1244a41397775baea03de793b860b4b9
|
|
4
|
+
data.tar.gz: 6125bc6e805189c3faa9ec3d33ff6545fd77c4c93ab966ccae142a2fc50102a5
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 1ef6550c32124fe3a2125dc2e79d10c05ec918bbabafd17918d1c13274954b33fae413cd679f58e5484c4b02b97bda64c6d495a62fb02d38e1afba389de7ac69
|
|
7
|
+
data.tar.gz: 2057d8334094ab913ebc115ed3818a54887cafa922688bcc66f54be4035322d51466ccd7610a1aad0b68f59ccb643604551a7b7e791168ba49f3be4a9e83dbf7
|
data/bin/schwarm
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require_relative "../lib/schwarm_cli"
|
|
5
|
+
|
|
6
|
+
begin
|
|
7
|
+
SchwarmCli::Commands::Main.start(ARGV)
|
|
8
|
+
rescue SchwarmCli::Error => e
|
|
9
|
+
warn "Error: #{e.message}"
|
|
10
|
+
exit 1
|
|
11
|
+
rescue Interrupt
|
|
12
|
+
warn "\nInterrupted"
|
|
13
|
+
exit 130
|
|
14
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SchwarmCli
|
|
4
|
+
class Client
|
|
5
|
+
class AgentSessions < Resource
|
|
6
|
+
def list(source: nil, status: nil, page: nil, per_page: nil)
|
|
7
|
+
params = { source:, status:, page:, per_page: }.compact
|
|
8
|
+
get("/api/v2/agent_sessions", params).body
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def find(id)
|
|
12
|
+
get("/api/v2/agent_sessions/#{id}").body
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SchwarmCli
|
|
4
|
+
class Client
|
|
5
|
+
class RecurringTasks < Resource
|
|
6
|
+
def list(repository_id: nil, query: nil, page: nil, per_page: nil)
|
|
7
|
+
params = { repository_id:, q: query, page:, per_page: }.compact
|
|
8
|
+
get("/api/v2/recurring_tasks", params).body
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def find(id)
|
|
12
|
+
get("/api/v2/recurring_tasks/#{id}").body
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create(**attributes)
|
|
16
|
+
post("/api/v2/recurring_tasks", { recurring_task: attributes }).body
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def update(id, **attributes)
|
|
20
|
+
patch("/api/v2/recurring_tasks/#{id}", { recurring_task: attributes }).body
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def destroy(id)
|
|
24
|
+
delete("/api/v2/recurring_tasks/#{id}")
|
|
25
|
+
nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def toggle(id)
|
|
29
|
+
post("/api/v2/recurring_tasks/#{id}/toggle").body
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SchwarmCli
|
|
4
|
+
class Client
|
|
5
|
+
class Repositories < Resource
|
|
6
|
+
def list(status: nil, query: nil, page: nil, per_page: nil)
|
|
7
|
+
params = { status:, q: query, page:, per_page: }.compact
|
|
8
|
+
get("/api/v2/repositories", params).body
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def find(id)
|
|
12
|
+
get("/api/v2/repositories/#{id}").body
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create(**attributes)
|
|
16
|
+
post("/api/v2/repositories", { repository: attributes }).body
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def update(id, **attributes)
|
|
20
|
+
patch("/api/v2/repositories/#{id}", { repository: attributes }).body
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def destroy(id)
|
|
24
|
+
delete("/api/v2/repositories/#{id}")
|
|
25
|
+
nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def pause(id)
|
|
29
|
+
post("/api/v2/repositories/#{id}/pause").body
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def resume(id)
|
|
33
|
+
post("/api/v2/repositories/#{id}/resume").body
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SchwarmCli
|
|
4
|
+
class Client
|
|
5
|
+
class RepositoryAgents < Resource
|
|
6
|
+
def list(repository_id: nil, query: nil, page: nil, per_page: nil)
|
|
7
|
+
params = { repository_id:, q: query, page:, per_page: }.compact
|
|
8
|
+
get("/api/v2/repository_agents", params).body
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def find(id)
|
|
12
|
+
get("/api/v2/repository_agents/#{id}").body
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create(**attributes)
|
|
16
|
+
post("/api/v2/repository_agents", { repository_agent: attributes }).body
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def update(id, **attributes)
|
|
20
|
+
patch("/api/v2/repository_agents/#{id}", { repository_agent: attributes }).body
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def destroy(id)
|
|
24
|
+
delete("/api/v2/repository_agents/#{id}")
|
|
25
|
+
nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def toggle(id)
|
|
29
|
+
post("/api/v2/repository_agents/#{id}/toggle").body
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def run_now(id)
|
|
33
|
+
post("/api/v2/repository_agents/#{id}/run_now").body
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SchwarmCli
|
|
4
|
+
class Client
|
|
5
|
+
class RepositorySkills < Resource
|
|
6
|
+
def list(repository_id: nil, skill_id: nil, page: nil, per_page: nil)
|
|
7
|
+
params = { repository_id:, skill_id:, page:, per_page: }.compact
|
|
8
|
+
get("/api/v2/repository_skills", params).body
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def find(id)
|
|
12
|
+
get("/api/v2/repository_skills/#{id}").body
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create(**attributes)
|
|
16
|
+
post("/api/v2/repository_skills", { repository_skill: attributes }).body
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def destroy(id)
|
|
20
|
+
delete("/api/v2/repository_skills/#{id}")
|
|
21
|
+
nil
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SchwarmCli
|
|
4
|
+
class Client
|
|
5
|
+
class Resource
|
|
6
|
+
def initialize(client:)
|
|
7
|
+
@client = client
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
attr_reader :client
|
|
13
|
+
|
|
14
|
+
def get(...) = client.get(...)
|
|
15
|
+
def post(...) = client.post(...)
|
|
16
|
+
def patch(...) = client.patch(...)
|
|
17
|
+
def delete(...) = client.delete(...)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SchwarmCli
|
|
4
|
+
class Client
|
|
5
|
+
class SecretFiles < Resource
|
|
6
|
+
def list(repository_id: nil, page: nil, per_page: nil)
|
|
7
|
+
params = { repository_id:, page:, per_page: }.compact
|
|
8
|
+
get("/api/v2/secret_files", params).body
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def find(id)
|
|
12
|
+
get("/api/v2/secret_files/#{id}").body
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create(**attributes)
|
|
16
|
+
post("/api/v2/secret_files", { secret_file: attributes }).body
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def update(id, **attributes)
|
|
20
|
+
patch("/api/v2/secret_files/#{id}", { secret_file: attributes }).body
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def destroy(id)
|
|
24
|
+
delete("/api/v2/secret_files/#{id}")
|
|
25
|
+
nil
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SchwarmCli
|
|
4
|
+
class Client
|
|
5
|
+
class SharedAgents < Resource
|
|
6
|
+
def list(query: nil, page: nil, per_page: nil)
|
|
7
|
+
params = { q: query, page:, per_page: }.compact
|
|
8
|
+
get("/api/v2/shared_agents", params).body
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def find(id)
|
|
12
|
+
get("/api/v2/shared_agents/#{id}").body
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create(**attributes)
|
|
16
|
+
post("/api/v2/shared_agents", { shared_agent: attributes }).body
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def update(id, **attributes)
|
|
20
|
+
patch("/api/v2/shared_agents/#{id}", { shared_agent: attributes }).body
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def destroy(id)
|
|
24
|
+
delete("/api/v2/shared_agents/#{id}")
|
|
25
|
+
nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def toggle(id)
|
|
29
|
+
post("/api/v2/shared_agents/#{id}/toggle").body
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SchwarmCli
|
|
4
|
+
class Client
|
|
5
|
+
class SkillFiles < Resource
|
|
6
|
+
def list(skill_id:, page: nil, per_page: nil)
|
|
7
|
+
params = { page:, per_page: }.compact
|
|
8
|
+
get("/api/v2/skills/#{skill_id}/files", params).body
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def find(skill_id:, id:)
|
|
12
|
+
get("/api/v2/skills/#{skill_id}/files/#{id}").body
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create(skill_id:, **attributes)
|
|
16
|
+
post("/api/v2/skills/#{skill_id}/files", { skill_file: attributes }).body
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def update(skill_id:, id:, **attributes)
|
|
20
|
+
patch("/api/v2/skills/#{skill_id}/files/#{id}", { skill_file: attributes }).body
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def destroy(skill_id:, id:)
|
|
24
|
+
delete("/api/v2/skills/#{skill_id}/files/#{id}")
|
|
25
|
+
nil
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SchwarmCli
|
|
4
|
+
class Client
|
|
5
|
+
class Skills < Resource
|
|
6
|
+
def list(query: nil, page: nil, per_page: nil)
|
|
7
|
+
params = { q: query, page:, per_page: }.compact
|
|
8
|
+
get("/api/v2/skills", params).body
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def find(id)
|
|
12
|
+
get("/api/v2/skills/#{id}").body
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create(**attributes)
|
|
16
|
+
post("/api/v2/skills", { skill: attributes }).body
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def update(id, **attributes)
|
|
20
|
+
patch("/api/v2/skills/#{id}", { skill: attributes }).body
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def destroy(id)
|
|
24
|
+
delete("/api/v2/skills/#{id}")
|
|
25
|
+
nil
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SchwarmCli
|
|
4
|
+
class Client
|
|
5
|
+
class TaskTemplates < Resource
|
|
6
|
+
def list(query: nil, page: nil, per_page: nil)
|
|
7
|
+
params = { q: query, page:, per_page: }.compact
|
|
8
|
+
get("/api/v2/task_templates", params).body
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def find(id)
|
|
12
|
+
get("/api/v2/task_templates/#{id}").body
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create(**attributes)
|
|
16
|
+
post("/api/v2/task_templates", { task_template: attributes }).body
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def update(id, **attributes)
|
|
20
|
+
patch("/api/v2/task_templates/#{id}", { task_template: attributes }).body
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def destroy(id)
|
|
24
|
+
delete("/api/v2/task_templates/#{id}")
|
|
25
|
+
nil
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SchwarmCli
|
|
4
|
+
class Client
|
|
5
|
+
class Tasks < Resource
|
|
6
|
+
def list(status: nil, repository_id: nil, page: nil, per_page: nil, query: nil)
|
|
7
|
+
params = { status:, repository_id:, page:, per_page:, q: query }.compact
|
|
8
|
+
get("/api/v2/tasks", params).body
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def find(id)
|
|
12
|
+
get("/api/v2/tasks/#{id}").body
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create(**attributes)
|
|
16
|
+
post("/api/v2/tasks", { task: attributes }).body
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def update(id, **attributes)
|
|
20
|
+
patch("/api/v2/tasks/#{id}", { task: attributes }).body
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def destroy(id)
|
|
24
|
+
delete("/api/v2/tasks/#{id}")
|
|
25
|
+
nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def start(id)
|
|
29
|
+
post("/api/v2/tasks/#{id}/start").body
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def archive(id)
|
|
33
|
+
post("/api/v2/tasks/#{id}/archive").body
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def retry(id)
|
|
37
|
+
post("/api/v2/tasks/#{id}/retry").body
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def reset(id)
|
|
41
|
+
post("/api/v2/tasks/#{id}/reset").body
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def pause(id)
|
|
45
|
+
post("/api/v2/tasks/#{id}/pause").body
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "faraday"
|
|
4
|
+
require "faraday/net_http_persistent"
|
|
5
|
+
require "faraday/retry"
|
|
6
|
+
|
|
7
|
+
require_relative "client/resource"
|
|
8
|
+
require_relative "client/tasks"
|
|
9
|
+
require_relative "client/repositories"
|
|
10
|
+
require_relative "client/skills"
|
|
11
|
+
require_relative "client/skill_files"
|
|
12
|
+
require_relative "client/task_templates"
|
|
13
|
+
require_relative "client/recurring_tasks"
|
|
14
|
+
require_relative "client/repository_agents"
|
|
15
|
+
require_relative "client/shared_agents"
|
|
16
|
+
require_relative "client/secret_files"
|
|
17
|
+
require_relative "client/agent_sessions"
|
|
18
|
+
require_relative "client/repository_skills"
|
|
19
|
+
require_relative "client/user_messages"
|
|
20
|
+
|
|
21
|
+
module SchwarmCli
|
|
22
|
+
class Client
|
|
23
|
+
attr_reader :tasks, :repositories, :skills, :skill_files, :templates,
|
|
24
|
+
:recurring, :agents, :shared_agents, :secrets, :sessions,
|
|
25
|
+
:repo_skills, :messages
|
|
26
|
+
|
|
27
|
+
def get(...) = conn.get(...)
|
|
28
|
+
def post(...) = conn.post(...)
|
|
29
|
+
def patch(...) = conn.patch(...)
|
|
30
|
+
def delete(...) = conn.delete(...)
|
|
31
|
+
|
|
32
|
+
def initialize(url: nil, api_key: nil, config_path: Config::DEFAULT_PATH)
|
|
33
|
+
config = Config.new(url:, api_key:, config_path:)
|
|
34
|
+
unless config.valid?
|
|
35
|
+
raise Error,
|
|
36
|
+
"Schwarm CLI not configured. Run `schwarm configure` or set SCHWARM_URL and SCHWARM_TOKEN."
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
@url = config.url
|
|
40
|
+
@api_key = config.api_key
|
|
41
|
+
init_resources
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
attr_reader :url, :api_key
|
|
47
|
+
|
|
48
|
+
def init_resources
|
|
49
|
+
@tasks = Tasks.new(client: self)
|
|
50
|
+
@repositories = Repositories.new(client: self)
|
|
51
|
+
@skills = Skills.new(client: self)
|
|
52
|
+
@skill_files = SkillFiles.new(client: self)
|
|
53
|
+
@templates = TaskTemplates.new(client: self)
|
|
54
|
+
@recurring = RecurringTasks.new(client: self)
|
|
55
|
+
@agents = RepositoryAgents.new(client: self)
|
|
56
|
+
@shared_agents = SharedAgents.new(client: self)
|
|
57
|
+
@secrets = SecretFiles.new(client: self)
|
|
58
|
+
@sessions = AgentSessions.new(client: self)
|
|
59
|
+
@repo_skills = RepositorySkills.new(client: self)
|
|
60
|
+
@messages = UserMessages.new(client: self)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def conn
|
|
64
|
+
@conn ||= Faraday.new(url:, headers:, **faraday_options) do |f|
|
|
65
|
+
f.request :json
|
|
66
|
+
f.request :authorization, "Bearer", api_key
|
|
67
|
+
f.request :retry, retry_options
|
|
68
|
+
|
|
69
|
+
f.response :json
|
|
70
|
+
f.response :raise_error
|
|
71
|
+
|
|
72
|
+
f.adapter :net_http_persistent
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def headers
|
|
77
|
+
{ "User-Agent" => "schwarm-cli/#{VERSION}" }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def faraday_options
|
|
81
|
+
{
|
|
82
|
+
request: {
|
|
83
|
+
open_timeout: 5,
|
|
84
|
+
read_timeout: 30,
|
|
85
|
+
write_timeout: 30
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def retry_options
|
|
91
|
+
{
|
|
92
|
+
max: 3,
|
|
93
|
+
interval: 0.5,
|
|
94
|
+
backoff_factor: 2,
|
|
95
|
+
interval_randomness: 0.5,
|
|
96
|
+
retry_statuses: [429, 500, 502, 503, 504],
|
|
97
|
+
methods: %i[get head options]
|
|
98
|
+
}
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SchwarmCli
|
|
4
|
+
module Commands
|
|
5
|
+
class Agents < Base
|
|
6
|
+
desc "list", "List repository agents"
|
|
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.agents.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 agent details"
|
|
18
|
+
def show(id)
|
|
19
|
+
handle_errors do
|
|
20
|
+
data = client.agents.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 repository agent"
|
|
30
|
+
option :name, type: :string, required: true, desc: "Agent name"
|
|
31
|
+
option :repo, type: :string, required: true, desc: "Repository ID"
|
|
32
|
+
option :prompt, type: :string, required: true, desc: "Agent prompt"
|
|
33
|
+
option :schedule, type: :string, desc: "Cron schedule"
|
|
34
|
+
def create
|
|
35
|
+
handle_errors do
|
|
36
|
+
attrs = { name: options[:name], github_repository_id: options[:repo], prompt: options[:prompt] }
|
|
37
|
+
attrs[:schedule] = options[:schedule] if options[:schedule]
|
|
38
|
+
|
|
39
|
+
data = client.agents.create(**attrs)
|
|
40
|
+
output_record(data, fields: { "ID" => "id", "Name" => "name", "Enabled" => "enabled" })
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
desc "update ID", "Update a repository agent"
|
|
45
|
+
option :name, type: :string, desc: "Agent name"
|
|
46
|
+
option :prompt, type: :string, desc: "Agent prompt"
|
|
47
|
+
option :schedule, type: :string, desc: "Cron schedule"
|
|
48
|
+
def update(id)
|
|
49
|
+
handle_errors do
|
|
50
|
+
data = client.agents.update(id, **update_attrs)
|
|
51
|
+
output_record(data, fields: { "ID" => "id", "Name" => "name", "Enabled" => "enabled" })
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
desc "delete ID", "Delete a repository agent"
|
|
56
|
+
def delete(id)
|
|
57
|
+
handle_errors do
|
|
58
|
+
client.agents.destroy(id)
|
|
59
|
+
puts "Agent #{id} deleted."
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
desc "toggle ID", "Toggle agent enabled/disabled"
|
|
64
|
+
def toggle(id)
|
|
65
|
+
handle_errors do
|
|
66
|
+
data = client.agents.toggle(id)
|
|
67
|
+
status = data.dig("data", "enabled") ? "enabled" : "disabled"
|
|
68
|
+
puts "Agent #{id} #{status}."
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
desc "run-now ID", "Trigger agent to run immediately"
|
|
73
|
+
map "run-now" => :run_now
|
|
74
|
+
def run_now(id)
|
|
75
|
+
handle_errors do
|
|
76
|
+
client.agents.run_now(id)
|
|
77
|
+
puts "Agent #{id} triggered."
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
def update_attrs
|
|
84
|
+
{}.tap do |attrs|
|
|
85
|
+
attrs[:name] = options[:name] if options[:name]
|
|
86
|
+
attrs[:prompt] = options[:prompt] if options[:prompt]
|
|
87
|
+
attrs[:schedule] = options[:schedule] if options[:schedule]
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "thor"
|
|
4
|
+
|
|
5
|
+
module SchwarmCli
|
|
6
|
+
module Commands
|
|
7
|
+
class Base < Thor
|
|
8
|
+
class_option :json, type: :boolean, default: false, desc: "Output as JSON"
|
|
9
|
+
class_option :url, type: :string, desc: "Schwarm server URL (overrides config)"
|
|
10
|
+
class_option :token, type: :string, desc: "API key (overrides config)"
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def client
|
|
15
|
+
@client ||= SchwarmCli::Client.new(url: options[:url], api_key: options[:token])
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def output_list(data, columns:)
|
|
19
|
+
if options[:json]
|
|
20
|
+
Formatters::Json.format(data)
|
|
21
|
+
else
|
|
22
|
+
Formatters::Table.format_list(data["data"], columns:)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def output_record(data, fields:)
|
|
27
|
+
if options[:json]
|
|
28
|
+
Formatters::Json.format(data)
|
|
29
|
+
else
|
|
30
|
+
Formatters::Table.format_record(data["data"], fields:)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def handle_errors
|
|
35
|
+
yield
|
|
36
|
+
rescue Faraday::UnauthorizedError
|
|
37
|
+
abort "Error: Unauthorized. Check your API key or run `schwarm configure`."
|
|
38
|
+
rescue Faraday::ResourceNotFound
|
|
39
|
+
abort "Error: Not found."
|
|
40
|
+
rescue Faraday::UnprocessableEntityError => e
|
|
41
|
+
abort "Error: #{parse_error_body(e)}"
|
|
42
|
+
rescue Faraday::ClientError => e
|
|
43
|
+
abort "Error: #{e.message}"
|
|
44
|
+
rescue Faraday::ServerError
|
|
45
|
+
abort "Error: Server error. Try again later."
|
|
46
|
+
rescue Faraday::ConnectionFailed
|
|
47
|
+
abort "Error: Could not connect to Schwarm server."
|
|
48
|
+
rescue Faraday::TimeoutError
|
|
49
|
+
abort "Error: Request timed out."
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def parse_error_body(error)
|
|
53
|
+
body = error.response&.dig(:body)
|
|
54
|
+
return "Validation failed" unless body.is_a?(String)
|
|
55
|
+
|
|
56
|
+
parsed = JSON.parse(body)
|
|
57
|
+
parsed.dig("error", "message") || "Validation failed"
|
|
58
|
+
rescue JSON::ParserError
|
|
59
|
+
"Validation failed"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|