legion-tty 0.4.24 → 0.4.25

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab1a18bdbec9078051e19b84ede94cdaacb600ed12006674dc5696f711230349
4
- data.tar.gz: 6735876baede0f4fd45637f6a5cb0cef4284f7117298fa96cb97c8ca667a23d4
3
+ metadata.gz: c2baad187737411e10cb975111c2e766cd5b1b1c20bc27b7731cc990672597a0
4
+ data.tar.gz: e2d8eaabf4459beba0805f830025321c11fa70ea572aba05640b005e20dbd12a
5
5
  SHA512:
6
- metadata.gz: '01294f74d7805fb5aad66aa1538ffe38cb1f8b407aaaa662d90cacaf7f8c0b4e787257636007f8a74e88e1e13b76a5432da4a2ff47aad0dd5b6f81852116ddfb'
7
- data.tar.gz: 789298565c5285d7ef1787fd7dfbf8034b181f57f3cab243cd4b424712b0ec7251836e8c8f5ff3b79faf4b0d98c5416e919e8cf80c42df09adbe443d5b77905f
6
+ metadata.gz: 53b05dc182ec33a56c75c58a3936c9753b018c8a78ac3ae83f2fac588bafdf5ecb09026a9f70120b86d7685ce75d484bd993ef83efabf84ee0f63c4d81daefb8
7
+ data.tar.gz: 6f6849814bba37b3ebee42a88be6a927efaa913437d1c050586902aa4850cbf334df571e310818b6ddc711ff5d0828ef89e12cb8e249d9b704248e73898e200c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.4.25] - 2026-03-19
4
+
5
+ ### Added
6
+ - `/ask <question>` command: quick concise Q&A mode (instructs LLM to answer in one paragraph)
7
+ - `/define <term>` command: ask LLM for a concise definition
8
+ - `/status` command: comprehensive view of all 18 toggleable modes and settings
9
+ - `/prefs [key] [value]` command: persistent user preferences in `~/.legionio/prefs.json`
10
+ - `/about` command: show legion-tty name, version, author, license, GitHub URL
11
+ - `/commands [pattern]` command: list all slash commands with optional pattern filter and count
12
+
13
+ ### Changed
14
+ - Total slash commands: 103 (milestone)
15
+
3
16
  ## [0.4.24] - 2026-03-19
4
17
 
5
18
  ### Added
@@ -154,6 +154,32 @@ module Legion
154
154
  end
155
155
  :handled
156
156
  end
157
+
158
+ def handle_ask(input)
159
+ question = input.split(nil, 2)[1]&.strip
160
+ unless question && !question.empty?
161
+ @message_stream.add_message(role: :system, content: 'Usage: /ask <question>')
162
+ return :handled
163
+ end
164
+
165
+ @message_stream.add_message(role: :user, content: question)
166
+ @message_stream.add_message(role: :assistant, content: '')
167
+ send_to_llm("Answer the following question concisely in one paragraph: #{question}")
168
+ :handled
169
+ end
170
+
171
+ def handle_define(input)
172
+ term = input.split(nil, 2)[1]&.strip
173
+ unless term && !term.empty?
174
+ @message_stream.add_message(role: :system, content: 'Usage: /define <term>')
175
+ return :handled
176
+ end
177
+
178
+ @message_stream.add_message(role: :user, content: term)
179
+ @message_stream.add_message(role: :assistant, content: '')
180
+ send_to_llm("Define the following term concisely: #{term}")
181
+ :handled
182
+ end
157
183
  end
158
184
  end
159
185
  end
@@ -680,6 +680,49 @@ module Legion
680
680
  :handled
681
681
  end
682
682
 
683
+ def handle_about
684
+ lines = [
685
+ 'legion-tty',
686
+ 'Description : Rich terminal UI for the LegionIO async cognition engine',
687
+ "Version : #{Legion::TTY::VERSION}",
688
+ 'Author : Matthew Iverson (@Esity)',
689
+ 'License : Apache-2.0',
690
+ 'GitHub : https://github.com/LegionIO/legion-tty'
691
+ ]
692
+ @message_stream.add_message(role: :system, content: lines.join("\n"))
693
+ :handled
694
+ end
695
+
696
+ def handle_commands(input)
697
+ pattern = input.split(nil, 2)[1]&.strip&.downcase
698
+ cmds = filter_commands(pattern)
699
+ header = commands_header(pattern, cmds)
700
+ rows = format_command_columns(cmds)
701
+ @message_stream.add_message(role: :system, content: "#{header}\n#{rows.join("\n")}")
702
+ :handled
703
+ end
704
+
705
+ def filter_commands(pattern)
706
+ cmds = SLASH_COMMANDS.sort
707
+ return cmds unless pattern && !pattern.empty?
708
+
709
+ cmds.select { |c| c.include?(pattern) }
710
+ end
711
+
712
+ def commands_header(pattern, cmds)
713
+ if pattern && !pattern.empty?
714
+ "Commands matching '#{pattern}' (#{cmds.size}):"
715
+ else
716
+ "All commands (#{cmds.size}):"
717
+ end
718
+ end
719
+
720
+ def format_command_columns(cmds)
721
+ col_width = cmds.map(&:length).max.to_i + 2
722
+ cols = [terminal_width / [col_width, 1].max, 1].max
723
+ cmds.each_slice(cols).map { |row| row.map { |c| c.ljust(col_width) }.join.rstrip }
724
+ end
725
+
683
726
  def handle_freq
684
727
  words = collect_freq_words
685
728
  if words.empty?
@@ -707,6 +750,108 @@ module Legion
707
750
  format(FREQ_ROW_FMT, rank: rank, word: word, count: count, pct: pct)
