schwarm-cli 0.1.3 → 0.1.5
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/commands/agents.rb +13 -7
- data/lib/schwarm_cli/commands/base.rb +7 -0
- data/lib/schwarm_cli/commands/recurring.rb +4 -4
- data/lib/schwarm_cli/commands/repo_skills.rb +6 -4
- data/lib/schwarm_cli/commands/secrets.rb +7 -4
- data/lib/schwarm_cli/commands/tasks.rb +12 -25
- data/lib/schwarm_cli/hands_off_task.rb +8 -19
- data/lib/schwarm_cli/repository_resolver.rb +65 -0
- data/lib/schwarm_cli/version.rb +1 -1
- data/lib/schwarm_cli.rb +1 -0
- data/schwarm-skill.md +26 -3
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f86723cf9675bb0de813b11efa16be17bd2b8bfa74bd9af1203130cdf7fda0f0
|
|
4
|
+
data.tar.gz: 479a9e83426d1fb675b79dd5780b14264d7a6c8454ee30404c104743aed30fdd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9e473284f4c066af2f5ed3a77cc365448574acd73a55e1f72e5d2eb94d1b11db5a95fc4fdaf23c498ecb721ef0f2f596ff753c1c869726446a66d6ae622cf167
|
|
7
|
+
data.tar.gz: b3d2498b0dcea13e9ed75ea1ee865fdf25658a31a5552059cfb617efcead48600f46008fbd4f580766250daa6b99f38619412a4c4cfa32175f6736b7f45e7c3e
|
|
@@ -4,13 +4,13 @@ module SchwarmCli
|
|
|
4
4
|
module Commands
|
|
5
5
|
class Agents < Base
|
|
6
6
|
desc "list", "List repository agents"
|
|
7
|
-
option :repo, type: :string, desc: "Filter by repository ID"
|
|
7
|
+
option :repo, type: :string, desc: "Filter by repository ID, owner/repo, or GitHub URL"
|
|
8
8
|
option :query, type: :string, desc: "Search by name"
|
|
9
9
|
pagination_options
|
|
10
10
|
def list
|
|
11
11
|
handle_errors do
|
|
12
12
|
data = fetch_paged do |page_params|
|
|
13
|
-
client.agents.list(repository_id: options[:repo], query: options[:query], **page_params)
|
|
13
|
+
client.agents.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
16
|
%w[ENABLED enabled], %w[SCHEDULE schedule]])
|
|
@@ -31,15 +31,12 @@ module SchwarmCli
|
|
|
31
31
|
|
|
32
32
|
desc "create", "Create a repository agent"
|
|
33
33
|
option :name, type: :string, required: true, desc: "Agent name"
|
|
34
|
-
option :repo, type: :string, required: true, desc: "Repository ID"
|
|
34
|
+
option :repo, type: :string, required: true, desc: "Repository ID, owner/repo, or GitHub URL"
|
|
35
35
|
option :prompt, type: :string, required: true, desc: "Agent prompt"
|
|
36
36
|
option :schedule, type: :string, desc: "Cron schedule"
|
|
37
37
|
def create
|
|
38
38
|
handle_errors do
|
|
39
|
-
|
|
40
|
-
attrs[:schedule] = options[:schedule] if options[:schedule]
|
|
41
|
-
|
|
42
|
-
data = client.agents.create(**attrs)
|
|
39
|
+
data = client.agents.create(**create_attrs)
|
|
43
40
|
output_record(data, fields: { "ID" => "id", "Name" => "name", "Enabled" => "enabled" })
|
|
44
41
|
end
|
|
45
42
|
end
|
|
@@ -83,6 +80,15 @@ module SchwarmCli
|
|
|
83
80
|
|
|
84
81
|
private
|
|
85
82
|
|
|
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
|
+
|
|
86
92
|
def update_attrs
|
|
87
93
|
{}.tap do |attrs|
|
|
88
94
|
attrs[:name] = options[:name] if options[:name]
|
|
@@ -25,6 +25,13 @@ module SchwarmCli
|
|
|
25
25
|
@client ||= SchwarmCli::Client.new(url: options[:url], api_key: options[:token])
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
# Resolves --repo input (ID, owner/repo, or GitHub URL) to a schwarm repo ID.
|
|
29
|
+
def resolve_repo(ref)
|
|
30
|
+
SchwarmCli::RepositoryResolver.new(client: client).resolve(ref)
|
|
31
|
+
rescue SchwarmCli::RepositoryResolver::ResolutionError => e
|
|
32
|
+
abort "Error: #{e.message}"
|
|
33
|
+
end
|
|
34
|
+
|
|
28
35
|
def output_list(data, columns:)
|
|
29
36
|
if options[:json]
|
|
30
37
|
Formatters::Json.format(data)
|
|
@@ -4,13 +4,13 @@ module SchwarmCli
|
|
|
4
4
|
module Commands
|
|
5
5
|
class Recurring < Base
|
|
6
6
|
desc "list", "List recurring tasks"
|
|
7
|
-
option :repo, type: :string, desc: "Filter by repository ID"
|
|
7
|
+
option :repo, type: :string, desc: "Filter by repository ID, owner/repo, or GitHub URL"
|
|
8
8
|
option :query, type: :string, desc: "Search by name"
|
|
9
9
|
pagination_options
|
|
10
10
|
def list
|
|
11
11
|
handle_errors do
|
|
12
12
|
data = fetch_paged do |page_params|
|
|
13
|
-
client.recurring.list(repository_id: options[:repo], query: options[:query], **page_params)
|
|
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
16
|
%w[ENABLED enabled], %w[SCHEDULE schedule]])
|
|
@@ -31,13 +31,13 @@ module SchwarmCli
|
|
|
31
31
|
|
|
32
32
|
desc "create", "Create a recurring task"
|
|
33
33
|
option :name, type: :string, required: true, desc: "Task name"
|
|
34
|
-
option :repo, type: :string, required: true, desc: "Repository ID"
|
|
34
|
+
option :repo, type: :string, required: true, desc: "Repository ID, owner/repo, or GitHub URL"
|
|
35
35
|
option :prompt, type: :string, required: true, desc: "Task prompt"
|
|
36
36
|
option :schedule, type: :string, required: true, desc: "Cron schedule"
|
|
37
37
|
def create
|
|
38
38
|
handle_errors do
|
|
39
39
|
attrs = {
|
|
40
|
-
name: options[:name], github_repository_id: options[:repo],
|
|
40
|
+
name: options[:name], github_repository_id: resolve_repo(options[:repo]),
|
|
41
41
|
prompt: options[:prompt], schedule: options[:schedule]
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -4,13 +4,15 @@ module SchwarmCli
|
|
|
4
4
|
module Commands
|
|
5
5
|
class RepoSkills < Base
|
|
6
6
|
desc "list", "List repository-skill associations"
|
|
7
|
-
option :repo, type: :string, desc: "Filter by repository ID"
|
|
7
|
+
option :repo, type: :string, desc: "Filter by repository ID, owner/repo, or GitHub URL"
|
|
8
8
|
option :skill, type: :string, desc: "Filter by skill ID"
|
|
9
9
|
pagination_options
|
|
10
10
|
def list
|
|
11
11
|
handle_errors do
|
|
12
12
|
data = fetch_paged do |page_params|
|
|
13
|
-
client.repo_skills.list(
|
|
13
|
+
client.repo_skills.list(
|
|
14
|
+
repository_id: resolve_repo(options[:repo]), skill_id: options[:skill], **page_params
|
|
15
|
+
)
|
|
14
16
|
end
|
|
15
17
|
output_list(data, columns: [%w[ID id], %w[REPO github_repository_name],
|
|
16
18
|
%w[SKILL skill_name]])
|
|
@@ -29,12 +31,12 @@ module SchwarmCli
|
|
|
29
31
|
end
|
|
30
32
|
|
|
31
33
|
desc "create", "Associate a skill with a repository"
|
|
32
|
-
option :repo, type: :string, required: true, desc: "Repository ID"
|
|
34
|
+
option :repo, type: :string, required: true, desc: "Repository ID, owner/repo, or GitHub URL"
|
|
33
35
|
option :skill, type: :string, required: true, desc: "Skill ID"
|
|
34
36
|
def create
|
|
35
37
|
handle_errors do
|
|
36
38
|
data = client.repo_skills.create(
|
|
37
|
-
github_repository_id: options[:repo], skill_id: options[:skill]
|
|
39
|
+
github_repository_id: resolve_repo(options[:repo]), skill_id: options[:skill]
|
|
38
40
|
)
|
|
39
41
|
output_record(data, fields: { "ID" => "id", "Repository" => "github_repository_id",
|
|
40
42
|
"Skill" => "skill_id" })
|
|
@@ -4,12 +4,12 @@ module SchwarmCli
|
|
|
4
4
|
module Commands
|
|
5
5
|
class Secrets < Base
|
|
6
6
|
desc "list", "List secret files"
|
|
7
|
-
option :repo, type: :string, desc: "Filter by repository ID"
|
|
7
|
+
option :repo, type: :string, desc: "Filter by repository ID, owner/repo, or GitHub URL"
|
|
8
8
|
pagination_options
|
|
9
9
|
def list
|
|
10
10
|
handle_errors do
|
|
11
11
|
data = fetch_paged do |page_params|
|
|
12
|
-
client.secrets.list(repository_id: options[:repo], **page_params)
|
|
12
|
+
client.secrets.list(repository_id: resolve_repo(options[:repo]), **page_params)
|
|
13
13
|
end
|
|
14
14
|
output_list(data, columns: [%w[ID id], %w[NAME name], %w[REPO github_repository_name],
|
|
15
15
|
%w[PATH path]])
|
|
@@ -29,14 +29,17 @@ module SchwarmCli
|
|
|
29
29
|
|
|
30
30
|
desc "create", "Create a secret file"
|
|
31
31
|
option :name, type: :string, required: true, desc: "Secret name"
|
|
32
|
-
option :repo, type: :string, required: true, desc: "Repository ID"
|
|
32
|
+
option :repo, type: :string, required: true, desc: "Repository ID, owner/repo, or GitHub URL"
|
|
33
33
|
option :path, type: :string, required: true, desc: "File path in workspace"
|
|
34
34
|
option :content, type: :string, desc: "Secret content"
|
|
35
35
|
option :file, type: :string, desc: "Read content from file"
|
|
36
36
|
def create
|
|
37
37
|
handle_errors do
|
|
38
38
|
content = read_content
|
|
39
|
-
attrs = {
|
|
39
|
+
attrs = {
|
|
40
|
+
name: options[:name], github_repository_id: resolve_repo(options[:repo]),
|
|
41
|
+
path: options[:path], content:
|
|
42
|
+
}
|
|
40
43
|
|
|
41
44
|
data = client.secrets.create(**attrs)
|
|
42
45
|
output_record(data, fields: { "ID" => "id", "Name" => "name", "Path" => "path" })
|
|
@@ -5,7 +5,7 @@ module SchwarmCli
|
|
|
5
5
|
class Tasks < Base
|
|
6
6
|
desc "list", "List tasks (excludes archived by default)"
|
|
7
7
|
option :status, type: :string, desc: "Filter by status"
|
|
8
|
-
option :repo, type: :string, desc: "Filter by repository ID"
|
|
8
|
+
option :repo, type: :string, desc: "Filter by repository ID, owner/repo, or GitHub URL"
|
|
9
9
|
option :query, type: :string, desc: "Search by name"
|
|
10
10
|
pagination_options
|
|
11
11
|
def list
|
|
@@ -32,8 +32,7 @@ module SchwarmCli
|
|
|
32
32
|
desc "create", "Create a new task"
|
|
33
33
|
option :name, type: :string, required: true, desc: "Task name"
|
|
34
34
|
option :prompt, type: :string, desc: "Task prompt"
|
|
35
|
-
option :
|
|
36
|
-
option :repo, type: :string, desc: "Repository ID"
|
|
35
|
+
option :repo, type: :string, desc: "Repository ID, owner/repo, or GitHub URL"
|
|
37
36
|
option :status, type: :string, desc: "Initial status (draft/waiting)"
|
|
38
37
|
option :template, type: :string, desc: "Template ID"
|
|
39
38
|
option :depends_on, type: :array, desc: "Dependency task IDs"
|
|
@@ -47,8 +46,7 @@ module SchwarmCli
|
|
|
47
46
|
desc "update ID", "Update a task"
|
|
48
47
|
option :name, type: :string, desc: "Task name"
|
|
49
48
|
option :prompt, type: :string, desc: "Task prompt"
|
|
50
|
-
option :
|
|
51
|
-
option :repo, type: :string, desc: "Repository ID"
|
|
49
|
+
option :repo, type: :string, desc: "Repository ID, owner/repo, or GitHub URL"
|
|
52
50
|
option :depends_on, type: :array, desc: "Dependency task IDs"
|
|
53
51
|
def update(id)
|
|
54
52
|
handle_errors do
|
|
@@ -116,16 +114,15 @@ module SchwarmCli
|
|
|
116
114
|
|
|
117
115
|
desc "handoff", "Hand off the current local branch to schwarm as a ready task"
|
|
118
116
|
option :prompt, type: :string, desc: "Task prompt"
|
|
119
|
-
option :
|
|
120
|
-
option :repo, type: :string, desc: "Repository ID (skips origin auto-detect)"
|
|
117
|
+
option :repo, type: :string, desc: "Repository ID, owner/repo, or GitHub URL (skips origin auto-detect)"
|
|
121
118
|
option :name, type: :string, desc: "Task name (defaults to the branch name)"
|
|
122
119
|
def handoff
|
|
123
|
-
prompt =
|
|
124
|
-
abort "Error: --prompt
|
|
120
|
+
prompt = options[:prompt]
|
|
121
|
+
abort "Error: --prompt is required." if prompt.nil? || prompt.strip.empty?
|
|
125
122
|
|
|
126
123
|
handle_errors do
|
|
127
124
|
result = SchwarmCli::HandsOffTask.new(client: client).call(
|
|
128
|
-
prompt: prompt, repo_override: options[:repo], name_override: options[:name]
|
|
125
|
+
prompt: prompt, repo_override: resolve_repo(options[:repo]), name_override: options[:name]
|
|
129
126
|
)
|
|
130
127
|
print_handoff_result(result)
|
|
131
128
|
end
|
|
@@ -136,7 +133,7 @@ module SchwarmCli
|
|
|
136
133
|
def list_attrs
|
|
137
134
|
exclude_archived = options[:status].nil? && !options[:all]
|
|
138
135
|
{
|
|
139
|
-
status: options[:status], repository_id: options[:repo], query: options[:query],
|
|
136
|
+
status: options[:status], repository_id: resolve_repo(options[:repo]), query: options[:query],
|
|
140
137
|
archived: exclude_archived ? false : nil
|
|
141
138
|
}
|
|
142
139
|
end
|
|
@@ -153,28 +150,18 @@ module SchwarmCli
|
|
|
153
150
|
|
|
154
151
|
def create_attrs
|
|
155
152
|
{
|
|
156
|
-
name: options[:name], prompt:
|
|
157
|
-
github_repository_id: options[:repo], status: options[:status],
|
|
153
|
+
name: options[:name], prompt: options[:prompt],
|
|
154
|
+
github_repository_id: resolve_repo(options[:repo]), status: options[:status],
|
|
158
155
|
task_template_id: options[:template], dependency_ids: options[:depends_on]
|
|
159
156
|
}.compact
|
|
160
157
|
end
|
|
161
158
|
|
|
162
159
|
def update_attrs
|
|
163
160
|
{
|
|
164
|
-
name: options[:name], github_repository_id: options[:repo],
|
|
161
|
+
name: options[:name], github_repository_id: resolve_repo(options[:repo]),
|
|
165
162
|
dependency_ids: options[:depends_on]
|
|
166
163
|
}.compact.tap do |attrs|
|
|
167
|
-
attrs[:prompt] =
|
|
168
|
-
end
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
def read_prompt
|
|
172
|
-
if options[:prompt_file]
|
|
173
|
-
file_path = File.expand_path(options[:prompt_file])
|
|
174
|
-
abort "Error: File not found: #{file_path}" unless File.exist?(file_path)
|
|
175
|
-
File.read(file_path)
|
|
176
|
-
else
|
|
177
|
-
options[:prompt]
|
|
164
|
+
attrs[:prompt] = options[:prompt] if options[:prompt]
|
|
178
165
|
end
|
|
179
166
|
end
|
|
180
167
|
end
|
|
@@ -84,28 +84,17 @@ module SchwarmCli
|
|
|
84
84
|
end
|
|
85
85
|
|
|
86
86
|
def resolve_repository(origin:, override:)
|
|
87
|
-
if override
|
|
88
|
-
begin
|
|
89
|
-
return @client.repositories.find(override)["data"]
|
|
90
|
-
rescue Faraday::ResourceNotFound
|
|
91
|
-
return nil
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
slug = origin_slug(origin)
|
|
96
|
-
response = @client.repositories.list(query: slug)
|
|
97
|
-
Array(response["data"]).find { |r| normalize_url(r["github_url"]) == normalize_url(origin) }
|
|
98
|
-
end
|
|
87
|
+
return find_by_id(override) if override
|
|
99
88
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
89
|
+
RepositoryResolver.new(client: @client).resolve_record(origin)
|
|
90
|
+
rescue RepositoryResolver::ResolutionError
|
|
91
|
+
nil
|
|
103
92
|
end
|
|
104
93
|
|
|
105
|
-
def
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
94
|
+
def find_by_id(id)
|
|
95
|
+
@client.repositories.find(id)["data"]
|
|
96
|
+
rescue Faraday::ResourceNotFound
|
|
97
|
+
nil
|
|
109
98
|
end
|
|
110
99
|
|
|
111
100
|
def create_task(repo:, branch:, prompt:, name_override:)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SchwarmCli
|
|
4
|
+
# Turns a user-provided `--repo` reference into a schwarm repository ID.
|
|
5
|
+
#
|
|
6
|
+
# Accepted inputs:
|
|
7
|
+
# - a schwarm repository ID (returned as-is)
|
|
8
|
+
# - "owner/repo"
|
|
9
|
+
# - "https://github.com/owner/repo[.git]"
|
|
10
|
+
# - "git@github.com:owner/repo[.git]"
|
|
11
|
+
class RepositoryResolver
|
|
12
|
+
class ResolutionError < StandardError; end
|
|
13
|
+
|
|
14
|
+
SLUG_PATTERNS = [
|
|
15
|
+
%r{\Ahttps?://github\.com/([^/\s]+/[^/\s]+?)(?:\.git)?/?\z},
|
|
16
|
+
%r{\Agit@github\.com:([^/\s:]+/[^/\s:]+?)(?:\.git)?\z},
|
|
17
|
+
%r{\A([^/\s:]+/[^/\s:]+?)(?:\.git)?\z}
|
|
18
|
+
].freeze
|
|
19
|
+
|
|
20
|
+
def initialize(client:)
|
|
21
|
+
@client = client
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def resolve(ref)
|
|
25
|
+
return nil if blank?(ref)
|
|
26
|
+
|
|
27
|
+
record = resolve_record(ref)
|
|
28
|
+
record ? record["id"] : ref
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Like `resolve`, but returns the full repo record when the ref is looked up
|
|
32
|
+
# via slug/URL. Returns nil when `ref` is blank or already a bare ID (caller
|
|
33
|
+
# should `find` by id directly in that case).
|
|
34
|
+
def resolve_record(ref)
|
|
35
|
+
return nil if blank?(ref)
|
|
36
|
+
|
|
37
|
+
slug = extract_slug(ref.strip)
|
|
38
|
+
slug ? lookup_by_slug(slug, ref) : nil
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def blank?(ref)
|
|
44
|
+
ref.nil? || ref.to_s.strip.empty?
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def extract_slug(ref)
|
|
48
|
+
SLUG_PATTERNS.filter_map { |pat| ref.match(pat)&.[](1) }.first
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def lookup_by_slug(slug, original)
|
|
52
|
+
response = @client.repositories.list(query: slug)
|
|
53
|
+
match = Array(response["data"]).find { |r| slug_from_url(r["url"]) == slug }
|
|
54
|
+
raise ResolutionError, "no schwarm repository matches `#{original}`" if match.nil?
|
|
55
|
+
|
|
56
|
+
match
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def slug_from_url(url)
|
|
60
|
+
return nil if url.nil?
|
|
61
|
+
|
|
62
|
+
url.sub(%r{\Ahttps?://github\.com/}, "").sub(/\Agit@github\.com:/, "").sub(/\.git\z/, "")
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
data/lib/schwarm_cli/version.rb
CHANGED
data/lib/schwarm_cli.rb
CHANGED
|
@@ -4,6 +4,7 @@ require_relative "schwarm_cli/version"
|
|
|
4
4
|
require_relative "schwarm_cli/config"
|
|
5
5
|
require_relative "schwarm_cli/client"
|
|
6
6
|
require_relative "schwarm_cli/git"
|
|
7
|
+
require_relative "schwarm_cli/repository_resolver"
|
|
7
8
|
require_relative "schwarm_cli/hands_off_task"
|
|
8
9
|
require_relative "schwarm_cli/formatters/json"
|
|
9
10
|
require_relative "schwarm_cli/formatters/table"
|
data/schwarm-skill.md
CHANGED
|
@@ -32,7 +32,14 @@ The `schwarm` CLI is installed and configured (`schwarm configure`).
|
|
|
32
32
|
```bash
|
|
33
33
|
schwarm tasks create --repo <REPO_ID> --name "Fix login bug" --prompt "The login form crashes when email is empty. Fix the validation in app/models/user.rb" --status ready
|
|
34
34
|
```
|
|
35
|
-
|
|
35
|
+
For a multi-line prompt, pipe via HEREDOC:
|
|
36
|
+
```bash
|
|
37
|
+
schwarm tasks create --repo <REPO_ID> --name "Fix login bug" --status ready --prompt "$(cat <<'EOF'
|
|
38
|
+
The login form crashes when empty. Fix validation in app/models/user.rb
|
|
39
|
+
and add a regression test.
|
|
40
|
+
EOF
|
|
41
|
+
)"
|
|
42
|
+
```
|
|
36
43
|
3. Check the created task:
|
|
37
44
|
```bash
|
|
38
45
|
schwarm tasks show <TASK_ID>
|
|
@@ -53,10 +60,24 @@ continues committing to it.
|
|
|
53
60
|
```bash
|
|
54
61
|
schwarm tasks handoff --prompt "continue the validation logic, add tests"
|
|
55
62
|
```
|
|
56
|
-
Use `--prompt-file ./handoff.md` for long prompts.
|
|
57
63
|
3. Take note of the task ID printed on success; you can monitor it like any
|
|
58
64
|
other task.
|
|
59
65
|
|
|
66
|
+
**Keep the prompt short.** The prompt is a pointer, not a spec. Before handing
|
|
67
|
+
off, commit any detailed instructions, design notes, or TODOs into the repo
|
|
68
|
+
(e.g. a `HANDOFF.md`, `AGENTS.md`, or inline comments) so the next agent reads
|
|
69
|
+
them from the working tree. Then the `--prompt` just needs to say what to do
|
|
70
|
+
next and where to look, e.g. `"continue per HANDOFF.md"`.
|
|
71
|
+
|
|
72
|
+
For a multi-line prompt, use a HEREDOC rather than a file flag:
|
|
73
|
+
```bash
|
|
74
|
+
schwarm tasks handoff --prompt "$(cat <<'EOF'
|
|
75
|
+
Continue the validation work. Start from the TODOs in app/models/user.rb
|
|
76
|
+
and follow the plan in HANDOFF.md.
|
|
77
|
+
EOF
|
|
78
|
+
)"
|
|
79
|
+
```
|
|
80
|
+
|
|
60
81
|
**Watch for:**
|
|
61
82
|
- The command refuses to hand off the base branch (`main`). Create a feature
|
|
62
83
|
branch first.
|
|
@@ -223,7 +244,9 @@ for tasks in a repository.
|
|
|
223
244
|
- Check task status before taking actions (e.g., only `retry` works on `error`
|
|
224
245
|
tasks, only `start` works on `draft` tasks).
|
|
225
246
|
- When building a DAG, create all tasks as drafts first, then start them all.
|
|
226
|
-
-
|
|
247
|
+
- Keep `--prompt` short — commit long-form instructions (plans, TODOs,
|
|
248
|
+
`HANDOFF.md`) into the repo and point the prompt at them. For multi-line
|
|
249
|
+
prompts, pipe via HEREDOC: `--prompt "$(cat <<'EOF' ... EOF)"`.
|
|
227
250
|
- Run `schwarm <command> help` for full flag documentation on any command.
|
|
228
251
|
- `schwarm tasks list` excludes archived tasks by default. Use `--all` to
|
|
229
252
|
include them or `--status archived` to see only archived.
|
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.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vincent Garrigues
|
|
@@ -122,6 +122,7 @@ files:
|
|
|
122
122
|
- lib/schwarm_cli/formatters/table.rb
|
|
123
123
|
- lib/schwarm_cli/git.rb
|
|
124
124
|
- lib/schwarm_cli/hands_off_task.rb
|
|
125
|
+
- lib/schwarm_cli/repository_resolver.rb
|
|
125
126
|
- lib/schwarm_cli/version.rb
|
|
126
127
|
- schwarm-skill.md
|
|
127
128
|
homepage: https://github.com/getdexter/schwarm
|