ace-task 0.39.2 → 0.39.3
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/.ace-defaults/nav/protocols/skill-sources/ace-task.yml +0 -0
- data/.ace-defaults/nav/protocols/wfi-sources/ace-task.yml +0 -0
- data/.ace-defaults/task/config.yml +0 -0
- data/CHANGELOG.md +7 -0
- data/README.md +0 -0
- data/Rakefile +0 -0
- data/handbook/guides/task-definition.g.md +0 -0
- data/handbook/skills/as-bug-analyze/SKILL.md +0 -0
- data/handbook/skills/as-bug-fix/SKILL.md +0 -0
- data/handbook/skills/as-task-document-unplanned/SKILL.md +0 -0
- data/handbook/skills/as-task-draft/SKILL.md +0 -0
- data/handbook/skills/as-task-finder/SKILL.md +0 -0
- data/handbook/skills/as-task-plan/SKILL.md +0 -0
- data/handbook/skills/as-task-review/SKILL.md +0 -0
- data/handbook/skills/as-task-review-questions/SKILL.md +0 -0
- data/handbook/skills/as-task-update/SKILL.md +0 -0
- data/handbook/skills/as-task-work/SKILL.md +0 -0
- data/handbook/templates/task/draft.template.md +0 -0
- data/handbook/templates/task/file-modification-checklist.template.md +0 -0
- data/handbook/templates/task/technical-approach.template.md +0 -0
- data/handbook/workflow-instructions/bug/analyze.wf.md +0 -0
- data/handbook/workflow-instructions/bug/fix.wf.md +0 -0
- data/handbook/workflow-instructions/task/document-unplanned.wf.md +0 -0
- data/handbook/workflow-instructions/task/finder.wf.md +0 -0
- data/handbook/workflow-instructions/task/plan.wf.md +0 -0
- data/handbook/workflow-instructions/task/review-plan.wf.md +0 -0
- data/handbook/workflow-instructions/task/review-questions.wf.md +0 -0
- data/handbook/workflow-instructions/task/review-work.wf.md +0 -0
- data/handbook/workflow-instructions/task/review.wf.md +0 -0
- data/handbook/workflow-instructions/task/update.wf.md +0 -0
- data/lib/ace/task/atoms/task_file_pattern.rb +0 -0
- data/lib/ace/task/atoms/task_id_formatter.rb +0 -0
- data/lib/ace/task/atoms/task_validation_rules.rb +0 -0
- data/lib/ace/task/cli/commands/create.rb +122 -4
- data/lib/ace/task/cli/commands/doctor.rb +0 -0
- data/lib/ace/task/cli/commands/plan.rb +0 -0
- data/lib/ace/task/cli/commands/show.rb +0 -0
- data/lib/ace/task/cli/commands/status.rb +0 -0
- data/lib/ace/task/models/task.rb +0 -0
- data/lib/ace/task/molecules/path_utils.rb +0 -0
- data/lib/ace/task/molecules/task_config_loader.rb +0 -0
- data/lib/ace/task/molecules/task_doctor_reporter.rb +0 -0
- data/lib/ace/task/molecules/task_loader.rb +0 -0
- data/lib/ace/task/molecules/task_plan_cache.rb +0 -0
- data/lib/ace/task/molecules/task_plan_generator.rb +0 -0
- data/lib/ace/task/molecules/task_structure_validator.rb +0 -0
- data/lib/ace/task/organisms/task_doctor.rb +0 -0
- data/lib/ace/task/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bf3a2b4bdbf7c413363c5f9b81a0f0b4161e6b50e58cce724adcb67ba03fc1c2
|
|
4
|
+
data.tar.gz: b08a3d0f30ad8dfb455c6232bde690e632a9028a603ac37fa289a4768c2f0312
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ea63fb03267e6eb84875128ff0ec56becc9fbc0a650a40344cf9a1b11090a61791eed9c97a203ce8a231b132534d442d0238d93cac07162ecd96f522cdd930be
|
|
7
|
+
data.tar.gz: 2be684d6224ec2a57dc9cc4f84eafdee43c14e1b044116e470f12b51dd1cab952267ff9b4a05d96f6e2df5eb4ef1b10d0bd52e32a31e53275a8cdca7e43b0626
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.39.3] - 2026-10-12
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Route `ace-task create --in FOLDER` through the task manager's relocation API
|
|
15
|
+
and remove the newly created task artifacts when destination placement fails.
|
|
16
|
+
|
|
10
17
|
## [0.39.2] - 2026-10-06
|
|
11
18
|
|
|
12
19
|
### Fixed
|
data/README.md
CHANGED
|
File without changes
|
data/Rakefile
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "ace/support/cli"
|
|
4
|
+
require "fileutils"
|
|
4
5
|
|
|
5
6
|
module Ace
|
|
6
7
|
module Task
|
|
@@ -10,6 +11,9 @@ module Ace
|
|
|
10
11
|
class Create < Ace::Support::Cli::Command
|
|
11
12
|
include Ace::Support::Cli::Base
|
|
12
13
|
|
|
14
|
+
# "next" is a move-to-root alias and is validated separately.
|
|
15
|
+
BUILT_IN_DESTINATIONS = %w[maybe anytime archive].freeze
|
|
16
|
+
|
|
13
17
|
desc <<~DESC.strip
|
|
14
18
|
Create a new task
|
|
15
19
|
|
|
@@ -38,7 +42,8 @@ module Ace
|
|
|
38
42
|
option :server, type: :string, desc: "Named forge server"
|
|
39
43
|
option :"default-server", type: :boolean, desc: "Use the configured default forge server"
|
|
40
44
|
option :"child-of", type: :string, desc: "Parent task reference (creates subtask)"
|
|
41
|
-
option :in, type: :string, aliases: %w[-i],
|
|
45
|
+
option :in, type: :string, aliases: %w[-i],
|
|
46
|
+
desc: "Top-level target (next, maybe, anytime, archive, or existing custom folder)"
|
|
42
47
|
option :"dry-run", type: :boolean, aliases: %w[-n], desc: "Preview without writing"
|
|
43
48
|
|
|
44
49
|
option :git_commit, type: :boolean, aliases: %w[--gc], desc: "Auto-commit changes"
|
|
@@ -72,6 +77,10 @@ module Ace
|
|
|
72
77
|
end
|
|
73
78
|
end
|
|
74
79
|
|
|
80
|
+
manager = Ace::Task::Organisms::TaskManager.new
|
|
81
|
+
validate_destination!(manager, in_folder) if in_folder && !child_of
|
|
82
|
+
placement_directories_before = directories_under(manager.root_dir) if in_folder && !child_of
|
|
83
|
+
|
|
75
84
|
if dry_run
|
|
76
85
|
puts "Would create task:"
|
|
77
86
|
puts " Title: #{title}"
|
|
@@ -85,8 +94,6 @@ module Ace
|
|
|
85
94
|
return
|
|
86
95
|
end
|
|
87
96
|
|
|
88
|
-
manager = Ace::Task::Organisms::TaskManager.new
|
|
89
|
-
|
|
90
97
|
task = begin
|
|
91
98
|
if child_of
|
|
92
99
|
manager.create_subtask(
|
|
@@ -119,7 +126,7 @@ module Ace
|
|
|
119
126
|
|
|
120
127
|
# Move to folder if specified
|
|
121
128
|
if in_folder && !child_of
|
|
122
|
-
task = manager
|
|
129
|
+
task = place_created_task(manager, task, in_folder, placement_directories_before)
|
|
123
130
|
end
|
|
124
131
|
|
|
125
132
|
puts "Created task #{task.id}"
|
|
@@ -140,6 +147,117 @@ module Ace
|
|
|
140
147
|
|
|
141
148
|
private
|
|
142
149
|
|
|
150
|
+
def validate_destination!(manager, target_folder)
|
|
151
|
+
detector = Ace::Support::Items::Atoms::SpecialFolderDetector
|
|
152
|
+
return if detector.move_to_root?(target_folder)
|
|
153
|
+
|
|
154
|
+
if detector.virtual_filter?(target_folder)
|
|
155
|
+
raise Ace::Support::Cli::Error,
|
|
156
|
+
"Destination '#{target_folder}' is a virtual list filter, not a physical folder."
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
normalized = detector.normalize(target_folder)
|
|
160
|
+
configured_path = File.join(manager.root_dir, normalized)
|
|
161
|
+
normalized_built_ins = BUILT_IN_DESTINATIONS.map { |name| detector.normalize(name) }
|
|
162
|
+
valid = !target_folder.strip.empty? &&
|
|
163
|
+
!normalized.include?(File::SEPARATOR) &&
|
|
164
|
+
!normalized.include?("..") &&
|
|
165
|
+
(normalized_built_ins.include?(normalized) || Dir.exist?(configured_path)) &&
|
|
166
|
+
destination_within_root?(manager.root_dir, configured_path)
|
|
167
|
+
return if valid
|
|
168
|
+
|
|
169
|
+
choices = (["next"] + BUILT_IN_DESTINATIONS).join(", ")
|
|
170
|
+
raise Ace::Support::Cli::Error,
|
|
171
|
+
"Destination '#{target_folder}' does not exist. " \
|
|
172
|
+
"Use #{choices}, or an existing custom task folder."
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def destination_within_root?(root, destination)
|
|
176
|
+
return true unless File.exist?(destination)
|
|
177
|
+
|
|
178
|
+
root_path = File.realpath(root)
|
|
179
|
+
destination_path = File.realpath(destination)
|
|
180
|
+
destination_path.start_with?(root_path + File::SEPARATOR)
|
|
181
|
+
rescue Errno::ENOENT, Errno::EACCES
|
|
182
|
+
false
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def place_created_task(manager, task, target_folder, directories_before)
|
|
186
|
+
placed_task = manager.update(task.id, move_to: target_folder)
|
|
187
|
+
expected_folder = if Ace::Support::Items::Atoms::SpecialFolderDetector.move_to_root?(target_folder)
|
|
188
|
+
nil
|
|
189
|
+
else
|
|
190
|
+
Ace::Support::Items::Atoms::SpecialFolderDetector.normalize(target_folder)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
unless placed_task && placed_task.special_folder == expected_folder
|
|
194
|
+
actual_folder = if placed_task
|
|
195
|
+
placed_task.special_folder || "root"
|
|
196
|
+
else
|
|
197
|
+
"no task returned"
|
|
198
|
+
end
|
|
199
|
+
# This internal signal is wrapped below with rollback and an actionable CLI error.
|
|
200
|
+
raise "placement returned #{actual_folder.inspect}, expected #{expected_folder || "root"}"
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
placed_task
|
|
204
|
+
rescue Ace::Git::Error
|
|
205
|
+
# update retains linked tasks after post-placement sync failures as
|
|
206
|
+
# recovery records; those are not destination-placement failures.
|
|
207
|
+
raise
|
|
208
|
+
rescue StandardError => e
|
|
209
|
+
begin
|
|
210
|
+
remove_created_task_artifacts(manager, task)
|
|
211
|
+
remove_empty_directories_created_since(manager.root_dir, directories_before)
|
|
212
|
+
rescue StandardError => cleanup_error
|
|
213
|
+
raise Ace::Support::Cli::Error,
|
|
214
|
+
"Failed to create task in '#{target_folder}': #{e.message}. " \
|
|
215
|
+
"Cleanup also failed: #{cleanup_error.message}"
|
|
216
|
+
end
|
|
217
|
+
raise Ace::Support::Cli::Error,
|
|
218
|
+
"Failed to create task in '#{target_folder}': #{e.message}. " \
|
|
219
|
+
"No task was created; fix the destination and retry."
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def remove_created_task_artifacts(manager, task)
|
|
223
|
+
root = File.expand_path(manager.root_dir)
|
|
224
|
+
candidates = [task.path]
|
|
225
|
+
candidates.concat(
|
|
226
|
+
Dir.glob(File.join(root, "**", "#{task.id}-*")).select { |path| File.directory?(path) }
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
candidates.uniq.each do |path|
|
|
230
|
+
expanded = File.expand_path(path)
|
|
231
|
+
next unless expanded.start_with?(root + File::SEPARATOR)
|
|
232
|
+
|
|
233
|
+
FileUtils.rm_rf(expanded)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
remaining = Dir.glob(File.join(root, "**", "#{task.id}-*")).select { |path| File.exist?(path) }
|
|
237
|
+
return if remaining.empty?
|
|
238
|
+
|
|
239
|
+
raise Ace::Support::Cli::Error,
|
|
240
|
+
"Failed to remove partial task artifacts after placement failure: #{remaining.join(", ")}"
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def directories_under(root)
|
|
244
|
+
return [] unless Dir.exist?(root)
|
|
245
|
+
|
|
246
|
+
[File.expand_path(root)] + Dir.glob(File.join(root, "**", "*"))
|
|
247
|
+
.select { |path| File.directory?(path) }
|
|
248
|
+
.map { |path| File.expand_path(path) }
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def remove_empty_directories_created_since(root, directories_before)
|
|
252
|
+
# Only directories created during this short command transaction
|
|
253
|
+
# are candidates, and non-empty concurrent directories are retained.
|
|
254
|
+
(directories_under(root) - directories_before).sort_by(&:length).reverse_each do |path|
|
|
255
|
+
Dir.rmdir(path)
|
|
256
|
+
rescue Errno::ENOENT, Errno::ENOTEMPTY
|
|
257
|
+
next
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
143
261
|
def resolve_title(positional_title, flag_title)
|
|
144
262
|
positional_present = present_string?(positional_title)
|
|
145
263
|
flag_present = present_string?(flag_title)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
data/lib/ace/task/models/task.rb
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
data/lib/ace/task/version.rb
CHANGED
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.39.
|
|
4
|
+
version: 0.39.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michal Czyz
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-10-
|
|
10
|
+
date: 2026-10-12 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: ace-support-core
|