11# frozen_string_literal: true
22
3+ # Command Line Interface Specification
4+ # ====================================
5+ #
6+ # This module implements the core functionality for all agent-workflow commands:
7+ #
8+ # `agent-task` (CLI.start_task) is used to record coding tasks that will be
9+ # developed by AI agents. It has two modes of operation:
10+ #
11+ # 1) Starting a new agent branch (you pass the branch name as argument to agent-task)
12+ # 2) Recording a new task in the current branch (it needs to be a agent branch already)
13+
14+
315module AgentTask
416 # CLI exposes the main binaries as callable methods so the functionality
517 # can be reused programmatically. The methods here mirror the behavior
@@ -15,7 +27,7 @@ def devshell_names(root)
1527 # This handles all possible Nix syntax variations correctly
1628 begin
1729 # Get the current system first
18- system_result = `nix eval --impure --raw --expr 'builtins.currentSystem' 2>/dev/null ` . strip
30+ system_result = `nix eval --impure --raw --expr 'builtins.currentSystem' 2>#{ File :: NULL } ` . strip
1931 require 'English'
2032 if $CHILD_STATUS. success?
2133 current_system = system_result
@@ -186,7 +198,7 @@ def start_task(args, stdin: $stdin, stdout: $stdout)
186198 unless editor
187199 editors = %w[ nano pico micro vim helix vi ]
188200 editors . each do |ed |
189- if system ( " command -v #{ ed } > /dev/null 2>&1" )
201+ if system ( ' command' , '-v' , ed , out : File :: NULL , err : File :: NULL )
190202 editor = ed
191203 break
192204 end
@@ -204,36 +216,11 @@ def start_task(args, stdin: $stdin, stdout: $stdout)
204216 task_content . gsub! ( "\r \n " , "\n " )
205217 abort ( 'Aborted: empty task prompt.' ) if task_content . strip . empty?
206218
219+ tasks = AgentTasks . new ( repo . root )
207220 if start_new_branch
208- now = Time . now . utc
209- year = now . year
210- month = format ( '%02d' , now . month )
211- day = format ( '%02d' , now . day )
212- hour = format ( '%02d' , now . hour )
213- min = format ( '%02d' , now . min )
214- filename = "#{ day } -#{ hour } #{ min } -#{ branch_name } "
215- tasks_dir = File . join ( repo . root , '.agents' , 'tasks' , year . to_s , month )
216- FileUtils . mkdir_p ( tasks_dir )
217- task_file = File . join ( tasks_dir , filename )
218-
219- commit_msg = "Start-Agent-Branch: #{ branch_name } "
220- target_remote = repo . default_remote_http_url
221- commit_msg += "\n Target-Remote: #{ target_remote } " if target_remote
222- commit_msg += "\n Dev-Shell: #{ options [ :devshell ] } " if options [ :devshell ]
223-
224- File . binwrite ( task_file , task_content )
225- repo . commit_file ( task_file , commit_msg )
221+ tasks . record_initial_task ( task_content , branch_name , devshell : options [ :devshell ] )
226222 else
227- start_commit = repo . latest_agent_branch_commit
228- abort ( 'Error: Could not locate task start commit' ) unless start_commit
229- files = repo . files_in_commit ( start_commit )
230- abort ( 'Error: Task start commit should introduce exactly one file' ) unless files . length == 1
231- task_file = File . join ( repo . root , files . first )
232- File . open ( task_file , 'a' ) do |f |
233- f . write ( "\n --- FOLLOW UP TASK ---\n " )
234- f . write ( task_content )
235- end
236- repo . commit_file ( task_file , 'Follow-up task' )
223+ tasks . append_task ( task_content )
237224 end
238225
239226 push = nil
@@ -289,7 +276,7 @@ def run_get_task(args = [])
289276 end
290277
291278 if repos . length == 1 && repos [ 0 ] [ 0 ] . nil?
292- puts repos [ 0 ] [ 1 ] . agent_prompt ( autopush : options [ :autopush ] )
279+ puts repos [ 0 ] [ 1 ] . agent_prompt_with_autopush_setup ( autopush : options [ :autopush ] )
293280 return
294281 end
295282
@@ -298,7 +285,7 @@ def run_get_task(args = [])
298285 next if dir . nil?
299286
300287 begin
301- msg = at . agent_prompt ( autopush : options [ :autopush ] )
288+ msg = at . agent_prompt_with_autopush_setup ( autopush : options [ :autopush ] )
302289 dir_messages << [ dir , msg ] if msg && !msg . empty?
303290 rescue StandardError
304291 next
@@ -321,16 +308,39 @@ def run_get_task(args = [])
321308 exit 1
322309 end
323310
324- def run_start_work ( _args = [ ] )
311+ def run_start_work ( args = [ ] )
312+ require 'optparse'
325313 require_relative '../agent_tasks'
326314
315+ options = { }
316+ OptionParser . new do |opts |
317+ opts . on ( '--task-description=DESC' , 'Record the given task description' ) do |val |
318+ options [ :task_description ] = val
319+ end
320+ opts . on ( '--branch-name=NAME' , 'Name to use for the task description file' ) do |val |
321+ options [ :branch_name ] = val
322+ end
323+ end . parse! ( args )
324+
327325 repos = discover_repos
328326 if repos . empty?
329327 puts "Error: Could not find repository root from #{ Dir . pwd } "
330328 exit 1
331329 end
332330
333- repos . to_h . each_value ( &:prepare_work_environment )
331+ repos . to_h . each_value do |at |
332+ if options [ :task_description ]
333+ if at . on_task_branch?
334+ at . append_task ( options [ :task_description ] )
335+ else
336+ unless options [ :branch_name ]
337+ raise StandardError , 'Error: --branch-name is required when not on an agent branch'
338+ end
339+
340+ at . record_initial_task ( options [ :task_description ] , options [ :branch_name ] )
341+ end
342+ end
343+ end
334344 rescue StandardError => e
335345 puts e . message
336346 exit 1
0 commit comments