ace-task 0.31.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.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.ace-defaults/nav/protocols/skill-sources/ace-task.yml +19 -0
  3. data/.ace-defaults/nav/protocols/wfi-sources/ace-task.yml +19 -0
  4. data/.ace-defaults/task/config.yml +25 -0
  5. data/CHANGELOG.md +518 -0
  6. data/README.md +52 -0
  7. data/Rakefile +12 -0
  8. data/exe/ace-task +22 -0
  9. data/handbook/guides/task-definition.g.md +156 -0
  10. data/handbook/skills/as-bug-analyze/SKILL.md +26 -0
  11. data/handbook/skills/as-bug-fix/SKILL.md +27 -0
  12. data/handbook/skills/as-task-document-unplanned/SKILL.md +27 -0
  13. data/handbook/skills/as-task-draft/SKILL.md +24 -0
  14. data/handbook/skills/as-task-finder/SKILL.md +27 -0
  15. data/handbook/skills/as-task-plan/SKILL.md +30 -0
  16. data/handbook/skills/as-task-review/SKILL.md +25 -0
  17. data/handbook/skills/as-task-review-questions/SKILL.md +25 -0
  18. data/handbook/skills/as-task-update/SKILL.md +21 -0
  19. data/handbook/skills/as-task-work/SKILL.md +41 -0
  20. data/handbook/templates/task/draft.template.md +166 -0
  21. data/handbook/templates/task/file-modification-checklist.template.md +26 -0
  22. data/handbook/templates/task/technical-approach.template.md +26 -0
  23. data/handbook/workflow-instructions/bug/analyze.wf.md +458 -0
  24. data/handbook/workflow-instructions/bug/fix.wf.md +512 -0
  25. data/handbook/workflow-instructions/task/document-unplanned.wf.md +222 -0
  26. data/handbook/workflow-instructions/task/draft.wf.md +552 -0
  27. data/handbook/workflow-instructions/task/finder.wf.md +22 -0
  28. data/handbook/workflow-instructions/task/plan.wf.md +489 -0
  29. data/handbook/workflow-instructions/task/review-plan.wf.md +144 -0
  30. data/handbook/workflow-instructions/task/review-questions.wf.md +411 -0
  31. data/handbook/workflow-instructions/task/review-work.wf.md +146 -0
  32. data/handbook/workflow-instructions/task/review.wf.md +351 -0
  33. data/handbook/workflow-instructions/task/update.wf.md +118 -0
  34. data/handbook/workflow-instructions/task/work.wf.md +106 -0
  35. data/lib/ace/task/atoms/task_file_pattern.rb +68 -0
  36. data/lib/ace/task/atoms/task_frontmatter_defaults.rb +46 -0
  37. data/lib/ace/task/atoms/task_id_formatter.rb +62 -0
  38. data/lib/ace/task/atoms/task_validation_rules.rb +51 -0
  39. data/lib/ace/task/cli/commands/create.rb +105 -0
  40. data/lib/ace/task/cli/commands/doctor.rb +206 -0
  41. data/lib/ace/task/cli/commands/list.rb +73 -0
  42. data/lib/ace/task/cli/commands/plan.rb +119 -0
  43. data/lib/ace/task/cli/commands/show.rb +58 -0
  44. data/lib/ace/task/cli/commands/status.rb +77 -0
  45. data/lib/ace/task/cli/commands/update.rb +183 -0
  46. data/lib/ace/task/cli.rb +83 -0
  47. data/lib/ace/task/models/task.rb +46 -0
  48. data/lib/ace/task/molecules/path_utils.rb +20 -0
  49. data/lib/ace/task/molecules/subtask_creator.rb +130 -0
  50. data/lib/ace/task/molecules/task_config_loader.rb +92 -0
  51. data/lib/ace/task/molecules/task_creator.rb +115 -0
  52. data/lib/ace/task/molecules/task_display_formatter.rb +221 -0
  53. data/lib/ace/task/molecules/task_doctor_fixer.rb +510 -0
  54. data/lib/ace/task/molecules/task_doctor_reporter.rb +264 -0
  55. data/lib/ace/task/molecules/task_frontmatter_validator.rb +138 -0
  56. data/lib/ace/task/molecules/task_loader.rb +119 -0
  57. data/lib/ace/task/molecules/task_plan_cache.rb +190 -0
  58. data/lib/ace/task/molecules/task_plan_generator.rb +141 -0
  59. data/lib/ace/task/molecules/task_plan_prompt_builder.rb +91 -0
  60. data/lib/ace/task/molecules/task_reparenter.rb +247 -0
  61. data/lib/ace/task/molecules/task_resolver.rb +115 -0
  62. data/lib/ace/task/molecules/task_scanner.rb +129 -0
  63. data/lib/ace/task/molecules/task_structure_validator.rb +154 -0
  64. data/lib/ace/task/organisms/task_doctor.rb +199 -0
  65. data/lib/ace/task/organisms/task_manager.rb +353 -0
  66. data/lib/ace/task/version.rb +7 -0
  67. data/lib/ace/task.rb +37 -0
  68. metadata +197 -0
