schwarm-cli 0.1.6 → 0.1.8
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 +4 -4
- data/lib/schwarm_cli/client.rb +3 -3
- data/lib/schwarm_cli/commands/agent_subscriptions.rb +107 -0
- data/lib/schwarm_cli/commands/agents.rb +18 -30
- data/lib/schwarm_cli/commands/base.rb +10 -8
- data/lib/schwarm_cli/commands/main.rb +5 -7
- data/lib/schwarm_cli/commands/recurring.rb +6 -6
- data/lib/schwarm_cli/commands/repos.rb +10 -2
- data/lib/schwarm_cli/commands/secrets.rb +26 -25
- data/lib/schwarm_cli/commands/sessions.rb +2 -1
- data/lib/schwarm_cli/commands/skills.rb +25 -4
- data/lib/schwarm_cli/commands/templates.rb +19 -7
- data/lib/schwarm_cli/version.rb +1 -1
- data/schwarm-skill.md +9 -4
- metadata +2 -2
- data/lib/schwarm_cli/commands/shared_agents.rb +0 -84
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1ce993c4ccb8c15a7a2743ef5d28c8f2c06e3513dad637c23ad0f7929e3dc8b5
|
|
4
|
+
data.tar.gz: add9e02c84c8b0bb05d96c34c0b07b68210669449bb0c428cda290b4559137a4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 54bde32d06880389d77bf624a431c4f702f58fefd6d97067f0f4b6e042ab4bd6fba7e64f3399a16e19e0a4fb1473580c68f45998ae8248cb9ca8a08d3c5ea327
|
|
7
|
+
data.tar.gz: f2a4b9dd8b1b2061c3dc7d9512b2889e260abce55c640b8f5638caded2c790c0db5f03753a895a418a9075c54a41dc69050f1af09b89750e167e187036742cf2
|
data/lib/schwarm_cli/client.rb
CHANGED
|
@@ -21,7 +21,7 @@ require_relative "client/user_messages"
|
|
|
21
21
|
module SchwarmCli
|
|
22
22
|
class Client
|
|
23
23
|
attr_reader :tasks, :repositories, :skills, :skill_files, :templates,
|
|
24
|
-
:recurring, :agents, :
|
|
24
|
+
:recurring, :agents, :subscriptions, :secrets, :sessions,
|
|
25
25
|
:repo_skills, :messages
|
|
26
26
|
|
|
27
27
|
def get(...) = conn.get(...)
|
|
@@ -52,8 +52,8 @@ module SchwarmCli
|
|
|
52
52
|
@skill_files = SkillFiles.new(client: self)
|
|
53
53
|
@templates = TaskTemplates.new(client: self)
|
|
54
54
|
@recurring = RecurringTasks.new(client: self)
|
|
55
|
-
@agents =
|
|
56
|
-
@
|
|
55
|
+
@agents = SharedAgents.new(client: self)
|
|
56
|
+
@subscriptions = RepositoryAgents.new(client: self)
|
|
57
57
|
@secrets = SecretFiles.new(client: self)
|
|
58
58
|
@sessions = AgentSessions.new(client: self)
|
|
59
59
|
@repo_skills = RepositorySkills.new(client: self)
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SchwarmCli
|
|
4
|
+
module Commands
|
|
5
|
+
class AgentSubscriptions < Base
|
|
6
|
+
desc "list", "List repository subscriptions"
|
|
7
|
+
option :repo, type: :string, desc: "Filter by repository ID, owner/repo, or GitHub URL"
|
|
8
|
+
option :query, type: :string, desc: "Search by name"
|
|
9
|
+
pagination_options
|
|
10
|
+
def list
|
|
11
|
+
handle_errors do
|
|
12
|
+
data = fetch_paged do |page_params|
|
|
13
|
+
client.subscriptions.list(repository_id: resolve_repo(options[:repo]), query: options[:query],
|
|
14
|
+
**page_params)
|
|
15
|
+
end
|
|
16
|
+
output_list(data, columns: [%w[ID id], %w[NAME name], %w[REPO github_repository_name],
|
|
17
|
+
%w[ENABLED enabled], %w[SCHEDULE schedule]])
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
desc "show ID", "Show subscription details"
|
|
22
|
+
def show(id)
|
|
23
|
+
handle_errors do
|
|
24
|
+
data = client.subscriptions.find(id)
|
|
25
|
+
output_record(data, fields: {
|
|
26
|
+
"ID" => "id", "Name" => "name", "Repository" => "github_repository_name",
|
|
27
|
+
"Agent" => "shared_agent_id", "Enabled" => "enabled",
|
|
28
|
+
"Schedule" => "schedule",
|
|
29
|
+
"Additional Instructions" => "additional_instructions",
|
|
30
|
+
"Created" => "created_at", "Updated" => "updated_at"
|
|
31
|
+
})
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
desc "create", "Subscribe an agent to a repository"
|
|
36
|
+
option :repo, type: :string, required: true, desc: "Repository ID, owner/repo, or GitHub URL"
|
|
37
|
+
option :agent, type: :string, required: true,
|
|
38
|
+
desc: "Agent ID to subscribe to this repository"
|
|
39
|
+
option :additional_instructions, type: :string,
|
|
40
|
+
desc: "Per-repository additional instructions appended to the shared prompt"
|
|
41
|
+
option :enabled, type: :boolean, default: true,
|
|
42
|
+
desc: "Whether the subscription is active (default: true)"
|
|
43
|
+
def create
|
|
44
|
+
handle_errors do
|
|
45
|
+
data = client.subscriptions.create(**create_attrs)
|
|
46
|
+
output_record(data, fields: { "ID" => "id", "Name" => "name", "Enabled" => "enabled" })
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
desc "update ID", "Update a subscription"
|
|
51
|
+
option :additional_instructions, type: :string,
|
|
52
|
+
desc: "Per-repository additional instructions"
|
|
53
|
+
option :enabled, type: :boolean, desc: "Whether the subscription is active"
|
|
54
|
+
def update(id)
|
|
55
|
+
handle_errors do
|
|
56
|
+
data = client.subscriptions.update(id, **update_attrs)
|
|
57
|
+
output_record(data, fields: { "ID" => "id", "Name" => "name", "Enabled" => "enabled" })
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
desc "delete ID", "Delete a subscription"
|
|
62
|
+
def delete(id)
|
|
63
|
+
handle_errors do
|
|
64
|
+
client.subscriptions.destroy(id)
|
|
65
|
+
puts "Subscription #{id} deleted."
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
desc "toggle ID", "Toggle subscription enabled/disabled"
|
|
70
|
+
def toggle(id)
|
|
71
|
+
handle_errors do
|
|
72
|
+
data = client.subscriptions.toggle(id)
|
|
73
|
+
status = data.dig("data", "enabled") ? "enabled" : "disabled"
|
|
74
|
+
puts "Subscription #{id} #{status}."
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
desc "run-now ID", "Trigger subscription to run immediately"
|
|
79
|
+
map "run-now" => :run_now
|
|
80
|
+
def run_now(id)
|
|
81
|
+
handle_errors do
|
|
82
|
+
client.subscriptions.run_now(id)
|
|
83
|
+
puts "Subscription #{id} triggered."
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
private
|
|
88
|
+
|
|
89
|
+
def create_attrs
|
|
90
|
+
attrs = {
|
|
91
|
+
shared_agent_id: options[:agent],
|
|
92
|
+
github_repository_id: resolve_repo(options[:repo]),
|
|
93
|
+
enabled: options[:enabled]
|
|
94
|
+
}
|
|
95
|
+
attrs[:additional_instructions] = options[:additional_instructions] if options[:additional_instructions]
|
|
96
|
+
attrs
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def update_attrs
|
|
100
|
+
{}.tap do |attrs|
|
|
101
|
+
attrs[:additional_instructions] = options[:additional_instructions] if options[:additional_instructions]
|
|
102
|
+
attrs[:enabled] = options[:enabled] unless options[:enabled].nil?
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "agent_subscriptions"
|
|
4
|
+
|
|
3
5
|
module SchwarmCli
|
|
4
6
|
module Commands
|
|
5
7
|
class Agents < Base
|
|
6
|
-
desc "
|
|
7
|
-
|
|
8
|
+
desc "subscriptions SUBCOMMAND", "Manage repository subscriptions"
|
|
9
|
+
subcommand "subscriptions", AgentSubscriptions
|
|
10
|
+
|
|
11
|
+
desc "list", "List agents"
|
|
8
12
|
option :query, type: :string, desc: "Search by name"
|
|
9
13
|
pagination_options
|
|
10
14
|
def list
|
|
11
15
|
handle_errors do
|
|
12
16
|
data = fetch_paged do |page_params|
|
|
13
|
-
client.agents.list(
|
|
17
|
+
client.agents.list(query: options[:query], **page_params)
|
|
14
18
|
end
|
|
15
|
-
output_list(data, columns: [%w[ID id], %w[NAME name], %w[
|
|
16
|
-
%w[
|
|
19
|
+
output_list(data, columns: [%w[ID id], %w[NAME name], %w[ENABLED enabled],
|
|
20
|
+
%w[SCHEDULE schedule]])
|
|
17
21
|
end
|
|
18
22
|
end
|
|
19
23
|
|
|
@@ -22,26 +26,28 @@ module SchwarmCli
|
|
|
22
26
|
handle_errors do
|
|
23
27
|
data = client.agents.find(id)
|
|
24
28
|
output_record(data, fields: {
|
|
25
|
-
"ID" => "id", "Name" => "name", "
|
|
26
|
-
"
|
|
29
|
+
"ID" => "id", "Name" => "name", "Enabled" => "enabled",
|
|
30
|
+
"Schedule" => "schedule", "Prompt" => "prompt",
|
|
27
31
|
"Created" => "created_at", "Updated" => "updated_at"
|
|
28
32
|
})
|
|
29
33
|
end
|
|
30
34
|
end
|
|
31
35
|
|
|
32
|
-
desc "create", "Create
|
|
36
|
+
desc "create", "Create an agent"
|
|
33
37
|
option :name, type: :string, required: true, desc: "Agent name"
|
|
34
|
-
option :repo, type: :string, required: true, desc: "Repository ID, owner/repo, or GitHub URL"
|
|
35
38
|
option :prompt, type: :string, required: true, desc: "Agent prompt"
|
|
36
39
|
option :schedule, type: :string, desc: "Cron schedule"
|
|
37
40
|
def create
|
|
38
41
|
handle_errors do
|
|
39
|
-
|
|
42
|
+
attrs = { name: options[:name], prompt: options[:prompt] }
|
|
43
|
+
attrs[:schedule] = options[:schedule] if options[:schedule]
|
|
44
|
+
|
|
45
|
+
data = client.agents.create(**attrs)
|
|
40
46
|
output_record(data, fields: { "ID" => "id", "Name" => "name", "Enabled" => "enabled" })
|
|
41
47
|
end
|
|
42
48
|
end
|
|
43
49
|
|
|
44
|
-
desc "update ID", "Update
|
|
50
|
+
desc "update ID", "Update an agent"
|
|
45
51
|
option :name, type: :string, desc: "Agent name"
|
|
46
52
|
option :prompt, type: :string, desc: "Agent prompt"
|
|
47
53
|
option :schedule, type: :string, desc: "Cron schedule"
|
|
@@ -52,7 +58,7 @@ module SchwarmCli
|
|
|
52
58
|
end
|
|
53
59
|
end
|
|
54
60
|
|
|
55
|
-
desc "delete ID", "Delete
|
|
61
|
+
desc "delete ID", "Delete an agent"
|
|
56
62
|
def delete(id)
|
|
57
63
|
handle_errors do
|
|
58
64
|
client.agents.destroy(id)
|
|
@@ -69,26 +75,8 @@ module SchwarmCli
|
|
|
69
75
|
end
|
|
70
76
|
end
|
|
71
77
|
|
|
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
78
|
private
|
|
82
79
|
|
|
83
|
-
def create_attrs
|
|
84
|
-
attrs = {
|
|
85
|
-
name: options[:name], github_repository_id: resolve_repo(options[:repo]),
|
|
86
|
-
prompt: options[:prompt]
|
|
87
|
-
}
|
|
88
|
-
attrs[:schedule] = options[:schedule] if options[:schedule]
|
|
89
|
-
attrs
|
|
90
|
-
end
|
|
91
|
-
|
|
92
80
|
def update_attrs
|
|
93
81
|
{}.tap do |attrs|
|
|
94
82
|
attrs[:name] = options[:name] if options[:name]
|
|
@@ -9,6 +9,8 @@ module SchwarmCli
|
|
|
9
9
|
class_option :url, type: :string, desc: "Schwarm server URL (overrides config)"
|
|
10
10
|
class_option :token, type: :string, desc: "API key (overrides config)"
|
|
11
11
|
|
|
12
|
+
def self.exit_on_failure? = true
|
|
13
|
+
|
|
12
14
|
DEFAULT_LIST_LIMIT = 20
|
|
13
15
|
|
|
14
16
|
# Declares --limit, --page, --all options for the next method.
|
|
@@ -87,12 +89,12 @@ module SchwarmCli
|
|
|
87
89
|
yield
|
|
88
90
|
rescue Faraday::UnauthorizedError
|
|
89
91
|
abort "Error: Unauthorized. Check your API key or run `schwarm configure`."
|
|
90
|
-
rescue Faraday::ResourceNotFound
|
|
91
|
-
abort "Error: Not found."
|
|
92
|
+
rescue Faraday::ResourceNotFound => e
|
|
93
|
+
abort "Error: #{parse_error_body(e, fallback: 'Not found.')}"
|
|
92
94
|
rescue Faraday::UnprocessableEntityError => e
|
|
93
|
-
abort "Error: #{parse_error_body(e)}"
|
|
95
|
+
abort "Error: #{parse_error_body(e, fallback: 'Validation failed')}"
|
|
94
96
|
rescue Faraday::ClientError => e
|
|
95
|
-
abort "Error: #{e.message}"
|
|
97
|
+
abort "Error: #{parse_error_body(e, fallback: e.message)}"
|
|
96
98
|
rescue Faraday::ServerError
|
|
97
99
|
abort "Error: Server error. Try again later."
|
|
98
100
|
rescue Faraday::ConnectionFailed
|
|
@@ -101,14 +103,14 @@ module SchwarmCli
|
|
|
101
103
|
abort "Error: Request timed out."
|
|
102
104
|
end
|
|
103
105
|
|
|
104
|
-
def parse_error_body(error)
|
|
106
|
+
def parse_error_body(error, fallback:)
|
|
105
107
|
body = error.response&.dig(:body)
|
|
106
|
-
return
|
|
108
|
+
return fallback unless body.is_a?(String) && !body.empty?
|
|
107
109
|
|
|
108
110
|
parsed = JSON.parse(body)
|
|
109
|
-
parsed.dig("error", "message") ||
|
|
111
|
+
parsed.dig("error", "message") || fallback
|
|
110
112
|
rescue JSON::ParserError
|
|
111
|
-
|
|
113
|
+
fallback
|
|
112
114
|
end
|
|
113
115
|
end
|
|
114
116
|
end
|
|
@@ -7,7 +7,6 @@ require_relative "templates"
|
|
|
7
7
|
require_relative "skills"
|
|
8
8
|
require_relative "skill_files"
|
|
9
9
|
require_relative "agents"
|
|
10
|
-
require_relative "shared_agents"
|
|
11
10
|
require_relative "recurring"
|
|
12
11
|
require_relative "secrets"
|
|
13
12
|
require_relative "sessions"
|
|
@@ -17,6 +16,8 @@ require_relative "configure"
|
|
|
17
16
|
module SchwarmCli
|
|
18
17
|
module Commands
|
|
19
18
|
class Main < Thor
|
|
19
|
+
def self.exit_on_failure? = true
|
|
20
|
+
|
|
20
21
|
desc "tasks SUBCOMMAND", "Manage tasks"
|
|
21
22
|
subcommand "tasks", Tasks
|
|
22
23
|
|
|
@@ -30,14 +31,11 @@ module SchwarmCli
|
|
|
30
31
|
subcommand "skills", SkillsCmd
|
|
31
32
|
|
|
32
33
|
desc "skill-files SUBCOMMAND", "Manage skill files"
|
|
33
|
-
subcommand "
|
|
34
|
+
subcommand "skill_files", SkillFilesCmd
|
|
34
35
|
|
|
35
|
-
desc "agents SUBCOMMAND", "Manage repository
|
|
36
|
+
desc "agents SUBCOMMAND", "Manage agents and their repository subscriptions"
|
|
36
37
|
subcommand "agents", Agents
|
|
37
38
|
|
|
38
|
-
desc "shared-agents SUBCOMMAND", "Manage shared agents"
|
|
39
|
-
subcommand "shared-agents", SharedAgentsCmd
|
|
40
|
-
|
|
41
39
|
desc "recurring SUBCOMMAND", "Manage recurring tasks"
|
|
42
40
|
subcommand "recurring", Recurring
|
|
43
41
|
|
|
@@ -48,7 +46,7 @@ module SchwarmCli
|
|
|
48
46
|
subcommand "sessions", Sessions
|
|
49
47
|
|
|
50
48
|
desc "repo-skills SUBCOMMAND", "Manage repository-skill associations"
|
|
51
|
-
subcommand "
|
|
49
|
+
subcommand "repo_skills", RepoSkills
|
|
52
50
|
|
|
53
51
|
desc "configure", "Set up Schwarm CLI configuration"
|
|
54
52
|
subcommand "configure", Configure
|
|
@@ -13,7 +13,7 @@ module SchwarmCli
|
|
|
13
13
|
client.recurring.list(repository_id: resolve_repo(options[:repo]), query: options[:query], **page_params)
|
|
14
14
|
end
|
|
15
15
|
output_list(data, columns: [%w[ID id], %w[NAME name], %w[REPO github_repository_name],
|
|
16
|
-
%w[ENABLED enabled], %w[SCHEDULE
|
|
16
|
+
%w[ENABLED enabled], %w[SCHEDULE cron_expression]])
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
|
|
@@ -23,7 +23,7 @@ module SchwarmCli
|
|
|
23
23
|
data = client.recurring.find(id)
|
|
24
24
|
output_record(data, fields: {
|
|
25
25
|
"ID" => "id", "Name" => "name", "Repository" => "github_repository_id",
|
|
26
|
-
"Enabled" => "enabled", "Schedule" => "
|
|
26
|
+
"Enabled" => "enabled", "Schedule" => "cron_expression", "Prompt" => "prompt",
|
|
27
27
|
"Created" => "created_at", "Updated" => "updated_at"
|
|
28
28
|
})
|
|
29
29
|
end
|
|
@@ -38,11 +38,11 @@ module SchwarmCli
|
|
|
38
38
|
handle_errors do
|
|
39
39
|
attrs = {
|
|
40
40
|
name: options[:name], github_repository_id: resolve_repo(options[:repo]),
|
|
41
|
-
prompt: options[:prompt],
|
|
41
|
+
prompt: options[:prompt], cron_expression: options[:schedule]
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
data = client.recurring.create(**attrs)
|
|
45
|
-
output_record(data, fields: { "ID" => "id", "Name" => "name", "Schedule" => "
|
|
45
|
+
output_record(data, fields: { "ID" => "id", "Name" => "name", "Schedule" => "cron_expression" })
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
|
|
@@ -53,7 +53,7 @@ module SchwarmCli
|
|
|
53
53
|
def update(id)
|
|
54
54
|
handle_errors do
|
|
55
55
|
data = client.recurring.update(id, **update_attrs)
|
|
56
|
-
output_record(data, fields: { "ID" => "id", "Name" => "name", "Schedule" => "
|
|
56
|
+
output_record(data, fields: { "ID" => "id", "Name" => "name", "Schedule" => "cron_expression" })
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
59
|
|
|
@@ -80,7 +80,7 @@ module SchwarmCli
|
|
|
80
80
|
{}.tap do |attrs|
|
|
81
81
|
attrs[:name] = options[:name] if options[:name]
|
|
82
82
|
attrs[:prompt] = options[:prompt] if options[:prompt]
|
|
83
|
-
attrs[:
|
|
83
|
+
attrs[:cron_expression] = options[:schedule] if options[:schedule]
|
|
84
84
|
end
|
|
85
85
|
end
|
|
86
86
|
end
|
|
@@ -64,7 +64,11 @@ module SchwarmCli
|
|
|
64
64
|
def pause(id)
|
|
65
65
|
handle_errors do
|
|
66
66
|
data = client.repositories.pause(id)
|
|
67
|
-
|
|
67
|
+
if options[:json]
|
|
68
|
+
output_record(data, fields: {})
|
|
69
|
+
else
|
|
70
|
+
puts "Repository #{id} paused (#{data.dig('data', 'status')})."
|
|
71
|
+
end
|
|
68
72
|
end
|
|
69
73
|
end
|
|
70
74
|
|
|
@@ -72,7 +76,11 @@ module SchwarmCli
|
|
|
72
76
|
def resume(id)
|
|
73
77
|
handle_errors do
|
|
74
78
|
data = client.repositories.resume(id)
|
|
75
|
-
|
|
79
|
+
if options[:json]
|
|
80
|
+
output_record(data, fields: {})
|
|
81
|
+
else
|
|
82
|
+
puts "Repository #{id} resumed (#{data.dig('data', 'status')})."
|
|
83
|
+
end
|
|
76
84
|
end
|
|
77
85
|
end
|
|
78
86
|
|
|
@@ -11,50 +11,46 @@ module SchwarmCli
|
|
|
11
11
|
data = fetch_paged do |page_params|
|
|
12
12
|
client.secrets.list(repository_id: resolve_repo(options[:repo]), **page_params)
|
|
13
13
|
end
|
|
14
|
-
output_list(data, columns: [%w[ID id], %w[
|
|
15
|
-
%w[PATH path]])
|
|
14
|
+
output_list(data, columns: [%w[ID id], %w[REPO github_repository_name], %w[PATH path]])
|
|
16
15
|
end
|
|
17
16
|
end
|
|
18
17
|
|
|
19
|
-
desc "show ID", "Show secret file details"
|
|
18
|
+
desc "show ID", "Show secret file details (metadata only — content is never returned)"
|
|
20
19
|
def show(id)
|
|
21
20
|
handle_errors do
|
|
22
21
|
data = client.secrets.find(id)
|
|
23
22
|
output_record(data, fields: {
|
|
24
|
-
"ID" => "id", "
|
|
23
|
+
"ID" => "id", "Repository" => "github_repository_name",
|
|
25
24
|
"Path" => "path", "Created" => "created_at", "Updated" => "updated_at"
|
|
26
25
|
})
|
|
27
26
|
end
|
|
28
27
|
end
|
|
29
28
|
|
|
30
29
|
desc "create", "Create a secret file"
|
|
31
|
-
option :name, type: :string, required: true, desc: "Secret name"
|
|
32
30
|
option :repo, type: :string, required: true, desc: "Repository ID, owner/repo, or GitHub URL"
|
|
33
31
|
option :path, type: :string, required: true, desc: "File path in workspace"
|
|
34
|
-
option :content, type: :string, desc: "Secret content"
|
|
35
|
-
option :file, type: :string, desc: "Read content from file"
|
|
32
|
+
option :content, type: :string, desc: "Secret content (mutually exclusive with --file)"
|
|
33
|
+
option :file, type: :string, desc: "Read content from file (mutually exclusive with --content)"
|
|
36
34
|
def create
|
|
37
35
|
handle_errors do
|
|
38
|
-
content = read_content
|
|
39
36
|
attrs = {
|
|
40
|
-
|
|
41
|
-
path: options[:path], content:
|
|
37
|
+
github_repository_id: resolve_repo(options[:repo]),
|
|
38
|
+
path: options[:path], content: read_content(required: true)
|
|
42
39
|
}
|
|
43
40
|
|
|
44
41
|
data = client.secrets.create(**attrs)
|
|
45
|
-
output_record(data, fields: { "ID" => "id", "
|
|
42
|
+
output_record(data, fields: { "ID" => "id", "Path" => "path" })
|
|
46
43
|
end
|
|
47
44
|
end
|
|
48
45
|
|
|
49
46
|
desc "update ID", "Update a secret file"
|
|
50
|
-
option :name, type: :string, desc: "Secret name"
|
|
51
47
|
option :path, type: :string, desc: "File path in workspace"
|
|
52
|
-
option :content, type: :string, desc: "Secret content"
|
|
53
|
-
option :file, type: :string, desc: "Read content from file"
|
|
48
|
+
option :content, type: :string, desc: "Secret content (mutually exclusive with --file)"
|
|
49
|
+
option :file, type: :string, desc: "Read content from file (mutually exclusive with --content)"
|
|
54
50
|
def update(id)
|
|
55
51
|
handle_errors do
|
|
56
52
|
data = client.secrets.update(id, **update_attrs)
|
|
57
|
-
output_record(data, fields: { "ID" => "id", "
|
|
53
|
+
output_record(data, fields: { "ID" => "id", "Path" => "path" })
|
|
58
54
|
end
|
|
59
55
|
end
|
|
60
56
|
|
|
@@ -69,19 +65,24 @@ module SchwarmCli
|
|
|
69
65
|
private
|
|
70
66
|
|
|
71
67
|
def update_attrs
|
|
72
|
-
{
|
|
73
|
-
|
|
68
|
+
{ path: options[:path] }.compact.tap do |attrs|
|
|
69
|
+
content = read_content(required: false)
|
|
70
|
+
attrs[:content] = content if content
|
|
74
71
|
end
|
|
75
72
|
end
|
|
76
73
|
|
|
77
|
-
def read_content
|
|
78
|
-
if options[:file]
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
74
|
+
def read_content(required:)
|
|
75
|
+
abort "Error: --content and --file are mutually exclusive." if options[:content] && options[:file]
|
|
76
|
+
return options[:content] if options[:content]
|
|
77
|
+
return read_file(options[:file]) if options[:file]
|
|
78
|
+
|
|
79
|
+
abort "Error: one of --content or --file is required." if required
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def read_file(path)
|
|
83
|
+
expanded = File.expand_path(path)
|
|
84
|
+
abort "Error: File not found: #{expanded}" unless File.exist?(expanded)
|
|
85
|
+
File.read(expanded)
|
|
85
86
|
end
|
|
86
87
|
end
|
|
87
88
|
end
|
|
@@ -27,7 +27,8 @@ module SchwarmCli
|
|
|
27
27
|
data = client.sessions.find(id)
|
|
28
28
|
output_record(data, fields: {
|
|
29
29
|
"ID" => "id", "Source" => "source", "Status" => "status",
|
|
30
|
-
"
|
|
30
|
+
"External ID" => "external_id", "Model" => "model_id",
|
|
31
|
+
"Error" => "error_message",
|
|
31
32
|
"Created" => "created_at", "Updated" => "updated_at"
|
|
32
33
|
})
|
|
33
34
|
end
|
|
@@ -21,19 +21,24 @@ module SchwarmCli
|
|
|
21
21
|
data = client.skills.find(id)
|
|
22
22
|
output_record(data, fields: {
|
|
23
23
|
"ID" => "id", "Name" => "name", "Description" => "description",
|
|
24
|
-
"
|
|
24
|
+
"Instructions" => "instructions", "Global" => "global",
|
|
25
|
+
"Created" => "created_at"
|
|
25
26
|
})
|
|
26
27
|
end
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
desc "create", "Create a skill"
|
|
30
31
|
option :name, type: :string, required: true, desc: "Skill name"
|
|
31
|
-
option :description, type: :string, desc: "Skill description"
|
|
32
|
+
option :description, type: :string, required: true, desc: "Skill description"
|
|
33
|
+
option :instructions, type: :string, desc: "Skill instructions (inline)"
|
|
34
|
+
option :instructions_file, type: :string, desc: "Read instructions from file"
|
|
32
35
|
option :global, type: :boolean, default: false, desc: "Make skill global"
|
|
33
36
|
def create
|
|
34
37
|
handle_errors do
|
|
35
|
-
attrs = {
|
|
36
|
-
|
|
38
|
+
attrs = {
|
|
39
|
+
name: options[:name], description: options[:description],
|
|
40
|
+
instructions: read_instructions, global: options[:global]
|
|
41
|
+
}
|
|
37
42
|
|
|
38
43
|
data = client.skills.create(**attrs)
|
|
39
44
|
output_record(data, fields: { "ID" => "id", "Name" => "name", "Global" => "global" })
|
|
@@ -43,6 +48,8 @@ module SchwarmCli
|
|
|
43
48
|
desc "update ID", "Update a skill"
|
|
44
49
|
option :name, type: :string, desc: "Skill name"
|
|
45
50
|
option :description, type: :string, desc: "Skill description"
|
|
51
|
+
option :instructions, type: :string, desc: "Skill instructions (inline)"
|
|
52
|
+
option :instructions_file, type: :string, desc: "Read instructions from file"
|
|
46
53
|
option :global, type: :boolean, desc: "Make skill global"
|
|
47
54
|
def update(id)
|
|
48
55
|
handle_errors do
|
|
@@ -62,10 +69,24 @@ module SchwarmCli
|
|
|
62
69
|
private
|
|
63
70
|
|
|
64
71
|
def update_attrs
|
|
72
|
+
instructions = read_instructions
|
|
65
73
|
{ name: options[:name], description: options[:description] }.compact.tap do |attrs|
|
|
74
|
+
attrs[:instructions] = instructions if instructions
|
|
66
75
|
attrs[:global] = options[:global] unless options[:global].nil?
|
|
67
76
|
end
|
|
68
77
|
end
|
|
78
|
+
|
|
79
|
+
def read_instructions
|
|
80
|
+
if options[:instructions] && options[:instructions_file]
|
|
81
|
+
abort "Error: --instructions and --instructions-file are mutually exclusive."
|
|
82
|
+
elsif options[:instructions_file]
|
|
83
|
+
file_path = File.expand_path(options[:instructions_file])
|
|
84
|
+
abort "Error: File not found: #{file_path}" unless File.exist?(file_path)
|
|
85
|
+
File.read(file_path)
|
|
86
|
+
else
|
|
87
|
+
options[:instructions]
|
|
88
|
+
end
|
|
89
|
+
end
|
|
69
90
|
end
|
|
70
91
|
end
|
|
71
92
|
end
|
|
@@ -20,7 +20,8 @@ module SchwarmCli
|
|
|
20
20
|
handle_errors do
|
|
21
21
|
data = client.templates.find(id)
|
|
22
22
|
output_record(data, fields: {
|
|
23
|
-
"ID" => "id", "Name" => "name", "
|
|
23
|
+
"ID" => "id", "Name" => "name", "Description" => "description",
|
|
24
|
+
"Prompt" => "prompt_prefix", "Created" => "created_at"
|
|
24
25
|
})
|
|
25
26
|
end
|
|
26
27
|
end
|
|
@@ -28,9 +29,13 @@ module SchwarmCli
|
|
|
28
29
|
desc "create", "Create a task template"
|
|
29
30
|
option :name, type: :string, required: true, desc: "Template name"
|
|
30
31
|
option :prompt, type: :string, required: true, desc: "Template prompt"
|
|
32
|
+
option :description, type: :string, desc: "Template description"
|
|
31
33
|
def create
|
|
32
34
|
handle_errors do
|
|
33
|
-
|
|
35
|
+
attrs = { name: options[:name], prompt_prefix: options[:prompt] }
|
|
36
|
+
attrs[:description] = options[:description] if options[:description]
|
|
37
|
+
|
|
38
|
+
data = client.templates.create(**attrs)
|
|
34
39
|
output_record(data, fields: { "ID" => "id", "Name" => "name" })
|
|
35
40
|
end
|
|
36
41
|
end
|
|
@@ -38,13 +43,10 @@ module SchwarmCli
|
|
|
38
43
|
desc "update ID", "Update a task template"
|
|
39
44
|
option :name, type: :string, desc: "Template name"
|
|
40
45
|
option :prompt, type: :string, desc: "Template prompt"
|
|
46
|
+
option :description, type: :string, desc: "Template description"
|
|
41
47
|
def update(id)
|
|
42
48
|
handle_errors do
|
|
43
|
-
|
|
44
|
-
attrs[:name] = options[:name] if options[:name]
|
|
45
|
-
attrs[:prompt] = options[:prompt] if options[:prompt]
|
|
46
|
-
|
|
47
|
-
data = client.templates.update(id, **attrs)
|
|
49
|
+
data = client.templates.update(id, **update_attrs)
|
|
48
50
|
output_record(data, fields: { "ID" => "id", "Name" => "name" })
|
|
49
51
|
end
|
|
50
52
|
end
|
|
@@ -56,6 +58,16 @@ module SchwarmCli
|
|
|
56
58
|
puts "Template #{id} deleted."
|
|
57
59
|
end
|
|
58
60
|
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def update_attrs
|
|
65
|
+
{}.tap do |attrs|
|
|
66
|
+
attrs[:name] = options[:name] if options[:name]
|
|
67
|
+
attrs[:prompt_prefix] = options[:prompt] if options[:prompt]
|
|
68
|
+
attrs[:description] = options[:description] if options[:description]
|
|
69
|
+
end
|
|
70
|
+
end
|
|
59
71
|
end
|
|
60
72
|
end
|
|
61
73
|
end
|
data/lib/schwarm_cli/version.rb
CHANGED
data/schwarm-skill.md
CHANGED
|
@@ -266,13 +266,18 @@ for tasks in a repository.
|
|
|
266
266
|
```bash
|
|
267
267
|
schwarm repo-skills create --repo <REPO_ID> --skill <SKILL_ID>
|
|
268
268
|
```
|
|
269
|
-
3. Create
|
|
269
|
+
3. Create an agent (a reusable definition with a name, prompt, and optional schedule):
|
|
270
270
|
```bash
|
|
271
|
-
schwarm agents create --
|
|
271
|
+
schwarm agents create --name "Code style" --prompt "Always follow the project's eslint config"
|
|
272
272
|
```
|
|
273
|
-
4.
|
|
273
|
+
4. Subscribe an agent to a repository so it runs against that repo:
|
|
274
274
|
```bash
|
|
275
|
-
schwarm agents
|
|
275
|
+
schwarm agents subscriptions create --repo <REPO_ID> --agent <AGENT_ID>
|
|
276
|
+
```
|
|
277
|
+
5. List subscriptions for a repo, or all agents:
|
|
278
|
+
```bash
|
|
279
|
+
schwarm agents subscriptions list --repo <REPO_ID>
|
|
280
|
+
schwarm agents list
|
|
276
281
|
```
|
|
277
282
|
|
|
278
283
|
## Tips
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: schwarm-cli
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vincent Garrigues
|
|
@@ -103,6 +103,7 @@ files:
|
|
|
103
103
|
- lib/schwarm_cli/client/task_templates.rb
|
|
104
104
|
- lib/schwarm_cli/client/tasks.rb
|
|
105
105
|
- lib/schwarm_cli/client/user_messages.rb
|
|
106
|
+
- lib/schwarm_cli/commands/agent_subscriptions.rb
|
|
106
107
|
- lib/schwarm_cli/commands/agents.rb
|
|
107
108
|
- lib/schwarm_cli/commands/base.rb
|
|
108
109
|
- lib/schwarm_cli/commands/configure.rb
|
|
@@ -112,7 +113,6 @@ files:
|
|
|
112
113
|
- lib/schwarm_cli/commands/repos.rb
|
|
113
114
|
- lib/schwarm_cli/commands/secrets.rb
|
|
114
115
|
- lib/schwarm_cli/commands/sessions.rb
|
|
115
|
-
- lib/schwarm_cli/commands/shared_agents.rb
|
|
116
116
|
- lib/schwarm_cli/commands/skill_files.rb
|
|
117
117
|
- lib/schwarm_cli/commands/skills.rb
|
|
118
118
|
- lib/schwarm_cli/commands/tasks.rb
|
|
@@ -1,84 +0,0 @@
|
|
|
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
|
-
pagination_options
|
|
9
|
-
def list
|
|
10
|
-
handle_errors do
|
|
11
|
-
data = fetch_paged do |page_params|
|
|
12
|
-
client.shared_agents.list(query: options[:query], **page_params)
|
|
13
|
-
end
|
|
14
|
-
output_list(data, columns: [%w[ID id], %w[NAME name], %w[ENABLED enabled],
|
|
15
|
-
%w[SCHEDULE schedule]])
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
desc "show ID", "Show shared agent details"
|
|
20
|
-
def show(id)
|
|
21
|
-
handle_errors do
|
|
22
|
-
data = client.shared_agents.find(id)
|
|
23
|
-
output_record(data, fields: {
|
|
24
|
-
"ID" => "id", "Name" => "name", "Enabled" => "enabled",
|
|
25
|
-
"Schedule" => "schedule", "Prompt" => "prompt",
|
|
26
|
-
"Created" => "created_at", "Updated" => "updated_at"
|
|
27
|
-
})
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
desc "create", "Create a shared agent"
|
|
32
|
-
option :name, type: :string, required: true, desc: "Agent name"
|
|
33
|
-
option :prompt, type: :string, required: true, desc: "Agent prompt"
|
|
34
|
-
option :schedule, type: :string, desc: "Cron schedule"
|
|
35
|
-
def create
|
|
36
|
-
handle_errors do
|
|
37
|
-
attrs = { name: options[:name], prompt: options[:prompt] }
|
|
38
|
-
attrs[:schedule] = options[:schedule] if options[:schedule]
|
|
39
|
-
|
|
40
|
-
data = client.shared_agents.create(**attrs)
|
|
41
|
-
output_record(data, fields: { "ID" => "id", "Name" => "name", "Enabled" => "enabled" })
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
desc "update ID", "Update a shared agent"
|
|
46
|
-
option :name, type: :string, desc: "Agent name"
|
|
47
|
-
option :prompt, type: :string, desc: "Agent prompt"
|
|
48
|
-
option :schedule, type: :string, desc: "Cron schedule"
|
|
49
|
-
def update(id)
|
|
50
|
-
handle_errors do
|
|
51
|
-
data = client.shared_agents.update(id, **update_attrs)
|
|
52
|
-
output_record(data, fields: { "ID" => "id", "Name" => "name", "Enabled" => "enabled" })
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
desc "delete ID", "Delete a shared agent"
|
|
57
|
-
def delete(id)
|
|
58
|
-
handle_errors do
|
|
59
|
-
client.shared_agents.destroy(id)
|
|
60
|
-
puts "Shared agent #{id} deleted."
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
desc "toggle ID", "Toggle shared agent enabled/disabled"
|
|
65
|
-
def toggle(id)
|
|
66
|
-
handle_errors do
|
|
67
|
-
data = client.shared_agents.toggle(id)
|
|
68
|
-
status = data.dig("data", "enabled") ? "enabled" : "disabled"
|
|
69
|
-
puts "Shared agent #{id} #{status}."
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
private
|
|
74
|
-
|
|
75
|
-
def update_attrs
|
|
76
|
-
{}.tap do |attrs|
|
|
77
|
-
attrs[:name] = options[:name] if options[:name]
|
|
78
|
-
attrs[:prompt] = options[:prompt] if options[:prompt]
|
|
79
|
-
attrs[:schedule] = options[:schedule] if options[:schedule]
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
end
|