ace-task 0.38.1 → 0.39.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 +4 -4
- data/CHANGELOG.md +15 -0
- data/handbook/workflow-instructions/task/draft.wf.md +18 -18
- data/lib/ace/task/atoms/task_frontmatter_defaults.rb +5 -2
- data/lib/ace/task/cli/commands/create.rb +20 -13
- data/lib/ace/task/cli/commands/issue_link.rb +38 -0
- data/lib/ace/task/cli/commands/issue_sync.rb +42 -0
- data/lib/ace/task/cli/commands/update.rb +2 -0
- data/lib/ace/task/cli.rb +9 -5
- data/lib/ace/task/molecules/issue_link.rb +75 -0
- data/lib/ace/task/molecules/issue_sync_adapter.rb +99 -0
- data/lib/ace/task/molecules/subtask_creator.rb +2 -2
- data/lib/ace/task/molecules/task_creator.rb +2 -2
- data/lib/ace/task/molecules/task_frontmatter_validator.rb +44 -18
- data/lib/ace/task/molecules/task_plan_prompt_builder.rb +3 -3
- data/lib/ace/task/molecules/task_reparenter.rb +66 -0
- data/lib/ace/task/molecules/task_resolver.rb +31 -3
- data/lib/ace/task/organisms/task_manager.rb +780 -107
- data/lib/ace/task/version.rb +1 -1
- data/lib/ace/task.rb +0 -1
- metadata +24 -8
- data/lib/ace/task/cli/commands/github_sync.rb +0 -73
- data/lib/ace/task/molecules/github_issue_sync_adapter.rb +0 -88
data/lib/ace/task/version.rb
CHANGED
data/lib/ace/task.rb
CHANGED
|
@@ -26,7 +26,6 @@ require_relative "task/molecules/subtask_creator"
|
|
|
26
26
|
require_relative "task/molecules/task_display_formatter"
|
|
27
27
|
require_relative "task/molecules/dependency_aware_smart_sorter"
|
|
28
28
|
require_relative "task/molecules/path_utils"
|
|
29
|
-
require_relative "task/molecules/github_issue_sync_adapter"
|
|
30
29
|
require_relative "task/molecules/task_plan_cache"
|
|
31
30
|
require_relative "task/molecules/task_plan_generator"
|
|
32
31
|
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ace-task
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.39.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michal Czyz
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-
|
|
10
|
+
date: 2026-10-03 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: ace-support-core
|
|
@@ -85,28 +85,42 @@ dependencies:
|
|
|
85
85
|
requirements:
|
|
86
86
|
- - "~>"
|
|
87
87
|
- !ruby/object:Gem::Version
|
|
88
|
-
version: '0.
|
|
88
|
+
version: '0.26'
|
|
89
89
|
type: :runtime
|
|
90
90
|
prerelease: false
|
|
91
91
|
version_requirements: !ruby/object:Gem::Requirement
|
|
92
92
|
requirements:
|
|
93
93
|
- - "~>"
|
|
94
94
|
- !ruby/object:Gem::Version
|
|
95
|
-
version: '0.
|
|
95
|
+
version: '0.26'
|
|
96
96
|
- !ruby/object:Gem::Dependency
|
|
97
97
|
name: ace-git-github
|
|
98
98
|
requirement: !ruby/object:Gem::Requirement
|
|
99
99
|
requirements:
|
|
100
100
|
- - "~>"
|
|
101
101
|
- !ruby/object:Gem::Version
|
|
102
|
-
version: '0.
|
|
102
|
+
version: '0.3'
|
|
103
|
+
type: :runtime
|
|
104
|
+
prerelease: false
|
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - "~>"
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '0.3'
|
|
110
|
+
- !ruby/object:Gem::Dependency
|
|
111
|
+
name: ace-git-forgejo
|
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - "~>"
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: '0.4'
|
|
103
117
|
type: :runtime
|
|
104
118
|
prerelease: false
|
|
105
119
|
version_requirements: !ruby/object:Gem::Requirement
|
|
106
120
|
requirements:
|
|
107
121
|
- - "~>"
|
|
108
122
|
- !ruby/object:Gem::Version
|
|
109
|
-
version: '0.
|
|
123
|
+
version: '0.4'
|
|
110
124
|
- !ruby/object:Gem::Dependency
|
|
111
125
|
name: ace-support-cli
|
|
112
126
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -172,7 +186,8 @@ files:
|
|
|
172
186
|
- lib/ace/task/cli.rb
|
|
173
187
|
- lib/ace/task/cli/commands/create.rb
|
|
174
188
|
- lib/ace/task/cli/commands/doctor.rb
|
|
175
|
-
- lib/ace/task/cli/commands/
|
|
189
|
+
- lib/ace/task/cli/commands/issue_link.rb
|
|
190
|
+
- lib/ace/task/cli/commands/issue_sync.rb
|
|
176
191
|
- lib/ace/task/cli/commands/list.rb
|
|
177
192
|
- lib/ace/task/cli/commands/plan.rb
|
|
178
193
|
- lib/ace/task/cli/commands/show.rb
|
|
@@ -180,7 +195,8 @@ files:
|
|
|
180
195
|
- lib/ace/task/cli/commands/update.rb
|
|
181
196
|
- lib/ace/task/models/task.rb
|
|
182
197
|
- lib/ace/task/molecules/dependency_aware_smart_sorter.rb
|
|
183
|
-
- lib/ace/task/molecules/
|
|
198
|
+
- lib/ace/task/molecules/issue_link.rb
|
|
199
|
+
- lib/ace/task/molecules/issue_sync_adapter.rb
|
|
184
200
|
- lib/ace/task/molecules/path_utils.rb
|
|
185
201
|
- lib/ace/task/molecules/subtask_creator.rb
|
|
186
202
|
- lib/ace/task/molecules/task_config_loader.rb
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "ace/support/cli"
|
|
4
|
-
|
|
5
|
-
module Ace
|
|
6
|
-
module Task
|
|
7
|
-
module CLI
|
|
8
|
-
module Commands
|
|
9
|
-
# ace-support-cli Command class for ace-task github-sync
|
|
10
|
-
class GithubSync < Ace::Support::Cli::Command
|
|
11
|
-
include Ace::Support::Cli::Base
|
|
12
|
-
|
|
13
|
-
desc <<~DESC.strip
|
|
14
|
-
Synchronize linked GitHub issues for a task or all linked tasks
|
|
15
|
-
DESC
|
|
16
|
-
|
|
17
|
-
example [
|
|
18
|
-
"q7w # Sync one task",
|
|
19
|
-
"--all # Sync all linked tasks",
|
|
20
|
-
"--pending # Replay tasks flagged with github_sync_pending (offline sync)"
|
|
21
|
-
]
|
|
22
|
-
|
|
23
|
-
argument :ref, required: false, desc: "Task reference (full ID, short ref, or suffix)"
|
|
24
|
-
option :all, type: :boolean, aliases: %w[-a], desc: "Sync all linked tasks"
|
|
25
|
-
option :pending, type: :boolean, desc: "Sync only tasks flagged with github_sync_pending"
|
|
26
|
-
|
|
27
|
-
option :quiet, type: :boolean, aliases: %w[-q], desc: "Suppress non-essential output"
|
|
28
|
-
option :verbose, type: :boolean, aliases: %w[-v], desc: "Show verbose output"
|
|
29
|
-
option :debug, type: :boolean, aliases: %w[-d], desc: "Show debug output"
|
|
30
|
-
|
|
31
|
-
def call(ref: nil, **options)
|
|
32
|
-
all = options[:all] || options[:pending]
|
|
33
|
-
|
|
34
|
-
if !all && (ref.nil? || ref.strip.empty?)
|
|
35
|
-
raise Ace::Support::Cli::Error.new("Provide a task reference or use --all")
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
manager = Ace::Task::Organisms::TaskManager.new
|
|
39
|
-
result = manager.github_sync(ref: ref, all: options[:all], pending: options[:pending])
|
|
40
|
-
raise Ace::Support::Cli::Error.new("Task '#{ref}' not found") if result.nil?
|
|
41
|
-
print_failures(result[:failures])
|
|
42
|
-
|
|
43
|
-
if result[:failed].to_i.positive?
|
|
44
|
-
raise Ace::Support::Cli::Error.new(
|
|
45
|
-
"GitHub sync incomplete: synced #{result[:synced]}, failed #{result[:failed]}, skipped #{result[:skipped]}"
|
|
46
|
-
)
|
|
47
|
-
elsif options[:pending] && result[:synced].to_i.zero? && result[:pending].to_i.zero?
|
|
48
|
-
puts "No pending GitHub syncs"
|
|
49
|
-
elsif all
|
|
50
|
-
puts "GitHub sync complete: synced #{result[:synced]} linked task(s), skipped #{result[:skipped]} task(s)"
|
|
51
|
-
pending = result[:pending].to_i
|
|
52
|
-
warn "gh unavailable: #{pending} task(s) remain flagged for github-sync --pending" if pending.positive?
|
|
53
|
-
elsif result[:pending].to_i.positive?
|
|
54
|
-
puts "GitHub sync skipped (gh unavailable); flagged for github-sync --pending"
|
|
55
|
-
elsif result[:synced].positive?
|
|
56
|
-
puts "GitHub sync complete: #{result[:task_id]}"
|
|
57
|
-
else
|
|
58
|
-
puts "No linked GitHub issues for task #{result[:task_id]}"
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
private
|
|
63
|
-
|
|
64
|
-
def print_failures(failures)
|
|
65
|
-
Array(failures).each do |failure|
|
|
66
|
-
warn "GitHub sync failed for #{failure[:task_id]}: #{failure[:error]}"
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
end
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Ace
|
|
4
|
-
module Task
|
|
5
|
-
module Molecules
|
|
6
|
-
# Bridges ace-task lifecycle events to reusable ace-git issue sync primitives.
|
|
7
|
-
# GitHub sync is best-effort: when gh is unavailable, operations no-op and
|
|
8
|
-
# callers record the pending sync on the task instead.
|
|
9
|
-
class GithubIssueSyncAdapter
|
|
10
|
-
UNAVAILABLE_MESSAGE = "GitHub issue sync primitives are unavailable. " \
|
|
11
|
-
"Update ace-git-github to a version providing them."
|
|
12
|
-
|
|
13
|
-
CANDIDATE_INTEGRATIONS = [
|
|
14
|
-
["Ace::Git::Github::IssueSync", :validate_link!],
|
|
15
|
-
["Ace::Git::Github::IssueSync", :sync_task]
|
|
16
|
-
].freeze
|
|
17
|
-
|
|
18
|
-
# True when GitHub sync should run: the integration resolves and reports
|
|
19
|
-
# gh as installed and authenticated.
|
|
20
|
-
def available?
|
|
21
|
-
receiver, = resolve_integration(:sync_task)
|
|
22
|
-
return false unless receiver
|
|
23
|
-
|
|
24
|
-
receiver.respond_to?(:available?) ? receiver.available? : false
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def validate_link!(issue_id:, previous_task: nil)
|
|
28
|
-
return unless issue_id.to_i.positive?
|
|
29
|
-
return unless available?
|
|
30
|
-
|
|
31
|
-
receiver, method_name = resolve_integration(:validate_link!)
|
|
32
|
-
raise UNAVAILABLE_MESSAGE unless receiver && method_name
|
|
33
|
-
|
|
34
|
-
receiver.public_send(
|
|
35
|
-
method_name,
|
|
36
|
-
issue_id: issue_id.to_i,
|
|
37
|
-
task_id: previous_task&.id,
|
|
38
|
-
previous_task_id: previous_task&.id
|
|
39
|
-
)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def sync_task(task:, reason:, previous_task: nil)
|
|
43
|
-
current_issue_ids = [task.metadata["github_issue"]].compact.map(&:to_i).uniq
|
|
44
|
-
previous_issue_ids = [previous_task&.metadata&.[]("github_issue")].compact.map(&:to_i).uniq
|
|
45
|
-
issue_ids = (current_issue_ids + previous_issue_ids).uniq
|
|
46
|
-
return {synced: 0, issues: []} if issue_ids.empty? || !available?
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
receiver, method_name = resolve_integration(:sync_task)
|
|
50
|
-
raise UNAVAILABLE_MESSAGE unless receiver && method_name
|
|
51
|
-
|
|
52
|
-
payload = {
|
|
53
|
-
task_id: task.id,
|
|
54
|
-
task_title: task.title,
|
|
55
|
-
task_status: task.status,
|
|
56
|
-
task_path: task.file_path || task.path,
|
|
57
|
-
issue_ids: issue_ids,
|
|
58
|
-
current_issue_ids: current_issue_ids,
|
|
59
|
-
reason: reason,
|
|
60
|
-
previous: previous_task ? {
|
|
61
|
-
id: previous_task.id,
|
|
62
|
-
title: previous_task.title,
|
|
63
|
-
status: previous_task.status,
|
|
64
|
-
path: previous_task.file_path || previous_task.path
|
|
65
|
-
} : nil
|
|
66
|
-
}
|
|
67
|
-
receiver.public_send(method_name, **payload)
|
|
68
|
-
{synced: issue_ids.length, issues: issue_ids}
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
private
|
|
72
|
-
|
|
73
|
-
def resolve_integration(expected_method = nil)
|
|
74
|
-
CANDIDATE_INTEGRATIONS.each do |constant_name, method_name|
|
|
75
|
-
next if expected_method && method_name != expected_method
|
|
76
|
-
|
|
77
|
-
klass = constant_name.split("::").reject(&:empty?).inject(Object) { |ctx, name| ctx.const_get(name) }
|
|
78
|
-
return [klass, method_name] if klass.respond_to?(method_name)
|
|
79
|
-
rescue NameError
|
|
80
|
-
next
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
[nil, nil]
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
end
|