ace-task 0.38.1 → 0.39.1

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.
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Ace
4
4
  module Task
5
- VERSION = "0.38.1"
5
+ VERSION = "0.39.1"
6
6
  end
7
7
  end
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.38.1
4
+ version: 0.39.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michal Czyz
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2026-09-30 00:00:00.000000000 Z
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.24'
88
+ version: '0.27'
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.24'
95
+ version: '0.27'
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.2'
102
+ version: '0.4'
103
103
  type: :runtime
104
104
  prerelease: false
105
105
  version_requirements: !ruby/object:Gem::Requirement
106
106
  requirements:
107
107
  - - "~>"
108
108
  - !ruby/object:Gem::Version
109
- version: '0.2'
109
+ version: '0.4'
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.5'
117
+ type: :runtime
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '0.5'
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/github_sync.rb
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/github_issue_sync_adapter.rb
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