@@ -0,0 +1,353 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../molecules/task_config_loader"
4
+ require_relative "../molecules/task_scanner"
5
+ require_relative "../molecules/task_resolver"
6
+ require_relative "../molecules/task_loader"
7
+ require_relative "../molecules/task_creator"
8
+ require_relative "../molecules/subtask_creator"
9
+ require_relative "../molecules/task_reparenter"
10
+ require_relative "../atoms/task_validation_rules"
11
+
12
+ module Ace
13
+ module Task
14
+ module Organisms
15
+ # Orchestrates all task CRUD operations.
16
+ # Entry point for task management with config-driven root directory.
17
+ class TaskManager
18
+ attr_reader :last_list_total, :last_folder_counts
19
+
20
+ # @param root_dir [String, nil] Override root directory for tasks
21
+ # @param config [Hash, nil] Override configuration
22
+ def initialize(root_dir: nil, config: nil)
23
+ @config = config || load_config
24
+ @root_dir = root_dir || resolve_root_dir
25
+ @last_update_note = nil
26
+ end
27
+
28
+ attr_reader :last_update_note
29
+
30
+ # Create a new task.
31
+ # @param title [String] Task title
32
+ # @param status [String, nil] Initial status
33
+ # @param priority [String, nil] Priority level
34
+ # @param tags [Array<String>] Tags
35
+ # @param dependencies [Array<String>] Dependency task IDs
36
+ # @param use_llm_slug [Boolean] Whether to attempt LLM slug generation
37
+ # @return [Models::Task] Created task
38
+ def create(title, status: nil, priority: nil, tags: [], dependencies: [], use_llm_slug: false, estimate: nil)
39
+ ensure_root_dir
40
+ creator = Molecules::TaskCreator.new(root_dir: @root_dir, config: @config)
41
+ creator.create(title, status: status, priority: priority, tags: tags,
42
+ dependencies: dependencies, use_llm_slug: use_llm_slug, estimate: estimate)
43
+ end
44
+
45
+ # Show (load) a single task by reference, including subtasks.
46
+ # @param ref [String] Full ID, shortcut, or subtask reference
47
+ # @return [Models::Task, nil] Loaded task or nil if not found
48
+ def show(ref)
49
+ scan_result = resolve_scan_result(ref)
50
+ return nil unless scan_result
51
+
52
+ loader = Molecules::TaskLoader.new
53
+ loader.load(scan_result.dir_path,
54
+ id: scan_result.id,
55
+ special_folder: scan_result.special_folder)
56
+ end
57
+
58
+ # List tasks with optional filtering and sorting.
59
+ # @param status [String, nil] Filter by status
60
+ # @param in_folder [String, nil] Filter by special folder (default: "next" = root items only)
61
+ # @param tags [Array<String>] Filter by tags (any match)
62
+ # @param filters [Array<String>, nil] Generic filter strings
63
+ # @param sort [String] Sort order: "smart", "id", "priority", "created" (default: "smart")
64
+ # @return [Array<Models::Task>] List of tasks
65
+ def list(status: nil, in_folder: "next", tags: [], filters: nil, sort: "smart")
66
+ scanner = Molecules::TaskScanner.new(@root_dir)
67
+ scan_results = scanner.scan_in_folder(in_folder)
68
+ @last_list_total = scanner.last_scan_total
69
+ @last_folder_counts = scanner.last_folder_counts
70
+
71
+ loader = Molecules::TaskLoader.new
72
+ tasks = scan_results.filter_map do |sr|
73
+ loader.load(sr.dir_path, id: sr.id, special_folder: sr.special_folder)
74
+ end
75
+
76
+ # Apply legacy filters
77
+ tasks = tasks.select { |t| t.status == status } if status
78
+ tasks = filter_by_tags(tasks, tags) if tags.any?
79
+
80
+ # Apply generic --filter specs
81
+ if filters && !filters.empty?
82
+ filter_specs = Ace::Support::Items::Atoms::FilterParser.parse(filters)
83
+ tasks = Ace::Support::Items::Molecules::FilterApplier.apply(
84
+ tasks, filter_specs, value_accessor: method(:task_value_accessor)
85
+ )
86
+ end
87
+
88
+ apply_sort(tasks, sort)
89
+ end
90
+
91
+ # Update a task's frontmatter fields and optionally move to a folder.
92
+ # @param ref [String] Task reference
93
+ # @param set [Hash] Fields to set (supports dot-notation for nested keys)
94
+ # @param add [Hash] Fields to add to arrays
95
+ # @param remove [Hash] Fields to remove from arrays
96
+ # @param move_to [String, nil] Target folder to move to (archive, maybe, anytime, next/root//)
97
+ # @param move_as_child_of [String, nil] Reparent: parent ref, "none" (promote), "self" (orchestrator)
98
+ # @return [Models::Task, nil] Updated task or nil if not found
99
+ def update(ref, set: {}, add: {}, remove: {}, move_to: nil, move_as_child_of: nil)
100
+ @last_update_note = nil
101
+ scan_result = resolve_scan_result(ref)
102
+ return nil unless scan_result
103
+
104
+ loader = Molecules::TaskLoader.new
105
+ task = loader.load(scan_result.dir_path,
106
+ id: scan_result.id,
107
+ special_folder: scan_result.special_folder)
108
+ return nil unless task
109
+
110
+ # Apply field updates if any
111
+ has_field_updates = [set, add, remove].any? { |h| h && !h.empty? }
112
+ if has_field_updates
113
+ Ace::Support::Items::Molecules::FieldUpdater.update(
114
+ task.file_path, set: set, add: add, remove: remove
115
+ )
116
+ end
117
+
118
+ # Apply move if requested
119
+ current_path = task.path
120
+ current_special = task.special_folder
121
+ current_id = task.id
122
+ if move_to
123
+ if archive_move_for_subtask?(task, move_to)
124
+ result = handle_subtask_archive_move(task, loader)
125
+ current_path = result[:path]
126
+ current_special = result[:special_folder]
127
+ current_id = result[:id]
128
+ else
129
+ mover = Ace::Support::Items::Molecules::FolderMover.new(@root_dir)
130
+ new_path = if Ace::Support::Items::Atoms::SpecialFolderDetector.move_to_root?(move_to)
131
+ mover.move_to_root(task)
132
+ else
133
+ archive_date = parse_archive_date(task)
134
+ mover.move(task, to: move_to, date: archive_date)
135
+ end
136
+ current_path = new_path
137
+ current_special = Ace::Support::Items::Atoms::SpecialFolderDetector.detect_in_path(
138
+ new_path, root: @root_dir
139
+ )
140
+ end
141
+ end
142
+
143
+ # Reparent if requested (mutually exclusive with move_to)
144
+ if move_as_child_of
145
+ reparenter = Molecules::TaskReparenter.new(root_dir: @root_dir, config: @config)
146
+ resolve_fn = ->(r) { show(r) }
147
+ # Reload task from current path before reparenting (may have been field-updated)
148
+ task_for_reparent = loader.load(current_path, id: task.id, special_folder: current_special)
149
+ return reparenter.reparent(task_for_reparent, target: move_as_child_of, resolve_ref: resolve_fn)
150
+ end
151
+
152
+ # Auto-archive hook: if a subtask status was set to terminal,
153
+ # check if all siblings are terminal and auto-move parent to archive
154
+ if set && set.key?("status")
155
+ check_auto_archive(task, set["status"], loader)
156
+ end
157
+
158
+ # Reload and return updated task
159
+ loader.load(current_path, id: current_id, special_folder: current_special)
160
+ end
161
+
162
+ # Create a subtask within a parent task.
163
+ # @param parent_ref [String] Parent task reference
164
+ # @param title [String] Subtask title
165
+ # @param status [String, nil] Initial status
166
+ # @param priority [String, nil] Priority level
167
+ # @param tags [Array<String>] Tags
168
+ # @return [Models::Task, nil] Created subtask or nil if parent not found
169
+ def create_subtask(parent_ref, title, status: nil, priority: nil, tags: [], estimate: nil)
170
+ parent = show(parent_ref)
171
+ return nil unless parent
172
+
173
+ subtask_creator = Molecules::SubtaskCreator.new(config: @config)
174
+ subtask_creator.create(parent, title, status: status, priority: priority, tags: tags, estimate: estimate)
175
+ end
176
+
177
+ # Get the root directory.
178
+ # @return [String] Absolute path to tasks root
179
+ attr_reader :root_dir
180
+
181
+ private
182
+
183
+ def load_config
184
+ Molecules::TaskConfigLoader.load
185
+ end
186
+
187
+ def resolve_root_dir
188
+ Molecules::TaskConfigLoader.root_dir(@config)
189
+ end
190
+
191
+ def ensure_root_dir
192
+ require "fileutils"
193
+ FileUtils.mkdir_p(@root_dir) unless Dir.exist?(@root_dir)
194
+ end
195
+
196
+ def resolve_scan_result(ref)
197
+ scanner = Molecules::TaskScanner.new(@root_dir)
198
+ scan_results = scanner.scan
199
+ resolver = Molecules::TaskResolver.new(scan_results)
200
+ resolver.resolve(ref)
201
+ end
202
+
203
+ def apply_sort(tasks, sort_mode)
204
+ case sort_mode
205
+ when "smart"
206
+ smart_sort(tasks)
207
+ when "id"
208
+ tasks.sort_by(&:id)
209
+ when "priority"
210
+ priority_order = {"critical" => 0, "high" => 1, "medium" => 2, "low" => 3}
211
+ tasks.sort_by { |t| priority_order[t.priority] || 99 }
212
+ when "created"
213
+ tasks.sort_by { |t| t.created_at || Time.at(0) }
214
+ else
215
+ tasks
216
+ end
217
+ end
218
+
219
+ def smart_sort(tasks)
220
+ Ace::Support::Items::Molecules::SmartSorter.sort(
221
+ tasks,
222
+ score_fn: method(:compute_task_score),
223
+ pin_accessor: ->(t) { t.metadata&.dig("position") }
224
+ )
225
+ end
226
+
227
+ def compute_task_score(task)
228
+ weight = Ace::Support::Items::Atoms::SortScoreCalculator.priority_weight(task.priority)
229
+ age = if task.created_at
230
+ [(Time.now - task.created_at) / 86_400.0, 0].max
231
+ else
232
+ 0
233
+ end
234
+ Ace::Support::Items::Atoms::SortScoreCalculator.compute(
235
+ priority_weight: weight,
236
+ age_days: age,
237
+ status: task.status
238
+ )
239
+ end
240
+
241
+ def filter_by_tags(tasks, tags)
242
+ return tasks if tags.empty?
243
+
244
+ tasks.select do |task|
245
+ tags.any? { |tag| task.tags.include?(tag) }
246
+ end
247
+ end
248
+
249
+ # Auto-archive: if a subtask reaches terminal status and all siblings
250
+ # in the parent directory are also terminal, move the parent to archive.
251
+ def check_auto_archive(task, new_status, loader)
252
+ terminal = Ace::Support::Items::Atoms::FolderCompletionDetector::TERMINAL_STATUSES
253
+ return unless terminal.include?(new_status.to_s.downcase)
254
+
255
+ # Only applies to subtasks (task dir is nested inside a parent dir)
256
+ parent_dir = File.dirname(task.path)
257
+ return if File.expand_path(parent_dir) == File.expand_path(@root_dir)
258
+
259
+ # Check if all specs in the parent dir (recursive for subtask subdirs) are terminal
260
+ return unless Ace::Support::Items::Atoms::FolderCompletionDetector.all_terminal?(
261
+ parent_dir, recursive: true
262
+ )
263
+
264
+ # Auto-move the parent folder to archive
265
+ parent_stub = Struct.new(:path).new(parent_dir)
266
+ mover = Ace::Support::Items::Molecules::FolderMover.new(@root_dir)
267
+ mover.move(parent_stub, to: "archive")
268
+ end
269
+
270
+ def parse_archive_date(task)
271
+ raw = task.metadata["completed_at"] || task.metadata["created_at"]
272
+ return nil unless raw
273
+
274
+ case raw
275
+ when Time then raw
276
+ when DateTime then raw.to_time
277
+ else begin
278
+ Time.parse(raw.to_s)
279
+ rescue
280
+ nil
281
+ end
282
+ end
283
+ end
284
+
285
+ def archive_move_for_subtask?(task, move_to)
286
+ normalized = Ace::Support::Items::Atoms::SpecialFolderDetector.normalize(move_to)
287
+ task.subtask? && normalized == "_archive"
288
+ end
289
+
290
+ def handle_subtask_archive_move(task, loader)
291
+ parent = show(task.parent_id)
292
+ unless parent
293
+ @last_update_note = "Subtask #{task.id} was not archived because parent task '#{task.parent_id}' was not found."
294
+ return {
295
+ path: task.path,
296
+ special_folder: task.special_folder,
297
+ id: task.id
298
+ }
299
+ end
300
+
301
+ parent_with_subtasks = loader.load(parent.path, id: parent.id, special_folder: parent.special_folder)
302
+ subtasks = parent_with_subtasks&.subtasks || []
303
+ all_terminal = subtasks.any? &&
304
+ subtasks.all? { |st| Atoms::TaskValidationRules.terminal_status?(st.status.to_s.downcase) }
305
+
306
+ unless all_terminal
307
+ @last_update_note = "Subtask #{task.id} was not archived because sibling subtasks are not all terminal."
308
+ return {
309
+ path: task.path,
310
+ special_folder: task.special_folder,
311
+ id: task.id
312
+ }
313
+ end
314
+
315
+ unless Atoms::TaskValidationRules.terminal_status?(parent.status.to_s.downcase)
316
+ Ace::Support::Items::Molecules::FieldUpdater.update(
317
+ parent.file_path, set: {"status" => "done"}
318
+ )
319
+ parent = loader.load(parent.path, id: parent.id, special_folder: parent.special_folder)
320
+ end
321
+
322
+ mover = Ace::Support::Items::Molecules::FolderMover.new(@root_dir)
323
+ new_parent_path = mover.move(parent, to: "archive", date: parse_archive_date(parent))
324
+ new_special_folder = Ace::Support::Items::Atoms::SpecialFolderDetector.detect_in_path(
325
+ new_parent_path, root: @root_dir
326
+ )
327
+
328
+ @last_update_note = "Archived parent task #{parent.id} because all subtasks are terminal."
329
+ {
330
+ path: File.join(new_parent_path, File.basename(task.path)),
331
+ special_folder: new_special_folder,
332
+ id: task.id
333
+ }
334
+ end
335
+
336
+ # Value accessor for FilterApplier
337
+ def task_value_accessor(item, key)
338
+ case key
339
+ when "status" then item.status
340
+ when "title" then item.title
341
+ when "tags" then item.tags
342
+ when "id" then item.id
343
+ when "priority" then item.priority
344
+ when "estimate" then item.estimate
345
+ when "special_folder" then item.special_folder
346
+ else
347
+ item.metadata[key] || item.metadata[key.to_sym] if item.respond_to?(:metadata) && item.metadata
348
+ end
349
+ end
350
+ end
351
+ end
352
+ end
353
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ace
4
+ module Task
5
+ VERSION = "0.31.0"
6
+ end
7
+ end
data/lib/ace/task.rb ADDED
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "task/version"
4
+
5
+ # Dependencies
6
+ require "ace/support/items"
7
+ require "ace/b36ts"
8
+
9
+ # Atoms
10
+ require_relative "task/atoms/task_id_formatter"
11
+ require_relative "task/atoms/task_file_pattern"
12
+ require_relative "task/atoms/task_frontmatter_defaults"
13
+
14
+ # Models
15
+ require_relative "task/models/task"
16
+
17
+ # Molecules
18
+ require_relative "task/molecules/task_config_loader"
19
+ require_relative "task/molecules/task_scanner"
20
+ require_relative "task/molecules/task_resolver"
21
+ require_relative "task/molecules/task_loader"
22
+ require_relative "task/molecules/task_creator"
23
+ require_relative "task/molecules/subtask_creator"
24
+ require_relative "task/molecules/task_display_formatter"
25
+ require_relative "task/molecules/path_utils"
26
+ require_relative "task/molecules/task_plan_cache"
27
+ require_relative "task/molecules/task_plan_generator"
28
+
29
+ # Organisms
30
+ require_relative "task/organisms/task_manager"
31
+
32
+ module Ace
33
+ # Task provides B36TS-based task management with type-marked IDs.
34
+ # Tasks use the format xxx.t.yyy where xxx and yyy are 3-char b36ts components.
35
+ module Task
36
+ end
37
+ end
metadata ADDED
@@ -0,0 +1,197 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ace-task
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.31.0
5
+ platform: ruby
6
+ authors:
7
+ - Michal Czyz
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: ace-support-core
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '0.25'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '0.25'
26
+ - !ruby/object:Gem::Dependency
27
+ name: ace-support-fs
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '0.2'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.2'
40
+ - !ruby/object:Gem::Dependency
41
+ name: ace-support-items
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0.3'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '0.3'
54
+ - !ruby/object:Gem::Dependency
55
+ name: ace-support-markdown
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.2'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '0.2'
68
+ - !ruby/object:Gem::Dependency
69
+ name: ace-b36ts
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '0.7'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '0.7'
82
+ - !ruby/object:Gem::Dependency
83
+ name: ace-support-cli
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '0.3'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '0.3'
96
+ description: Behavioral spec-based task management with compact IDs, subtask trees,
97
+ AI-powered implementation plans, and automated health checks. Same CLI for developers
98
+ and coding agents.
99
+ email:
100
+ - mc@cs3b.com
101
+ executables:
102
+ - ace-task
103
+ extensions: []
104
+ extra_rdoc_files: []
105
+ files:
106
+ - ".ace-defaults/nav/protocols/skill-sources/ace-task.yml"
107
+ - ".ace-defaults/nav/protocols/wfi-sources/ace-task.yml"
108
+ - ".ace-defaults/task/config.yml"
109
+ - CHANGELOG.md
110
+ - README.md
111
+ - Rakefile
112
+ - exe/ace-task
113
+ - handbook/guides/task-definition.g.md
114
+ - handbook/skills/as-bug-analyze/SKILL.md
115
+ - handbook/skills/as-bug-fix/SKILL.md
116
+ - handbook/skills/as-task-document-unplanned/SKILL.md
117
+ - handbook/skills/as-task-draft/SKILL.md
118
+ - handbook/skills/as-task-finder/SKILL.md
119
+ - handbook/skills/as-task-plan/SKILL.md
120
+ - handbook/skills/as-task-review-questions/SKILL.md
121
+ - handbook/skills/as-task-review/SKILL.md
122
+ - handbook/skills/as-task-update/SKILL.md
123
+ - handbook/skills/as-task-work/SKILL.md
124
+ - handbook/templates/task/draft.template.md
125
+ - handbook/templates/task/file-modification-checklist.template.md
126
+ - handbook/templates/task/technical-approach.template.md
127
+ - handbook/workflow-instructions/bug/analyze.wf.md
128
+ - handbook/workflow-instructions/bug/fix.wf.md
129
+ - handbook/workflow-instructions/task/document-unplanned.wf.md
130
+ - handbook/workflow-instructions/task/draft.wf.md
131
+ - handbook/workflow-instructions/task/finder.wf.md
132
+ - handbook/workflow-instructions/task/plan.wf.md
133
+ - handbook/workflow-instructions/task/review-plan.wf.md
134
+ - handbook/workflow-instructions/task/review-questions.wf.md
135
+ - handbook/workflow-instructions/task/review-work.wf.md
136
+ - handbook/workflow-instructions/task/review.wf.md
137
+ - handbook/workflow-instructions/task/update.wf.md
138
+ - handbook/workflow-instructions/task/work.wf.md
139
+ - lib/ace/task.rb
140
+ - lib/ace/task/atoms/task_file_pattern.rb
141
+ - lib/ace/task/atoms/task_frontmatter_defaults.rb
142
+ - lib/ace/task/atoms/task_id_formatter.rb
143
+ - lib/ace/task/atoms/task_validation_rules.rb
144
+ - lib/ace/task/cli.rb
145
+ - lib/ace/task/cli/commands/create.rb
146
+ - lib/ace/task/cli/commands/doctor.rb
147
+ - lib/ace/task/cli/commands/list.rb
148
+ - lib/ace/task/cli/commands/plan.rb
149
+ - lib/ace/task/cli/commands/show.rb
150
+ - lib/ace/task/cli/commands/status.rb
151
+ - lib/ace/task/cli/commands/update.rb
152
+ - lib/ace/task/models/task.rb
153
+ - lib/ace/task/molecules/path_utils.rb
154
+ - lib/ace/task/molecules/subtask_creator.rb
155
+ - lib/ace/task/molecules/task_config_loader.rb
156
+ - lib/ace/task/molecules/task_creator.rb
157
+ - lib/ace/task/molecules/task_display_formatter.rb
158
+ - lib/ace/task/molecules/task_doctor_fixer.rb
159
+ - lib/ace/task/molecules/task_doctor_reporter.rb
160
+ - lib/ace/task/molecules/task_frontmatter_validator.rb
161
+ - lib/ace/task/molecules/task_loader.rb
162
+ - lib/ace/task/molecules/task_plan_cache.rb
163
+ - lib/ace/task/molecules/task_plan_generator.rb
164
+ - lib/ace/task/molecules/task_plan_prompt_builder.rb
165
+ - lib/ace/task/molecules/task_reparenter.rb
166
+ - lib/ace/task/molecules/task_resolver.rb
167
+ - lib/ace/task/molecules/task_scanner.rb
168
+ - lib/ace/task/molecules/task_structure_validator.rb
169
+ - lib/ace/task/organisms/task_doctor.rb
170
+ - lib/ace/task/organisms/task_manager.rb
171
+ - lib/ace/task/version.rb
172
+ homepage: https://github.com/cs3b/ace
173
+ licenses:
174
+ - MIT
175
+ metadata:
176
+ allowed_push_host: https://rubygems.org
177
+ homepage_uri: https://github.com/cs3b/ace
178
+ source_code_uri: https://github.com/cs3b/ace/tree/main/ace-task/
179
+ changelog_uri: https://github.com/cs3b/ace/blob/main/ace-task/CHANGELOG.md
180
+ rdoc_options: []
181
+ require_paths:
182
+ - lib
183
+ required_ruby_version: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: 3.2.0
188
+ required_rubygems_version: !ruby/object:Gem::Requirement
189
+ requirements:
190
+ - - ">="
191
+ - !ruby/object:Gem::Version
192
+ version: '0'
193
+ requirements: []
194
+ rubygems_version: 3.6.9
195
+ specification_version: 4
196
+ summary: Draft, organize, and tackle tasks — for you and your agents
197
+ test_files: []