708
751
  end
709
752
  end
753
+
754
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
755
+ def handle_status
756
+ autosave_val = @autosave_enabled ? "on (every #{@autosave_interval}s)" : 'off'
757
+ filter_val = @message_stream.filter ? @message_stream.filter[:type].to_s : 'none'
758
+ wrap_val = @message_stream.wrap_width ? @message_stream.wrap_width.to_s : 'off'
759
+ truncate_val = @message_stream.truncate_limit ? @message_stream.truncate_limit.to_s : 'off'
760
+ tee_val = @tee_path || 'off'
761
+ lines = [
762
+ 'Mode Status:',
763
+ " Plan mode : #{@plan_mode ? 'on' : 'off'}",
764
+ " Focus mode : #{@focus_mode ? 'on' : 'off'}",
765
+ " Debug mode : #{@debug_mode ? 'on' : 'off'}",
766
+ " Silent mode: #{@silent_mode ? 'on' : 'off'}",
767
+ " Mute system: #{@muted_system ? 'on' : 'off'}",
768
+ " Multi-line : #{@multiline_mode ? 'on' : 'off'}",
769
+ " Speak mode : #{defined?(@speak_mode) && @speak_mode ? 'on' : 'off'}",
770
+ " Autosave : #{autosave_val}",
771
+ " Color : #{@message_stream.colorize ? 'on' : 'off'}",
772
+ " Timestamps : #{@message_stream.show_timestamps ? 'on' : 'off'}",
773
+ " Numbers : #{@message_stream.show_numbers ? 'on' : 'off'}",
774
+ " Wrap : #{wrap_val}",
775
+ " Truncate : #{truncate_val}",
776
+ " Filter : #{filter_val}",
777
+ " Tee : #{tee_val}",
778
+ " Theme : #{Theme.current_theme}",
779
+ " Personality: #{@personality || 'default'}"
780
+ ]
781
+ @message_stream.add_message(role: :system, content: lines.join("\n"))
782
+ :handled
783
+ end
784
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
785
+
786
+ def handle_prefs(input)
787
+ parts = input.split(nil, 3)
788
+ key = parts[1]
789
+ value = parts[2]
790
+ if key.nil?
791
+ show_all_prefs
792
+ elsif value.nil?
793
+ show_one_pref(key)
794
+ else
795
+ set_pref(key, value)
796
+ end
797
+ :handled
798
+ end
799
+
800
+ def prefs_path
801
+ File.expand_path('~/.legionio/prefs.json')
802
+ end
803
+
804
+ def load_prefs
805
+ return {} unless File.exist?(prefs_path)
806
+
807
+ require 'json'
808
+ ::JSON.parse(File.read(prefs_path))
809
+ rescue ::JSON::ParserError
810
+ {}
811
+ end
812
+
813
+ def save_prefs(prefs)
814
+ require 'fileutils'
815
+ require 'json'
816
+ FileUtils.mkdir_p(File.dirname(prefs_path))
817
+ File.write(prefs_path, ::JSON.pretty_generate(prefs))
818
+ end
819
+
820
+ def show_all_prefs
821
+ prefs = load_prefs
822
+ if prefs.empty?
823
+ @message_stream.add_message(role: :system, content: 'No preferences saved.')
824
+ else
825
+ lines = prefs.map { |k, v| " #{k}: #{v}" }
826
+ @message_stream.add_message(role: :system, content: "Preferences:\n#{lines.join("\n")}")
827
+ end
828
+ end
829
+
830
+ def show_one_pref(key)
831
+ val = load_prefs[key]
832
+ if val.nil?
833
+ @message_stream.add_message(role: :system, content: "No preference set for '#{key}'.")
834
+ else
835
+ @message_stream.add_message(role: :system, content: "#{key}: #{val}")
836
+ end
837
+ end
838
+
839
+ def set_pref(key, value)
840
+ prefs = load_prefs
841
+ prefs[key] = value
842
+ save_prefs(prefs)
843
+ apply_pref(key, value)
844
+ @message_stream.add_message(role: :system, content: "Preference set: #{key} = #{value}")
845
+ end
846
+
847
+ def apply_pref(key, value)
848
+ case key
849
+ when 'theme' then handle_theme("/theme #{value}")
850
+ when 'personality' then handle_personality("/personality #{value}")
851
+ when 'color' then handle_color("/color #{value}")
852
+ when 'timestamps' then handle_timestamps("/timestamps #{value}")
853
+ end
854
+ end
710
855
  end
711
856
  end
712
857
  end
@@ -45,7 +45,10 @@ module Legion
45
45
  /color /timestamps
46
46
  /top /bottom /head /tail
47
47
  /draft /revise
48
- /mark /freq].freeze
48
+ /mark /freq
49
+ /about /commands
50
+ /ask /define
51
+ /status /prefs].freeze
49
52
 
50
53
  PERSONALITIES = {
51
54
  'default' => 'You are Legion, an async cognition engine and AI assistant. Be helpful and concise.',
@@ -492,6 +495,12 @@ module Legion
492
495
  when '/revise' then handle_revise(input)
493
496
  when '/mark' then handle_mark(input)
494
497
  when '/freq' then handle_freq
498
+ when '/about' then handle_about
499
+ when '/commands' then handle_commands(input)
500
+ when '/ask' then handle_ask(input)
501
+ when '/define' then handle_define(input)
502
+ when '/status' then handle_status
503
+ when '/prefs' then handle_prefs(input)
495
504
  else :handled
496
505
  end
497
506
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Legion
4
4
  module TTY
5
- VERSION = '0.4.24'
5
+ VERSION = '0.4.25'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: legion-tty
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.24
4
+ version: 0.4.25
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity