Class: Aias::CLI
- Inherits:
-
Thor
- Object
- Thor
- Aias::CLI
- Defined in:
- lib/aias/cli.rb,
lib/aias/cli/add.rb,
lib/aias/cli/last.rb,
lib/aias/cli/list.rb,
lib/aias/cli/next.rb,
lib/aias/cli/show.rb,
lib/aias/cli/check.rb,
lib/aias/cli/clear.rb,
lib/aias/cli/remove.rb,
lib/aias/cli/update.rb,
lib/aias/cli/dry_run.rb,
lib/aias/cli/install.rb,
lib/aias/cli/version.rb,
lib/aias/cli/uninstall.rb
Constant Summary collapse
- AIA_CONFIG_SRC =
Paths::AIA_CONFIG
- AIA_SCHEDULE_DIR =
Paths::SCHEDULE_DIR
- AIA_SCHEDULE_CFG =
Paths::SCHEDULE_CFG
Class Method Summary collapse
Instance Method Summary collapse
- #add(path) ⇒ Object
- #check ⇒ Object
- #clear ⇒ Object
- #dry_run ⇒ Object
-
#help(command = nil, subcommand = false) ⇒ Object
--------------------------------------------------------------------------- help — appends crontab reference when listing all commands ---------------------------------------------------------------------------.
- #install(*patterns) ⇒ Object
- #last_run(n = "5") ⇒ Object
- #list ⇒ Object
- #remove(prompt_id) ⇒ Object
- #show(prompt_id) ⇒ Object
- #uninstall ⇒ Object
- #upcoming(n = "5") ⇒ Object
- #update ⇒ Object
- #version ⇒ Object
Class Method Details
.exit_on_failure? ⇒ Boolean
7 |
# File 'lib/aias/cli.rb', line 7 def self.exit_on_failure? = true |
Instance Method Details
#add(path) ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/aias/cli/add.rb', line 6 def add(path) absolute = File.(path) unless File.file?(absolute) && absolute.end_with?(".md") say_error "aias [error] '#{path}' must be an existing .md file" exit(1) end prompts_dir = effective_prompts_dir_for(absolute) result = PromptScanner.new(prompts_dir: prompts_dir).scan_one(absolute) vr = validator.validate(result) unless vr.valid? say_error "aias [error] #{result.prompt_id}: #{vr.errors.join('; ')}" exit(1) end cron_line = builder.build(result, prompts_dir: prompts_dir) manager.ensure_log_directories([result.prompt_id]) manager.add_job(cron_line, result.prompt_id) say "aias: added #{result.prompt_id} (#{CronDescriber.display(result.schedule)})" rescue Aias::Error => e say_error "aias [error] #{e.}" exit(1) end |
#check ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/aias/cli/check.rb', line 6 def check results = scanner.scan installed = manager.installed_jobs installed_ids = installed.map { |j| j[:prompt_id] }.to_set valid, invalid = partition_results(results) discovered_ids = valid.map { |r, _| r.prompt_id }.to_set new_jobs = discovered_ids - installed_ids orphaned_jobs = installed_ids - discovered_ids say "=== aias check ===" say "" unless invalid.empty? say "INVALID (would be skipped by update):" invalid.each { |r, vr| say " #{r.prompt_id}: #{vr.errors.join('; ')}" } say "" end unless new_jobs.empty? say "NEW (not yet installed — run `aias update`):" new_jobs.each do |id| r = valid.find { |result, _| result.prompt_id == id }&.first sched = r ? " #{CronDescriber.display(r.schedule)}" : "" say " + #{id}#{sched}" end say "" end unless orphaned_jobs.empty? say "ORPHANED (installed but no longer scheduled):" orphaned_jobs.each { |id| say " - #{id}" } say "" end if invalid.empty? && new_jobs.empty? && orphaned_jobs.empty? say "OK — crontab is in sync with scheduled prompts" end rescue Aias::Error => e say_error "aias [error] #{e.}" exit(1) end |
#clear ⇒ Object
6 7 8 9 |
# File 'lib/aias/cli/clear.rb', line 6 def clear manager.clear say "aias: all managed crontab entries removed" end |
#dry_run ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# File 'lib/aias/cli/dry_run.rb', line 6 def dry_run results = scanner.scan valid, invalid = partition_results(results) invalid.each { |r, vr| $stderr.puts "aias [skip] #{r.prompt_id}: #{vr.errors.join('; ')}" } if valid.empty? say "aias: no valid scheduled prompts found" return end cron_lines = valid.map { |r, _vr| builder.build(r) } say manager.dry_run(cron_lines) rescue Aias::Error => e say_error "aias [error] #{e.}" exit(1) end |
#help(command = nil, subcommand = false) ⇒ Object
help — appends crontab reference when listing all commands
33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/aias/cli.rb', line 33 def help(command = nil, subcommand = false) super return if command say "" say "Crontab commands:" say " crontab -l # view current crontab" say " crontab -e # edit crontab in $EDITOR" say " EDITOR=nano crontab -e # edit with a specific editor" say " crontab -r # remove entire crontab" end |
#install(*patterns) ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/aias/cli/install.rb', line 18 def install(*patterns) env_vars = ENV.select { |k, _| k.end_with?("_API_KEY") || k.start_with?("AIA_") } env_vars["PATH"] = ENV["PATH"] env_vars["LANG"] = ENV["LANG"] if ENV["LANG"] env_vars["LC_ALL"] = ENV["LC_ALL"] if ENV["LC_ALL"] patterns.flat_map(&:split).map(&:upcase).each do |pattern| ENV.each { |k, v| env_vars[k] = v if File.fnmatch(pattern, k) } end env_file.install(env_vars) installed = env_vars.keys.sort say "aias: installed #{installed.join(', ')} into #{Paths::SCHEDULE_ENV}" FileUtils.mkdir_p(AIA_SCHEDULE_DIR, mode: 0o700) unless File.exist?(AIA_SCHEDULE_CFG) if File.exist?(AIA_CONFIG_SRC) FileUtils.cp(AIA_CONFIG_SRC, AIA_SCHEDULE_CFG) say "aias: copied #{AIA_CONFIG_SRC} → #{AIA_SCHEDULE_CFG}" else say "aias: #{AIA_CONFIG_SRC} not found — create #{AIA_SCHEDULE_CFG} manually" end say "" say "Review #{AIA_SCHEDULE_CFG} — these settings apply to all scheduled prompts." say "Prompt frontmatter overrides any setting in that file." end if ENV["AIA_PROMPTS__DIR"] dir = File.(ENV["AIA_PROMPTS__DIR"]) if ScheduleConfig.new.set_prompts_dir(dir) say "aias: set prompts.dir=#{dir} in #{AIA_SCHEDULE_CFG}" end end rescue Aias::Error => e say_error "aias [error] #{e.}" exit(1) end |
#last_run(n = "5") ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/aias/cli/last.rb', line 6 def last_run(n = "5") jobs = manager.installed_jobs.first(n.to_i) if jobs.empty? say "aias: no installed jobs" return end jobs.each do |job| log_stat = File.exist?(job[:log_path]) ? File.mtime(job[:log_path]).to_s : "never run" say "#{job[:prompt_id]}" say " schedule : #{CronDescriber.display(job[:cron_expr])}" say " last run : #{log_stat}" say " log : #{job[:log_path]}" say "" end say "(Pass N as argument to show N entries. Last-run time is derived from the log file modification timestamp.)" end |
#list ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 |
# File 'lib/aias/cli/list.rb', line 6 def list jobs = manager.installed_jobs if jobs.empty? say "aias: no installed jobs" return end say format("%-30s %-40s %s", "PROMPT ID", "SCHEDULE", "LOG") say "-" * 100 jobs.each do |job| say format("%-30s %-40s %s", job[:prompt_id], Aias::CronDescriber.display(job[:cron_expr]), job[:log_path]) end end |
#remove(prompt_id) ⇒ Object
6 7 8 9 10 11 12 |
# File 'lib/aias/cli/remove.rb', line 6 def remove(prompt_id) manager.remove_job(prompt_id) say "aias: removed #{prompt_id}" rescue Aias::Error => e say_error "aias [error] #{e.}" exit(1) end |
#show(prompt_id) ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 |
# File 'lib/aias/cli/show.rb', line 6 def show(prompt_id) job = manager.installed_jobs.find { |j| j[:prompt_id] == prompt_id } if job say "prompt_id : #{job[:prompt_id]}" say "schedule : #{CronDescriber.display(job[:cron_expr])}" say "log : #{job[:log_path]}" else say "aias: '#{prompt_id}' is not currently installed" exit(1) end end |
#uninstall ⇒ Object
6 7 8 9 10 11 12 13 |
# File 'lib/aias/cli/uninstall.rb', line 6 def uninstall env_file.uninstall say "aias: env vars removed from #{Paths::SCHEDULE_ENV}" say " #{AIA_SCHEDULE_DIR} is unchanged" rescue Aias::Error => e say_error "aias [error] #{e.}" exit(1) end |
#upcoming(n = "5") ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/aias/cli/next.rb', line 6 def upcoming(n = "5") jobs = manager.installed_jobs.first(n.to_i) if jobs.empty? say "aias: no installed jobs" return end now = Time.now jobs.each do |job| cron = Fugit.parse_cronish(job[:cron_expr]) next_time = cron ? cron.next_time(now).localtime.to_s : "unknown (invalid cron expression)" say "#{job[:prompt_id]}" say " schedule : #{CronDescriber.display(job[:cron_expr])}" say " next run : #{next_time}" say " log : #{job[:log_path]}" say "" end say "(Pass N as argument to show N entries.)" end |
#update ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/aias/cli/update.rb', line 6 def update results = scanner.scan valid, invalid = partition_results(results) invalid.each do |r, vr| $stderr.puts "aias [skip] #{r.prompt_id}: #{vr.errors.join('; ')}" end if valid.empty? say "aias: no valid scheduled prompts found — crontab not changed" return end cron_lines = valid.map { |r, _vr| builder.build(r, prompts_dir: [:prompts_dir]) } manager.ensure_log_directories(valid.map { |r, _vr| r.prompt_id }) manager.install(cron_lines) say "aias: installed #{valid.size} job(s)" \ "#{invalid.empty? ? '' : ", skipped #{invalid.size} invalid"}" rescue Aias::Error => e say_error "aias [error] #{e.}" exit(1) end |