ace-assign 0.37.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 (104) hide show
  1. checksums.yaml +7 -0
  2. data/.ace-defaults/assign/catalog/composition-rules.yml +211 -0
  3. data/.ace-defaults/assign/catalog/recipes/batch-tasks.recipe.yml +44 -0
  4. data/.ace-defaults/assign/catalog/recipes/documentation.recipe.yml +35 -0
  5. data/.ace-defaults/assign/catalog/recipes/fix-and-review.recipe.yml +32 -0
  6. data/.ace-defaults/assign/catalog/recipes/implement-simple.recipe.yml +29 -0
  7. data/.ace-defaults/assign/catalog/recipes/implement-with-pr.recipe.yml +48 -0
  8. data/.ace-defaults/assign/catalog/recipes/release-only.recipe.yml +34 -0
  9. data/.ace-defaults/assign/catalog/steps/apply-feedback.step.yml +22 -0
  10. data/.ace-defaults/assign/catalog/steps/commit.step.yml +22 -0
  11. data/.ace-defaults/assign/catalog/steps/create-pr.step.yml +28 -0
  12. data/.ace-defaults/assign/catalog/steps/create-retro.step.yml +22 -0
  13. data/.ace-defaults/assign/catalog/steps/fix-tests.step.yml +22 -0
  14. data/.ace-defaults/assign/catalog/steps/lint.step.yml +22 -0
  15. data/.ace-defaults/assign/catalog/steps/mark-task-done.step.yml +57 -0
  16. data/.ace-defaults/assign/catalog/steps/onboard-base.step.yml +19 -0
  17. data/.ace-defaults/assign/catalog/steps/onboard.step.yml +19 -0
  18. data/.ace-defaults/assign/catalog/steps/plan-task.step.yml +17 -0
  19. data/.ace-defaults/assign/catalog/steps/pre-commit-review.step.yml +34 -0
  20. data/.ace-defaults/assign/catalog/steps/push-to-remote.step.yml +28 -0
  21. data/.ace-defaults/assign/catalog/steps/rebase-with-main.step.yml +28 -0
  22. data/.ace-defaults/assign/catalog/steps/reflect-and-refactor.step.yml +57 -0
  23. data/.ace-defaults/assign/catalog/steps/release-minor.step.yml +23 -0
  24. data/.ace-defaults/assign/catalog/steps/release.step.yml +23 -0
  25. data/.ace-defaults/assign/catalog/steps/reorganize-commits.step.yml +28 -0
  26. data/.ace-defaults/assign/catalog/steps/research.step.yml +19 -0
  27. data/.ace-defaults/assign/catalog/steps/review-pr.step.yml +22 -0
  28. data/.ace-defaults/assign/catalog/steps/security-audit.step.yml +22 -0
  29. data/.ace-defaults/assign/catalog/steps/split-subtree-root.step.yml +25 -0
  30. data/.ace-defaults/assign/catalog/steps/squash-changelog.step.yml +28 -0
  31. data/.ace-defaults/assign/catalog/steps/task-load.step.yml +29 -0
  32. data/.ace-defaults/assign/catalog/steps/update-docs.step.yml +38 -0
  33. data/.ace-defaults/assign/catalog/steps/update-pr-desc.step.yml +28 -0
  34. data/.ace-defaults/assign/catalog/steps/verify-e2e.step.yml +42 -0
  35. data/.ace-defaults/assign/catalog/steps/verify-test-suite.step.yml +48 -0
  36. data/.ace-defaults/assign/catalog/steps/verify-test.step.yml +36 -0
  37. data/.ace-defaults/assign/catalog/steps/work-on-task.step.yml +23 -0
  38. data/.ace-defaults/assign/config.yml +48 -0
  39. data/.ace-defaults/assign/presets/fix-bug.yml +65 -0
  40. data/.ace-defaults/assign/presets/quick-implement.yml +41 -0
  41. data/.ace-defaults/assign/presets/release-only.yml +35 -0
  42. data/.ace-defaults/assign/presets/work-on-docs.yml +41 -0
  43. data/.ace-defaults/assign/presets/work-on-task.yml +179 -0
  44. data/.ace-defaults/nav/protocols/skill-sources/ace-assign.yml +19 -0
  45. data/.ace-defaults/nav/protocols/wfi-sources/ace-assign.yml +19 -0
  46. data/CHANGELOG.md +1415 -0
  47. data/README.md +87 -0
  48. data/Rakefile +16 -0
  49. data/docs/exit-codes.md +61 -0
  50. data/docs/getting-started.md +121 -0
  51. data/docs/handbook.md +40 -0
  52. data/docs/usage.md +224 -0
  53. data/exe/ace-assign +16 -0
  54. data/handbook/guides/fork-context.g.md +231 -0
  55. data/handbook/skills/as-assign-compose/SKILL.md +24 -0
  56. data/handbook/skills/as-assign-create/SKILL.md +23 -0
  57. data/handbook/skills/as-assign-drive/SKILL.md +24 -0
  58. data/handbook/skills/as-assign-prepare/SKILL.md +23 -0
  59. data/handbook/skills/as-assign-recover-fork/SKILL.md +22 -0
  60. data/handbook/skills/as-assign-run-in-batches/SKILL.md +23 -0
  61. data/handbook/skills/as-assign-start/SKILL.md +25 -0
  62. data/handbook/workflow-instructions/assign/compose.wf.md +256 -0
  63. data/handbook/workflow-instructions/assign/create.wf.md +215 -0
  64. data/handbook/workflow-instructions/assign/drive.wf.md +666 -0
  65. data/handbook/workflow-instructions/assign/prepare.wf.md +469 -0
  66. data/handbook/workflow-instructions/assign/recover-fork.wf.md +233 -0
  67. data/handbook/workflow-instructions/assign/run-in-batches.wf.md +212 -0
  68. data/handbook/workflow-instructions/assign/start.wf.md +46 -0
  69. data/lib/ace/assign/atoms/assign_frontmatter_parser.rb +173 -0
  70. data/lib/ace/assign/atoms/catalog_loader.rb +101 -0
  71. data/lib/ace/assign/atoms/composition_rules.rb +219 -0
  72. data/lib/ace/assign/atoms/number_generator.rb +110 -0
  73. data/lib/ace/assign/atoms/preset_expander.rb +277 -0
  74. data/lib/ace/assign/atoms/step_file_parser.rb +207 -0
  75. data/lib/ace/assign/atoms/step_numbering.rb +227 -0
  76. data/lib/ace/assign/atoms/step_sorter.rb +66 -0
  77. data/lib/ace/assign/atoms/tree_formatter.rb +106 -0
  78. data/lib/ace/assign/cli/commands/add.rb +102 -0
  79. data/lib/ace/assign/cli/commands/assignment_target.rb +55 -0
  80. data/lib/ace/assign/cli/commands/create.rb +63 -0
  81. data/lib/ace/assign/cli/commands/fail.rb +43 -0
  82. data/lib/ace/assign/cli/commands/finish.rb +88 -0
  83. data/lib/ace/assign/cli/commands/fork_run.rb +229 -0
  84. data/lib/ace/assign/cli/commands/list.rb +166 -0
  85. data/lib/ace/assign/cli/commands/retry_cmd.rb +42 -0
  86. data/lib/ace/assign/cli/commands/select.rb +45 -0
  87. data/lib/ace/assign/cli/commands/start.rb +40 -0
  88. data/lib/ace/assign/cli/commands/status.rb +407 -0
  89. data/lib/ace/assign/cli.rb +144 -0
  90. data/lib/ace/assign/models/assignment.rb +107 -0
  91. data/lib/ace/assign/models/assignment_info.rb +66 -0
  92. data/lib/ace/assign/models/queue_state.rb +326 -0
  93. data/lib/ace/assign/models/step.rb +197 -0
  94. data/lib/ace/assign/molecules/assignment_discoverer.rb +57 -0
  95. data/lib/ace/assign/molecules/assignment_manager.rb +276 -0
  96. data/lib/ace/assign/molecules/fork_session_launcher.rb +102 -0
  97. data/lib/ace/assign/molecules/queue_scanner.rb +130 -0
  98. data/lib/ace/assign/molecules/skill_assign_source_resolver.rb +376 -0
  99. data/lib/ace/assign/molecules/step_renumberer.rb +227 -0
  100. data/lib/ace/assign/molecules/step_writer.rb +246 -0
  101. data/lib/ace/assign/organisms/assignment_executor.rb +1299 -0
  102. data/lib/ace/assign/version.rb +7 -0
  103. data/lib/ace/assign.rb +141 -0
  104. metadata +289 -0
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module Ace
6
+ module Assign
7
+ module CLI
8
+ module Commands
9
+ # List all assignments with state information
10
+ #
11
+ # @example List active assignments
12
+ # ace-assign list
13
+ #
14
+ # @example Include completed assignments
15
+ # ace-assign list --all
16
+ #
17
+ # @example Filter by task
18
+ # ace-assign list --task my-task
19
+ #
20
+ # @example JSON output
21
+ # ace-assign list --format json
22
+ class List < Ace::Support::Cli::Command
23
+ include Ace::Support::Cli::Base
24
+
25
+ # Column widths for table display
26
+ COL_ID = 10
27
+ COL_NAME = 25
28
+ COL_STATUS = 12
29
+ COL_PROGRESS = 10
30
+ COL_STEP = 20
31
+ COL_UPDATED = 15
32
+
33
+ # Status display labels
34
+ STATE_LABELS = {
35
+ running: "running",
36
+ paused: "paused",
37
+ completed: "completed",
38
+ failed: "failed",
39
+ empty: "empty"
40
+ }.freeze
41
+
42
+ desc "List all assignments"
43
+
44
+ option :all, aliases: ["-a"], type: :boolean, default: false, desc: "Include completed assignments"
45
+ option :task, aliases: ["-t"], desc: "Filter by task reference"
46
+ option :tree, type: :boolean, default: false, desc: "Show assignment hierarchy as tree"
47
+ option :format, aliases: ["-f"], desc: "Output format (table, json)", default: "table"
48
+ option :quiet, aliases: ["-q"], type: :boolean, default: false, desc: "Suppress non-essential output"
49
+ option :debug, aliases: ["-d"], type: :boolean, default: false, desc: "Show debug output"
50
+
51
+ def call(**options)
52
+ discoverer = Molecules::AssignmentDiscoverer.new
53
+ manager = Molecules::AssignmentManager.new
54
+ current_id = manager.current_id
55
+
56
+ all_assignments = discoverer.find_all(include_completed: true)
57
+ assignments = if options[:task]
58
+ all_assignments.select { |ai| ai.assignment.name == options[:task] }
59
+ .then { |filtered| options[:all] ? filtered : filtered.reject(&:completed?) }
60
+ elsif options[:all]
61
+ all_assignments
62
+ else
63
+ all_assignments.reject(&:completed?)
64
+ end
65
+
66
+ hidden_completed = options[:all] ? 0 : all_assignments.count(&:completed?)
67
+
68
+ if options[:tree]
69
+ print_tree(assignments)
70
+ elsif options[:format] == "json"
71
+ print_json(assignments, current_id: current_id)
72
+ else
73
+ print_table(assignments, current_id: current_id, hidden_completed: hidden_completed)
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ def print_tree(assignments)
80
+ puts Atoms::TreeFormatter.format(assignments)
81
+ end
82
+
83
+ def print_table(assignments, current_id:, hidden_completed:)
84
+ if assignments.empty?
85
+ if hidden_completed > 0
86
+ puts "No active assignments (#{hidden_completed} completed, use --all to show)"
87
+ else
88
+ puts "No assignments found."
89
+ end
90
+ return
91
+ end
92
+
93
+ # Header
94
+ puts format(
95
+ "%-#{COL_ID}s %-#{COL_NAME}s %-#{COL_STATUS}s %-#{COL_PROGRESS}s %-#{COL_STEP}s %s",
96
+ "ID", "NAME", "STATUS", "PROGRESS", "CURRENT STEP", "UPDATED"
97
+ )
98
+ puts "-" * 95
99
+
100
+ # Rows
101
+ assignments.each do |info|
102
+ marker = (info.id == current_id) ? "*" : " "
103
+ id_display = "#{marker}#{info.id}"
104
+
105
+ name_display = truncate(info.name.to_s, COL_NAME - 1)
106
+ state_display = STATE_LABELS[info.state] || info.state.to_s
107
+ step_display = truncate(info.current_step, COL_STEP - 1)
108
+ updated_display = format_relative_time(info.updated_at)
109
+
110
+ puts format(
111
+ "%-#{COL_ID}s %-#{COL_NAME}s %-#{COL_STATUS}s %-#{COL_PROGRESS}s %-#{COL_STEP}s %s",
112
+ id_display, name_display, state_display, info.progress, step_display, updated_display
113
+ )
114
+ end
115
+
116
+ puts
117
+ total = assignments.size + hidden_completed
118
+ if hidden_completed > 0
119
+ puts "#{assignments.size}/#{total} assignment(s) shown (use --all to include completed)"
120
+ else
121
+ puts "#{assignments.size} assignment(s) found"
122
+ end
123
+ puts "* = current selection" if current_id
124
+ end
125
+
126
+ def print_json(assignments, current_id:)
127
+ data = assignments.map do |info|
128
+ {
129
+ id: info.id,
130
+ name: info.name,
131
+ state: info.state.to_s,
132
+ progress: info.progress,
133
+ current_step: info.current_step,
134
+ updated_at: info.updated_at.iso8601,
135
+ is_current: info.id == current_id
136
+ }
137
+ end
138
+
139
+ puts JSON.pretty_generate(data)
140
+ end
141
+
142
+ def truncate(str, max_length)
143
+ return str if str.length <= max_length
144
+
145
+ str[0..max_length - 4] + "..."
146
+ end
147
+
148
+ def format_relative_time(time)
149
+ return "-" unless time
150
+
151
+ diff = Time.now - time
152
+ if diff < 60
153
+ "#{diff.to_i}s ago"
154
+ elsif diff < 3600
155
+ "#{(diff / 60).to_i}m ago"
156
+ elsif diff < 86_400
157
+ "#{(diff / 3600).to_i}h ago"
158
+ else
159
+ "#{(diff / 86_400).to_i}d ago"
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ace
4
+ module Assign
5
+ module CLI
6
+ module Commands
7
+ # Retry a failed step (creates new step linked to original)
8
+ class RetryCmd < Ace::Support::Cli::Command
9
+ include Ace::Support::Cli::Base
10
+ include AssignmentTarget
11
+
12
+ desc "Retry a step by creating a new linked step"
13
+
14
+ argument :step_ref, required: true, desc: "Step number to retry (e.g., 040)"
15
+ option :assignment, desc: "Target specific assignment ID"
16
+ option :quiet, aliases: ["-q"], type: :boolean, default: false, desc: "Suppress non-essential output"
17
+ option :debug, aliases: ["-d"], type: :boolean, default: false, desc: "Show debug output"
18
+
19
+ def call(step_ref:, **options)
20
+ target = resolve_assignment_target(options)
21
+ executor = build_executor_for_target(target)
22
+ result = executor.retry_step(step_ref)
23
+
24
+ unless options[:quiet]
25
+ retry_step = result[:retry]
26
+ original = result[:original]
27
+
28
+ puts "Created: steps/#{File.basename(retry_step.file_path)} (retry of #{original.number})"
29
+ puts "Original #{original.number}-#{original.name} preserved: #{original.status}"
30
+
31
+ if result[:state].current && result[:state].current.number != retry_step.number
32
+ puts "Note: Step #{result[:state].current.number} (#{result[:state].current.name}) must complete first"
33
+ end
34
+ end
35
+ end
36
+
37
+ private
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ace
4
+ module Assign
5
+ module CLI
6
+ module Commands
7
+ # Select an assignment as current (sets .current symlink)
8
+ #
9
+ # @example Select by ID
10
+ # ace-assign select abc123
11
+ #
12
+ # @example Clear current selection
13
+ # ace-assign select --clear
14
+ class Select < Ace::Support::Cli::Command
15
+ include Ace::Support::Cli::Base
16
+
17
+ desc "Select an assignment as the current active assignment"
18
+
19
+ argument :id, required: false, desc: "Assignment ID to select"
20
+ option :clear, type: :boolean, default: false, desc: "Clear current selection (revert to .latest)"
21
+ option :quiet, aliases: ["-q"], type: :boolean, default: false, desc: "Suppress non-essential output"
22
+ option :debug, aliases: ["-d"], type: :boolean, default: false, desc: "Show debug output"
23
+
24
+ def call(id: nil, **options)
25
+ manager = Molecules::AssignmentManager.new
26
+
27
+ if options[:clear]
28
+ manager.clear_current
29
+ puts "Cleared current assignment selection (will use most recent)" unless options[:quiet]
30
+ return
31
+ end
32
+
33
+ raise Error, "Assignment ID required. Usage: ace-assign select <id> or ace-assign select --clear" unless id
34
+
35
+ assignment = manager.set_current(id)
36
+
37
+ unless options[:quiet]
38
+ puts "Selected assignment: #{assignment.name} (#{assignment.id})"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ace
4
+ module Assign
5
+ module CLI
6
+ module Commands
7
+ # Start a pending step
8
+ class Start < Ace::Support::Cli::Command
9
+ include Ace::Support::Cli::Base
10
+ include AssignmentTarget
11
+
12
+ desc "Start next workable pending step"
13
+
14
+ argument :step, required: false, desc: "Step number to start (active assignment only)"
15
+ option :assignment, desc: "Target specific assignment ID"
16
+ option :quiet, aliases: ["-q"], type: :boolean, default: false, desc: "Suppress non-essential output"
17
+ option :debug, aliases: ["-d"], type: :boolean, default: false, desc: "Show debug output"
18
+
19
+ def call(step: nil, **options)
20
+ if step && options[:assignment]
21
+ raise Error, "Positional STEP targeting is only supported for active assignment. Use --assignment without STEP for cross-assignment start."
22
+ end
23
+
24
+ target = resolve_assignment_target(options)
25
+ executor = build_executor_for_target(target)
26
+ result = executor.start_step(step_number: step, fork_root: target.scope)
27
+
28
+ return if options[:quiet]
29
+
30
+ started = result[:started]
31
+ puts "Step #{started.number} (#{started.name}) started"
32
+ puts
33
+ puts "Instructions:"
34
+ puts started.instructions
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end